Latest working version - modified calculation of VDk to have the flag to include cutoff within it so that there is a single universal function that calculated the DDI potential for the solver.

This commit is contained in:
Karthik 2025-03-19 14:56:26 +01:00
parent 4af0ce726a
commit f6394cd6a0
8 changed files with 124 additions and 137 deletions

View File

@ -326,11 +326,19 @@ JobNumber = 1;
[contrast, period_X, period_Y] = Scripts.analyzeGSWavefunction_in_plane_trap(SaveDirectory, JobNumber); [contrast, period_X, period_Y] = Scripts.analyzeGSWavefunction_in_plane_trap(SaveDirectory, JobNumber);
%% %%
SaveDirectory = './Results/Data_TiltingOfDipoles/TransitionAngle/OptimalSystemSize/Hz500/Degree15'; SaveDirectory = './Results/Data_TiltingOfDipoles/TransitionAngle/OptimalSystemSize/Hz500/Degree0';
% Define the desired range for Lx and Ly % Define the desired range for Lx and Ly
Lx_Range = 4:0.4:11; % Extend Lx from 5 to 10 Lx_Range = 4:0.2:6; % Extend Lx from 5 to 10
Ly_Range = 4:0.4:11; % Extend Ly from 5 to 10 Ly_Range = 4:0.2:6; % Extend Ly from 5 to 10
MinEnergyDataArray = Scripts.analyzeGSWavefunction_optimal_system_size(SaveDirectory, Lx_Range, Ly_Range); MinEnergyDataArray = Scripts.analyzeGSWavefunction_optimal_system_size(SaveDirectory, Lx_Range, Ly_Range);
%%
SaveDirectory = './Results/Data_TiltingOfDipoles/TransitionAngle/OptimalSystemSize/Hz500/Degree0';
% Define the desired range
LatticeSpacing = 1.0:0.05:4.0;
MinEnergyDataArray = Scripts.analyzeGSWavefunction_constrained_optimal_system_size(SaveDirectory, LatticeSpacing);
% Plotter.visualizeGSWavefunction2D(SaveDirectory, 1)
%% - Analysis %% - Analysis
SaveDirectory = './Results/Data_TiltingOfDipoles/HarmonicTrap/AspectRatio/AR2_8'; SaveDirectory = './Results/Data_TiltingOfDipoles/HarmonicTrap/AspectRatio/AR2_8';
JobNumber = 0; % 79 JobNumber = 0; % 79
@ -338,6 +346,7 @@ JobNumber = 0; % 79
% JobNumber = 2; % 81 % JobNumber = 2; % 81
Plotter.visualizeGSWavefunction2D(SaveDirectory, JobNumber) Plotter.visualizeGSWavefunction2D(SaveDirectory, JobNumber)
[contrast, period_X, period_Y] = Scripts.analyzeGSWavefunction_in_plane_trap(SaveDirectory, JobNumber); [contrast, period_X, period_Y] = Scripts.analyzeGSWavefunction_in_plane_trap(SaveDirectory, JobNumber);
%% - Analysis %% - Analysis
SaveDirectory = './Results/Data_TiltingOfDipoles/HarmonicTrap/AspectRatio/AR3_7'; SaveDirectory = './Results/Data_TiltingOfDipoles/HarmonicTrap/AspectRatio/AR3_7';
% JobNumber = 0; % 80 % JobNumber = 0; % 80
@ -346,3 +355,4 @@ JobNumber = 2; % 82
% JobNumber = 3; % 83 % JobNumber = 3; % 83
Plotter.visualizeGSWavefunction2D(SaveDirectory, JobNumber) Plotter.visualizeGSWavefunction2D(SaveDirectory, JobNumber)
[contrast, period_X, period_Y] = Scripts.analyzeGSWavefunction_in_plane_trap(SaveDirectory, JobNumber); [contrast, period_X, period_Y] = Scripts.analyzeGSWavefunction_in_plane_trap(SaveDirectory, JobNumber);

View File

