From f17628a23cad6755ab49f768cc8eb7d8b4721613 Mon Sep 17 00:00:00 2001 From: Karthik Date: Mon, 2 Jun 2025 00:48:03 +0200 Subject: [PATCH] Latest scripts to track phase transition via tilt --- .../+Scripts/run_on_cluster.m | 106 ++++++++++++------ .../+Scripts/run_on_cluster_wrapper.m | 26 +++++ ...bmit_jobs_for_tracking_phase_transition.sh | 39 +++++++ 3 files changed, 136 insertions(+), 35 deletions(-) create mode 100644 Dipolar-Gas-Simulator/+Scripts/run_on_cluster_wrapper.m create mode 100644 Dipolar-Gas-Simulator/submit_jobs_for_tracking_phase_transition.sh diff --git a/Dipolar-Gas-Simulator/+Scripts/run_on_cluster.m b/Dipolar-Gas-Simulator/+Scripts/run_on_cluster.m index 0eeee9a..d3957d4 100644 --- a/Dipolar-Gas-Simulator/+Scripts/run_on_cluster.m +++ b/Dipolar-Gas-Simulator/+Scripts/run_on_cluster.m @@ -1,41 +1,77 @@ -OptionsStruct = struct; +function run_on_cluster(batchParams, batchIdx) + nJobs = size(batchParams, 1); -OptionsStruct.NumberOfAtoms = 5E7; -OptionsStruct.DipolarPolarAngle = deg2rad(0); -OptionsStruct.DipolarAzimuthAngle = 0; -OptionsStruct.ScatteringLength = 102; + for k = 1:nJobs + % Unpack parameter tuple + a_s = batchParams(k, 1); + theta_deg = batchParams(k, 2); + phi_deg = batchParams(k, 3); + N_atoms = batchParams(k, 4); -OptionsStruct.TrapFrequencies = [50, 20, 150]; -OptionsStruct.TrapPotentialType = 'Harmonic'; + theta_rad = deg2rad(theta_deg); + phi_rad = deg2rad(phi_deg); -OptionsStruct.NumberOfGridPoints = [128, 256, 128]; -OptionsStruct.Dimensions = [40, 80, 40]; -OptionsStruct.UseApproximationForLHY = true; -OptionsStruct.IncludeDDICutOff = true; -OptionsStruct.CutoffType = 'Cylindrical'; -OptionsStruct.SimulationMode = 'ImaginaryTimeEvolution'; % 'ImaginaryTimeEvolution' | 'RealTimeEvolution' | 'EnergyMinimization' -OptionsStruct.GradientDescentMethod = 'NonLinearCGD'; % 'HeavyBall' | 'NonLinearCGD' -OptionsStruct.MaxIterationsForGD = 15000; -OptionsStruct.TimeStepSize = 1E-3; % in s -OptionsStruct.MinimumTimeStepSize = 1E-6; % in s -OptionsStruct.TimeCutOff = 1E4; % in s -OptionsStruct.EnergyTolerance = 5E-10; -OptionsStruct.ResidualTolerance = 1E-05; -OptionsStruct.NoiseScaleFactor = 0.010; + % Create unique save directory + jobName = sprintf('aS_%03d_theta_%03d_phi_%03d_N_%d', a_s, theta_deg, phi_deg, N_atoms); + saveDir = fullfile('./Results/Data_3D/PhaseDiagram', jobName); + if ~exist(saveDir, 'dir') + mkdir(saveDir); + end -OptionsStruct.PlotLive = true; -OptionsStruct.JobNumber = 0; -OptionsStruct.RunOnGPU = false; -OptionsStruct.SaveData = true; -OptionsStruct.SaveDirectory = './Results/Data_3D/ImagTimeProp'; -options = Helper.convertstruct2cell(OptionsStruct); + % Copy psi_init.mat from the parent folder into saveDir + srcFile = fullfile('./Results/Data_3D/PhaseDiagram', 'psi_init.mat'); + destFile = fullfile(saveDir, 'psi_init.mat'); + if exist(srcFile, 'file') + copyfile(srcFile, destFile); + end -sim = Simulator.DipolarGas(options{:}); -pot = Simulator.Potentials(options{:}); -sim.Potential = pot.trap(); + % Options for this run + OptionsStruct = struct; + OptionsStruct.NumberOfAtoms = N_atoms; + OptionsStruct.DipolarPolarAngle = theta_rad; + OptionsStruct.DipolarAzimuthAngle = phi_rad; + OptionsStruct.ScatteringLength = a_s; -%-% 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); \ No newline at end of file + OptionsStruct.TrapFrequencies = [50, 20, 150]; + OptionsStruct.TrapPotentialType = 'Harmonic'; + + OptionsStruct.NumberOfGridPoints = [128, 256, 128]; + OptionsStruct.Dimensions = [40, 80, 40]; + OptionsStruct.UseApproximationForLHY = true; + OptionsStruct.IncludeDDICutOff = true; + OptionsStruct.CutoffType = 'Cylindrical'; + OptionsStruct.SimulationMode = 'ImaginaryTimeEvolution'; + OptionsStruct.GradientDescentMethod = 'NonLinearCGD'; + OptionsStruct.MaxIterationsForGD = 15000; + OptionsStruct.TimeStepSize = 1E-3; + OptionsStruct.MinimumTimeStepSize = 1E-6; + OptionsStruct.TimeCutOff = 2E6; + OptionsStruct.EnergyTolerance = 5E-08; + OptionsStruct.ResidualTolerance = 1E-05; + OptionsStruct.NoiseScaleFactor = 0.010; + + OptionsStruct.PlotLive = false; + OptionsStruct.JobNumber = k; + OptionsStruct.RunOnGPU = true; + OptionsStruct.SaveData = true; + OptionsStruct.SaveDirectory = saveDir; + + options = Helper.convertstruct2cell(OptionsStruct); + + sim = Simulator.DipolarGas(options{:}); + pot = Simulator.Potentials(options{:}); + sim.Potential = pot.trap(); + + NumberOfOutputs = 5; + try + [Params, Transf, psi, ~, ~, stats] = Helper.runWithProfiling(@() sim.run(), NumberOfOutputs, saveDir); + save(fullfile('./Results/Data_3D/PhaseDiagram', 'psi_init.mat'), 'psi', 'Transf', 'Params'); + catch ME + fprintf('ERROR in job %d:\n%s\n', k, getReport(ME, 'extended')); + continue; + end + + fprintf('Batch %d | Job %d: a_s = %d, theta = %d°, phi = %d°, N = %d | Time = %.2f s\n', ... + batchIdx, k, a_s, theta_deg, phi_deg, N_atoms, stats.runtime); + end +end \ No newline at end of file diff --git a/Dipolar-Gas-Simulator/+Scripts/run_on_cluster_wrapper.m b/Dipolar-Gas-Simulator/+Scripts/run_on_cluster_wrapper.m new file mode 100644 index 0000000..477beca --- /dev/null +++ b/Dipolar-Gas-Simulator/+Scripts/run_on_cluster_wrapper.m @@ -0,0 +1,26 @@ +function run_on_cluster_wrapper() % batchIdx is unused now + % Read parameter ranges + a_s_list = parse_environmental_variable('SCATTERING_LENGTH_RANGE', 85); % Scattering length(s) + theta = str2double(getenv('POLAR_ANGLE')); % Single polar angle + phi_list = parse_environmental_variable('AZIMUTHAL_ANGLE_RANGE', 0); % Azimuthal angle(s) + N_atoms_list = parse_environmental_variable('NUM_ATOMS_LIST', 90000); % Atom number(s) + + % Create full parameter grid for fixed theta + [A, P, N] = ndgrid(a_s_list, phi_list, N_atoms_list); + paramGrid = [A(:), repmat(theta, numel(A), 1), P(:), N(:)]; + + % Call the cluster execution function + batchIdx = 1; % Still needed for logging/debugging + Scripts.run_on_cluster(paramGrid, batchIdx); +end + +function vals = parse_environmental_variable(varName, default) + str = getenv(varName); + if isempty(str) + vals = default; + elseif startsWith(str, '[') + vals = str2num(str); %#ok + else + vals = eval(str); % Trust only controlled environments + end +end diff --git a/Dipolar-Gas-Simulator/submit_jobs_for_tracking_phase_transition.sh b/Dipolar-Gas-Simulator/submit_jobs_for_tracking_phase_transition.sh new file mode 100644 index 0000000..d67e9cc --- /dev/null +++ b/Dipolar-Gas-Simulator/submit_jobs_for_tracking_phase_transition.sh @@ -0,0 +1,39 @@ +#!/bin/bash +#SBATCH --partition=gpu-single +#SBATCH --nodes=1 +#SBATCH --ntasks-per-node=1 +#SBATCH --cpus-per-task=8 +#SBATCH --gres=gpu:1 +#SBATCH --mem=32G +#SBATCH --time=48:00:00 +#SBATCH --job-name=theta_scan_serial +#SBATCH --output=log_theta_scan.out +#SBATCH --error=log_theta_scan.err + +module load math/matlab/R2023a + +# ----------- Define scan ranges ----------- + +# Use space-separated floating-point/integer values +SCATTERING_LENGTH_RANGE="[95.62]" +POLAR_ANGLE_RANGE="[0.0 5.0 10.0 15.0 20.0 25.0 30.0 35.0 40.0 45.0]" +AZIMUTHAL_ANGLE_RANGE="[0.0]" +NUM_ATOMS_LIST="[500000]" + +# Strip brackets and spaces for looping +polarAngles=($(echo "$POLAR_ANGLE_RANGE" | tr -d '[],')) + +# ----------- Run all polar angle jobs sequentially within one SLURM job ----------- + +for theta in "${polarAngles[@]}"; do + echo "Running MATLAB for polar angle θ = $theta°" + + matlab -nodisplay -nosplash -r "\ + setenv('SCATTERING_LENGTH_RANGE', '$SCATTERING_LENGTH_RANGE'); \ + setenv('POLAR_ANGLE', '$theta'); \ + setenv('AZIMUTHAL_ANGLE_RANGE', '$AZIMUTHAL_ANGLE_RANGE'); \ + setenv('NUM_ATOMS_LIST', '$NUM_ATOMS_LIST'); \ + Scripts.run_on_cluster_wrapper(); exit" + + echo "Finished MATLAB job for θ = $theta°" +done \ No newline at end of file