% Compare numerical methods

%% - Polyak's heavy-ball GD

OptionsStruct = struct;

OptionsStruct.NumberOfAtoms           = 40000;
OptionsStruct.DipolarPolarAngle       = deg2rad(0);
OptionsStruct.DipolarAzimuthAngle     = 0;
OptionsStruct.ScatteringLength        = 95;

OptionsStruct.TrapFrequencies         = [30, 60, 90];
OptionsStruct.TrapPotentialType       = 'Harmonic';

OptionsStruct.NumberOfGridPoints      = [128, 64, 64];
OptionsStruct.Dimensions              = [30, 20, 20];
OptionsStruct.UseApproximationForLHY  = true;
OptionsStruct.IncludeDDICutOff        = true;
OptionsStruct.CutoffType              = 'Cylindrical';
OptionsStruct.SimulationMode          = 'EnergyMinimization';  % 'ImaginaryTimeEvolution' | 'RealTimeEvolution' | 'EnergyMinimization'
OptionsStruct.GradientDescentMethod   = 'HeavyBall';           % 'HeavyBall' | 'NonLinearCGD' 
OptionsStruct.MaxIterationsForGD      = 1000;
OptionsStruct.NoiseScaleFactor        = 0.010;

OptionsStruct.PlotLive                = true;
OptionsStruct.JobNumber               = 0;
OptionsStruct.RunOnGPU                = false;
OptionsStruct.SaveData                = true;
OptionsStruct.SaveDirectory           = './Results/Data_3D/GradientDescent';
options                               = Helper.convertstruct2cell(OptionsStruct);

sim                                   = Simulator.DipolarGas(options{:});
pot                                   = Simulator.Potentials(options{:});
sim.Potential                         = pot.trap();

%-% Run Simulation %-%
NumberOfOutputs                       = 5;
[Params, Transf, psi, V, VDk, stats]  = Helper.runWithProfiling(@() sim.run(), NumberOfOutputs, OptionsStruct.SaveDirectory);
fprintf('Runtime: %.3f seconds\n', stats.runtime);
fprintf('Memory used: %.2f MB\n', stats.workspaceMemoryMB);

clear all

%% - Non-linear CGD

OptionsStruct = struct;

OptionsStruct.NumberOfAtoms           = 40000;
OptionsStruct.DipolarPolarAngle       = deg2rad(0);
OptionsStruct.DipolarAzimuthAngle     = 0;
OptionsStruct.ScatteringLength        = 95;

OptionsStruct.TrapFrequencies         = [30, 60, 90];
OptionsStruct.TrapPotentialType       = 'Harmonic';

OptionsStruct.NumberOfGridPoints      = [128, 64, 64];
OptionsStruct.Dimensions              = [30, 20, 20];
OptionsStruct.UseApproximationForLHY  = true;
OptionsStruct.IncludeDDICutOff        = true;
OptionsStruct.CutoffType              = 'Cylindrical';
OptionsStruct.SimulationMode          = 'EnergyMinimization';  % 'ImaginaryTimeEvolution' | 'RealTimeEvolution' | 'EnergyMinimization'
OptionsStruct.GradientDescentMethod   = 'NonLinearCGD';           % 'HeavyBall' | 'NonLinearCGD' 
OptionsStruct.MaxIterationsForGD      = 1000;
OptionsStruct.NoiseScaleFactor        = 0.010;

OptionsStruct.PlotLive                = true;
OptionsStruct.JobNumber               = 1;
OptionsStruct.RunOnGPU                = false;
OptionsStruct.SaveData                = true;
OptionsStruct.SaveDirectory           = './Results/Data_3D/GradientDescent';
options                               = Helper.convertstruct2cell(OptionsStruct);

sim                                   = Simulator.DipolarGas(options{:});
pot                                   = Simulator.Potentials(options{:});
sim.Potential                         = pot.trap();

%-% Run Simulation %-%
NumberOfOutputs                       = 5;
[Params, Transf, psi, V, VDk, stats]  = Helper.runWithProfiling(@() sim.run(), NumberOfOutputs, OptionsStruct.SaveDirectory);
fprintf('Runtime: %.3f seconds\n', stats.runtime);
fprintf('Memory used: %.2f MB\n', stats.workspaceMemoryMB);

clear all

%% - Imaginary time propagation

OptionsStruct = struct;

OptionsStruct.NumberOfAtoms           = 40000;
OptionsStruct.DipolarPolarAngle       = deg2rad(0);
OptionsStruct.DipolarAzimuthAngle     = 0;
OptionsStruct.ScatteringLength        = 95;

OptionsStruct.TrapFrequencies         = [30, 60, 90];
OptionsStruct.TrapPotentialType       = 'Harmonic';

OptionsStruct.NumberOfGridPoints      = [128, 64, 64];
OptionsStruct.Dimensions              = [30, 20, 20];
OptionsStruct.UseApproximationForLHY  = true;
OptionsStruct.IncludeDDICutOff        = true;
OptionsStruct.CutoffType              = 'Cylindrical';
OptionsStruct.SimulationMode          = 'ImaginaryTimeEvolution';     % 'ImaginaryTimeEvolution' | 'RealTimeEvolution' | 'EnergyMinimization'
OptionsStruct.TimeStepSize            = 1E-3;            % in s
OptionsStruct.MinimumTimeStepSize     = 1E-6;            % in s
OptionsStruct.TimeCutOff              = 1E5;             % in s
OptionsStruct.EnergyTolerance         = 5E-10;
OptionsStruct.ResidualTolerance       = 1E-08;
OptionsStruct.NoiseScaleFactor        = 0.010;

OptionsStruct.PlotLive                = true;
OptionsStruct.JobNumber               = 0;
OptionsStruct.RunOnGPU                = false;
OptionsStruct.SaveData                = true;
OptionsStruct.SaveDirectory           = './Results/Data_3D/AnisotropicTrap/Tilted0';
options                               = Helper.convertstruct2cell(OptionsStruct);

sim                                   = Simulator.DipolarGas(options{:});
pot                                   = Simulator.Potentials(options{:});
sim.Potential                         = pot.trap();

%-% Run Simulation %-%
NumberOfOutputs                       = 5;
[Params, Transf, psi, V, VDk, stats]  = Helper.runWithProfiling(@() sim.run(), NumberOfOutputs, OptionsStruct.SaveDirectory);
fprintf('Runtime: %.3f seconds\n', stats.runtime);
fprintf('Memory used: %.2f MB\n', stats.workspaceMemoryMB);

clear all