@ -1,89 +1,74 @@
%% AR = 2.8 %% Tilting of the dipoles
OptionsStruct = struct; ppum = 1250; % Atom Number Density in per micrometers
OptionsStruct.NumberOfAtoms = 5E5; %% theta = 0
OptionsStruct.DipolarPolarAngle = 0;
OptionsStruct.DipolarAzimuthAngle = 0;
OptionsStruct.ScatteringLength = 78.0;
AspectRatio = 2.8; LatticeSpacing = 1.0:0.05:4.0;
HorizontalTrapFrequency = 125; totalIterations = numel(LatticeSpacing);
VerticalTrapFrequency = HorizontalTrapFrequency * AspectRatio;
OptionsStruct.TrapFrequencies = [HorizontalTrapFrequency, HorizontalTrapFrequency, VerticalTrapFrequency];
OptionsStruct.TrapPotentialType = 'Harmonic';
OptionsStruct.NumberOfGridPoints = [256, 256]; % create a local cluster object
OptionsStruct.Dimensions = [18, 18]; cluster = parcluster('local');
OptionsStruct.TimeStepSize = 1E-3; % in s
OptionsStruct.MinimumTimeStepSize = 1E-5; % in s
OptionsStruct.TimeCutOff = 2E6; % in s
OptionsStruct.EnergyTolerance = 5E-10;
OptionsStruct.ResidualTolerance = 1E-04;
OptionsStruct.NoiseScaleFactor = 0.05;
OptionsStruct.MaxIterations = 10; % get the number of dedicated cores from environment
OptionsStruct.VariationalWidth = 2.0; nprocs = str2num(getenv('SLURM_NPROCS'));
OptionsStruct.WidthLowerBound = 0.01;
OptionsStruct.WidthUpperBound = 12;
OptionsStruct.WidthCutoff = 1e-2;
OptionsStruct.PlotLive = false; % you may explicitly set the JobStorageLocation to the tmp directory that is unique to each cluster job (and is on local, fast scratch)
OptionsStruct.JobNumber = 0; parpool_tmpdir = [getenv('TMP'),'/.matlab/local_cluster_jobs/slurm_jobID_',getenv('SLURM_JOB_ID')];
OptionsStruct.RunOnGPU = true; mkdir(parpool_tmpdir);
OptionsStruct.SaveData = true; cluster.JobStorageLocation = parpool_tmpdir;
OptionsStruct.SaveDirectory = './Results/Data_TiltingOfDipoles/HarmonicTrap/AspectRatio/AR2_8';
options = Helper.convertstruct2cell(OptionsStruct);
clear OptionsStruct
solver = VariationalSolver2D.DipolarGas(options{:}); % start the parallel pool
pot = VariationalSolver2D.Potentials(options{:}); parpool(cluster, nprocs)
solver.Potential = pot.trap();
%-% Run Solver %-% % Parallel loop over all combinations of i, j
[Params, Transf, psi, V, VDk] = solver.run(); parfor (k = 1:totalIterations, cluster)
%% AR = 4.0 a = LatticeSpacing(k);
lx = a;
ly = sqrt(3)*a;
OptionsStruct = struct; % Initialize OptionsStruct
OptionsStruct = struct;
OptionsStruct.NumberOfAtoms = 5E5; % Assign values to OptionsStruct
OptionsStruct.DipolarPolarAngle = 0; OptionsStruct.NumberOfAtoms = ppum * (lx*ly);
OptionsStruct.DipolarAzimuthAngle = 0; OptionsStruct.DipolarPolarAngle = deg2rad(0);
OptionsStruct.ScatteringLength = 78.0; OptionsStruct.DipolarAzimuthAngle = 0;
OptionsStruct.ScatteringLength = 75.00;
AspectRatio = 4.0; OptionsStruct.TrapFrequencies = [0, 0, 500];
HorizontalTrapFrequency = 125; OptionsStruct.TrapPotentialType = 'None';
VerticalTrapFrequency = HorizontalTrapFrequency * AspectRatio;
OptionsStruct.TrapFrequencies = [HorizontalTrapFrequency, HorizontalTrapFrequency, VerticalTrapFrequency];
OptionsStruct.TrapPotentialType = 'Harmonic';
OptionsStruct.NumberOfGridPoints = [256, 256]; OptionsStruct.NumberOfGridPoints = [128, 128];
OptionsStruct.Dimensions = [18, 18]; OptionsStruct.Dimensions = [lx, ly];
OptionsStruct.TimeStepSize = 1E-3; % in s OptionsStruct.TimeStepSize = 5E-4; % in s
OptionsStruct.MinimumTimeStepSize = 1E-5; % in s OptionsStruct.MinimumTimeStepSize = 1E-5; % in s
OptionsStruct.TimeCutOff = 2E6; % in s OptionsStruct.TimeCutOff = 2E6; % in s
OptionsStruct.EnergyTolerance = 5E-10; OptionsStruct.EnergyTolerance = 5E-10;
OptionsStruct.ResidualTolerance = 1E-04; OptionsStruct.ResidualTolerance = 1E-05;
OptionsStruct.NoiseScaleFactor = 0.05; OptionsStruct.NoiseScaleFactor = 0.05;
OptionsStruct.IncludeDDICutOff = false;
OptionsStruct.MaxIterations = 10; OptionsStruct.MaxIterations = 10;
OptionsStruct.VariationalWidth = 2.0; OptionsStruct.VariationalWidth = 1.10;
OptionsStruct.WidthLowerBound = 0.01; OptionsStruct.WidthLowerBound = 0.01;
OptionsStruct.WidthUpperBound = 12; OptionsStruct.WidthUpperBound = 12;
OptionsStruct.WidthCutoff = 1e-2; OptionsStruct.WidthCutoff = 1e-2;
OptionsStruct.PlotLive = false; OptionsStruct.PlotLive = false;
OptionsStruct.JobNumber = 0; OptionsStruct.JobNumber = k;
OptionsStruct.RunOnGPU = true; OptionsStruct.RunOnGPU = true;
OptionsStruct.SaveData = true; OptionsStruct.SaveData = true;
OptionsStruct.SaveDirectory = './Results/Data_TiltingOfDipoles/HarmonicTrap/AspectRatio/AR4_0'; OptionsStruct.SaveDirectory = sprintf('./Results/Data_TiltingOfDipoles/TransitionAngle/OptimalSystemSize/Hz500/Degree%i', round(rad2deg(OptionsStruct.DipolarPolarAngle)));
options = Helper.convertstruct2cell(OptionsStruct);
clear OptionsStruct
solver = VariationalSolver2D.DipolarGas(options{:}); options = Helper.convertstruct2cell(OptionsStruct);
pot = VariationalSolver2D.Potentials(options{:});
solver.Potential = pot.trap();
%-% Run Solver %-% solver = VariationalSolver2D.DipolarGas(options{:});
[Params, Transf, psi, V, VDk] = solver.run(); pot = VariationalSolver2D.Potentials(options{:});
solver.Potential = pot.trap();
% Run Solver
[Params, Transf, psi, V, VDk] = solver.run();
end

View File

@ -1,31 +1,43 @@
%% Tilting of the dipoles %% Tilting of the dipoles
% Atom Number Density = 1250 ppum
ppum = 1250; ppum = 1250; % Atom Number Density in per micrometers
%% theta = 0 %% theta = 0
Lx = 8:0.4:11; Lx = 4:0.4:11;
Ly = 4:0.4:11; Ly = 4:0.4:11;
cluster = parcluster;
% Create a combined index for all i, j pairs % Create a combined index for all i, j pairs
[I, J] = ndgrid(1:numel(Lx), 1:numel(Ly)); [I, J] = ndgrid(1:numel(Lx), 1:numel(Ly));
totalIterations = numel(I); totalIterations = numel(I);
% create a local cluster object
cluster = parcluster('local');
% get the number of dedicated cores from environment
nprocs = str2num(getenv('SLURM_NPROCS'));
% you may explicitly set the JobStorageLocation to the tmp directory that is unique to each cluster job (and is on local, fast scratch)
parpool_tmpdir = [getenv('TMP'),'/.matlab/local_cluster_jobs/slurm_jobID_',getenv('SLURM_JOB_ID')];
mkdir(parpool_tmpdir);
cluster.JobStorageLocation = parpool_tmpdir;
% start the parallel pool
parpool(cluster, nprocs)
% Parallel loop over all combinations of i, j % Parallel loop over all combinations of i, j
parfor (k = 1:totalIterations, cluster) parfor (k = 1:totalIterations, cluster)
i = I(k);
j = J(k); i = I(k);
lx = Lx(i); j = J(k);
ly = Ly(j); lx = Lx(i);
ly = Ly(j);
% Initialize OptionsStruct % Initialize OptionsStruct
OptionsStruct = struct; OptionsStruct = struct;
% Assign values to OptionsStruct % Assign values to OptionsStruct
OptionsStruct.NumberOfAtoms = ppum * (lx*ly); OptionsStruct.NumberOfAtoms = ppum * (lx*ly);
OptionsStruct.DipolarPolarAngle = deg2rad(15); OptionsStruct.DipolarPolarAngle = deg2rad(0);
OptionsStruct.DipolarAzimuthAngle = 0; OptionsStruct.DipolarAzimuthAngle = 0;
OptionsStruct.ScatteringLength = 75.00; OptionsStruct.ScatteringLength = 75.00;
@ -49,17 +61,18 @@ parfor (k = 1:totalIterations, cluster)
OptionsStruct.WidthCutoff = 1e-2; OptionsStruct.WidthCutoff = 1e-2;
OptionsStruct.PlotLive = false; OptionsStruct.PlotLive = false;
OptionsStruct.JobNumber = (i - 1) * num_inner + j; OptionsStruct.JobNumber = k;
OptionsStruct.RunOnGPU = true; OptionsStruct.RunOnGPU = true;
OptionsStruct.SaveData = true; OptionsStruct.SaveData = true;
OptionsStruct.SaveDirectory = sprintf('./Results/Data_TiltingOfDipoles/TransitionAngle/OptimalSystemSize/Hz500/Degree%i', round(rad2deg(OptionsStruct.DipolarPolarAngle))); OptionsStruct.SaveDirectory = sprintf('./Results/Data_TiltingOfDipoles/TransitionAngle/OptimalSystemSize/Hz500/Degree%i', round(rad2deg(OptionsStruct.DipolarPolarAngle)));
options = Helper.convertstruct2cell(OptionsStruct); options = Helper.convertstruct2cell(OptionsStruct);
solver = VariationalSolver2D.DipolarGas(options{:}); solver = VariationalSolver2D.DipolarGas(options{:});
pot = VariationalSolver2D.Potentials(options{:}); pot = VariationalSolver2D.Potentials(options{:});
solver.Potential = pot.trap(); solver.Potential = pot.trap();
% Run Solver % Run Solver
[Params, Transf, psi, V, VDk] = solver.run(); [Params, Transf, psi, V, VDk] = solver.run();
end end

View File

@ -1,4 +1,4 @@
function VDk = calculateVDkWithCutoff(~, Transf, Params, ell) function VDk = calculateVDk(~, Transf, Params, ell, IncludeDDICutOff)
% == Calculating the DDI potential in Fourier space with appropriate cutoff == % % == Calculating the DDI potential in Fourier space with appropriate cutoff == %
% Interaction in K space % Interaction in K space
@ -17,13 +17,15 @@ function VDk = calculateVDkWithCutoff(~, Transf, Params, ell)
% Full DDI % Full DDI
VDk = Fpar*sin(Params.theta)^2 + Fperp*cos(Params.theta)^2; VDk = Fpar*sin(Params.theta)^2 + Fperp*cos(Params.theta)^2;
% Implementing a cutoff: if IncludeDDICutOff
VDr = ifftn(VDk); % Implementing a cutoff:
VDr = fftshift(VDr); VDr = ifftn(VDk);
rcut = min(Transf.Xmax,Transf.Ymax); VDr = fftshift(VDr);
R = sqrt(Transf.X.^2+Transf.Y.^2) < 0.9*rcut; rcut = min(Transf.Xmax,Transf.Ymax);
VDr = VDr.*double(R); R = sqrt(Transf.X.^2+Transf.Y.^2) < 0.9*rcut;
VDr = ifftshift(VDr); VDr = VDr.*double(R);
VDk = fftn(VDr); VDr = ifftshift(VDr);
VDk = fftn(VDr);
end
end end

View File

@ -1,19 +0,0 @@
function VDk = calculateVDkWithoutCutoff(~, Transf, Params, ell)
% == Calculating the DDI potential in Fourier space with appropriate cutoff == %
% Interaction in K space
QX = Transf.KX*ell/sqrt(2);
QY = Transf.KY*ell/sqrt(2);
Qsq = QX.^2 + QY.^2;
absQ = sqrt(Qsq);
QDsq = QX.^2*cos(Params.eta)^2 + QY.^2*sin(Params.eta)^2;
% Bare interaction
Fpar = -1 + 3*sqrt(pi)*QDsq.*erfcx(absQ)./absQ; % Scaled complementary error function erfcx(x) = e^(x^2) * erfc(x)
Fperp = 2 - 3*sqrt(pi).*absQ.*erfcx(absQ);
Fpar(absQ == 0) = -1;
% Full DDI
VDk = Fpar*sin(Params.theta)^2 + Fperp*cos(Params.theta)^2;
end

View File

@ -1,4 +1,4 @@
function E = calculateVariationalEnergy(this, psi, Params, ell, Transf, V) function E = calculateVariationalEnergy(this, psi, Params, ell, Transf, V, IncludeDDICutOff)
g_eff = Params.gs * (1/(sqrt(2*pi)*ell)); g_eff = Params.gs * (1/(sqrt(2*pi)*ell));
gamma_eff = Params.gammaQF * (sqrt(2/5)/(pi^(3/4)*ell^(3/2))); gamma_eff = Params.gammaQF * (sqrt(2/5)/(pi^(3/4)*ell^(3/2)));
@ -9,7 +9,7 @@ function E = calculateVariationalEnergy(this, psi, Params, ell, Transf, V)
normfac = Params.Lx*Params.Ly/numel(psi); normfac = Params.Lx*Params.Ly/numel(psi);
% DDIs % DDIs
VDk = this.calculateVDkWithCutoff(Transf, Params, ell); % VDk depends on the variational parameters. THIS HAS TO BE RECALCULATED HERE FOR THE CONSTRAINED OPTIMIZATION TO WORK! VDk = this.calculateVDk(Transf, Params, ell, IncludeDDICutOff); % VDk depends on the variational parameters. THIS HAS TO BE RECALCULATED HERE FOR THE CONSTRAINED OPTIMIZATION TO WORK!
frho = fftn(abs(psi).^2); frho = fftn(abs(psi).^2);
Phi = real(ifftn(frho.*VDk)); Phi = real(ifftn(frho.*VDk));
Eddi = 0.5*Params.gdd*Phi.*abs(psi).^2/(sqrt(2*pi)*ell); Eddi = 0.5*Params.gdd*Phi.*abs(psi).^2/(sqrt(2*pi)*ell);

View File

@ -4,11 +4,7 @@ function [psi,V,VDk] = initialize(this,Params,VParams,Transf)
assert(~anynan(V), 'Potential not defined! Specify as <SimulatorObject>.Potential = <PotentialsObject>.trap() + <AdditionalTerms>.'); assert(~anynan(V), 'Potential not defined! Specify as <SimulatorObject>.Potential = <PotentialsObject>.trap() + <AdditionalTerms>.');
% == Calculating the DDIs == % % == Calculating the DDIs == %
if this.IncludeDDICutOff VDk = this.Calculator.calculateVDk(Transf, Params, VParams.ell, this.IncludeDDICutOff);
VDk = this.Calculator.calculateVDkWithCutoff(Transf, Params, VParams.ell);
else
VDk = this.Calculator.calculateVDkWithoutCutoff(Transf, Params, VParams.ell);
end
% == Setting up the initial wavefunction == % % == Setting up the initial wavefunction == %
psi = this.setupWavefunction(Params,Transf); psi = this.setupWavefunction(Params,Transf);

View File

@ -28,7 +28,7 @@ function [Params, Transf, psi, V, VDk] = run(this)
[psi,V,VDk] = this.initialize(Params,VParams,Transf); [psi,V,VDk] = this.initialize(Params,VParams,Transf);
ells(1) = VParams.ell; ells(1) = VParams.ell;
E_Var = @(x) this.Calculator.calculateVariationalEnergy(psi, Params, x, Transf, V)/Params.N; E_Var = @(x) this.Calculator.calculateVariationalEnergy(psi, Params, x, Transf, V, this.IncludeDDICutOff)/Params.N;
E_vs_iter(1) = E_Var(ells(1)); E_vs_iter(1) = E_Var(ells(1));
t_idx = 1; firstpoint = 1; t_idx = 1; firstpoint = 1;
@ -61,7 +61,7 @@ function [Params, Transf, psi, V, VDk] = run(this)
psi = gather(psi); psi = gather(psi);
% --- Constrained minimization --- % --- Constrained minimization ---
E_Var = @(x) this.Calculator.calculateVariationalEnergy(psi, Params, x, Transf, V)/Params.N; E_Var = @(x) this.Calculator.calculateVariationalEnergy(psi, Params, x, Transf, V, this.IncludeDDICutOff)/Params.N;
VParams.ell = fmincon(E_Var,VParams.ell,[],[],[],[],Params.ell_lower,Params.ell_upper,[],fminconoptions); VParams.ell = fmincon(E_Var,VParams.ell,[],[],[],[],Params.ell_lower,Params.ell_upper,[],fminconoptions);
% --- Convergence check --- % --- Convergence check ---