Skip to content

Commit 1791a2c

Browse files
authored
Merge pull request #929 from ProjectTorreyPines/use_ENVs_for_OMFIT_OMAS
Refactor DIII-D data fetching to use local OMAS/OMFIT when possible
2 parents 73d11f8 + 082bea5 commit 1791a2c

File tree

6 files changed

+133
-161
lines changed

6 files changed

+133
-161
lines changed

Project.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ version = "0.9.2"
55

66
[deps]
77
AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c"
8+
ArgParse = "c7e460c6-2fb9-53a9-8c5b-16f535851c63"
89
BalanceOfPlantSurrogate = "001e48cb-5a1e-4e3c-a5d4-cdc3aa14f3de"
910
BoundaryPlasmaModels = "2da5b0d0-c5e5-4f14-9caf-62d0020df410"
1011
CHEASE = "40781a8e-f1bb-11ec-24ef-0f6bc40c1567"
@@ -79,6 +80,7 @@ WeaveExt = "Weave"
7980

8081
[compat]
8182
AbstractTrees = "0.4"
83+
ArgParse = "1.2.0"
8284
BalanceOfPlantSurrogate = "3"
8385
BoundaryPlasmaModels = "1"
8486
CHEASE = "1"

deploy/omega/base.lua

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ local base_depot = envdir .. "/.julia"
1515
setenv("FUSE_HOME", basedir)
1616
setenv("FUSE_ENVIRONMENT", fuse_env)
1717

18+
-- Environment variables for data fetching
19+
setenv("FUSE_OMFIT_HOST", "localhost")
20+
setenv("FUSE_OMFIT_ROOT", "/fusion/projects/theory/fuse/d3d_data_fetching/OMFIT-source")
21+
setenv("FUSE_OMAS_ROOT", "/fusion/projects/theory/fuse/d3d_data_fetching/omas")
22+
23+
1824
-- We put the user depot first so their own packages get installed there,
1925
-- then the FUSE environment's depot after so it can find packages for the
2026
-- precompiled sysimage
@@ -33,4 +39,4 @@ setenv("JULIA_CPU_TARGET", "generic")
3339
prepend_path("JUPYTER_PATH", envdir .. "/.jupyter")
3440

3541
prepend_path("PATH", basedir .. "/miniconda3/bin")
36-
prepend_path("PATH", envdir)
42+
prepend_path("PATH", envdir)

deploy/perlmutter/base.lua

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ else
3030
)
3131
end
3232

33+
-- Environment variables for data fetching
34+
setenv("FUSE_OMFIT_HOST", "localhost")
35+
setenv("FUSE_OMFIT_ROOT", "/global/common/software/m3739/perlmutter/OMFIT-CAKE")
36+
setenv("FUSE_OMAS_ROOT", "/global/common/software/m3739/perlmutter/FUSE_OMAS")
37+
setenv("FUSE_RESULT_ARCHIVE", pathJoin("/global/cfs/cdirs/m3739/FUSE/d3d-time-dependent", os.getenv("USER")))
38+
3339
-- The FUSE sysimage enviornment is the last place julia looks for packages
3440
-- when a user does `using <package>`, but this allows Julia to automatically
3541
-- find FUSE, Plots, and IJulia.

deploy/perlmutter/deploy.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22
command -v module >/dev/null 2>&1 || source /usr/share/lmod/lmod/init/bash
33
module load julia/1.11.4
44

5+
# Set up OMFIT and OMAS which is needed for the DIII-D study
6+
export FUSE_OMFIT_HOST="localhost"
7+
export FUSE_OMFIT_ROOT="/global/common/software/m3739/perlmutter/OMFIT-CAKE"
8+
export FUSE_OMAS_ROOT="/global/common/software/m3739/perlmutter/FUSE_OMAS"
9+
510
basedir="/global/common/software/m3739/perlmutter/fuse"
611

712
fuse_env=`curl -s https://api.github.com/repos/ProjectTorreyPines/FUSE.jl/releases/latest | jq -r .name`

src/cases/D3D.jl

Lines changed: 112 additions & 160 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
1+
2+
13
"""
24
case_parameters(::Val{:D3D}, shot::Int;
35
fit_profiles::Bool=true,
46
EFIT_tree::String="EFIT02",
57
PROFILES_tree::String="ZIPFIT01",
68
CER_analysis_type::String="CERAUTO",
9+
EFIT_run_id::String="",
10+
PROFILES_run_id::String="",
11+
omfit_host::String=get(ENV, "FUSE_OMFIT_HOST", "somega.gat.com"),
12+
omfit_root::String=get(ENV, "FUSE_OMFIT_ROOT", "/fusion/projects/theory/fuse/d3d_data_fetching/OMFIT-source"),
13+
omas_root::String=get(ENV, "FUSE_OMAS_ROOT", "/fusion/projects/theory/fuse/d3d_data_fetching/omas"),
714
time_averaging::Float64=0.05,
815
rho_averaging::Float64=0.25,
916
new_impurity_match_power_rad::Symbol=:none,
10-
omega_user::String=get(ENV, "OMEGA_USER", ENV["USER"]),
11-
omega_omfit_root::String=get(ENV, "OMEGA_OMFIT_ROOT", "/fusion/projects/theory/fuse/d3d_data_fetching/OMFIT-source"),
12-
omega_omas_root::String=get(ENV, "OMEGA_OMAS_ROOT", "/fusion/projects/theory/fuse/d3d_data_fetching/omas"),
1317
use_local_cache::Bool=false
1418
)
1519
@@ -20,117 +24,41 @@ function case_parameters(::Val{:D3D}, shot::Int;
2024
EFIT_tree::String="EFIT02",
2125
PROFILES_tree::String="ZIPFIT01",
2226
CER_analysis_type::String="CERAUTO",
27+
EFIT_run_id::String="",
28+
PROFILES_run_id::String="",
29+
omfit_host::String=get(ENV, "FUSE_OMFIT_HOST", "somega.gat.com"),
30+
omfit_root::String=get(ENV, "FUSE_OMFIT_ROOT", "/fusion/projects/theory/fuse/d3d_data_fetching/OMFIT-source"),
31+
omas_root::String=get(ENV, "FUSE_OMAS_ROOT", "/fusion/projects/theory/fuse/d3d_data_fetching/omas"),
2332
time_averaging::Float64=0.05,
2433
rho_averaging::Float64=0.25,
2534
new_impurity_match_power_rad::Symbol=:none,
26-
omega_user::String=get(ENV, "OMEGA_USER", ENV["USER"]),
27-
omega_omfit_root::String=get(ENV, "OMEGA_OMFIT_ROOT", "/fusion/projects/theory/fuse/d3d_data_fetching/OMFIT-source"),
28-
omega_omas_root::String=get(ENV, "OMEGA_OMAS_ROOT", "/fusion/projects/theory/fuse/d3d_data_fetching/omas"),
2935
use_local_cache::Bool=false
3036
)
3137
ini, act = case_parameters(Val(:D3D_machine))
3238
ini.general.casename = "D3D $shot"
3339

34-
# to get user EFITs use (shot, USER01) to get (shot01, EFIT)
35-
if contains(EFIT_tree, "USER")
36-
efit_shot = parse(Int, "$(shot)$(EFIT_tree[5:end])")
37-
EFIT_tree = "EFIT"
38-
else
39-
efit_shot = shot
40-
end
41-
42-
# to get user OMFIT_PROFS use (shot, OMFIT_PROFS001) to get (shot001, OMFIT_PROFS)
43-
if contains(PROFILES_tree, "OMFIT_PROFS")
44-
prof_shot = parse(Int, "$(shot)$(PROFILES_tree[12:end])")
45-
PROFILES_tree = "OMFIT_PROFS"
46-
else
47-
prof_shot = shot
48-
end
49-
50-
# omas fetching script
51-
omas_fetching = """
52-
import time
53-
import omas
54-
from omas.omas_utils import printe
55-
from omas.machine_mappings import d3d
56-
from numpy import *
57-
58-
ods = omas.ODS()
59-
60-
tic = time.time()
61-
printe("- Fetching ec_launcher data")
62-
d3d.ec_launcher_active_hardware(ods, $shot)
63-
64-
# printe("- Fetching nbi data")
65-
# d3d.nbi_active_hardware(ods, $shot)
66-
67-
printe("- Fetching core_profiles data")
68-
d3d.core_profiles_profile_1d(ods, $prof_shot, PROFILES_tree="$(PROFILES_tree)")
69-
70-
printe("- Fetching wall data")
71-
d3d.wall(ods, $shot)
72-
73-
printe("- Fetching coils data")
74-
d3d.pf_active_hardware(ods, $shot)
75-
d3d.pf_active_coil_current_data(ods, $shot)
76-
77-
printe("- Fetching magnetic hardware data")
78-
d3d.magnetics_hardware(ods, $shot)
79-
80-
printe("- Fetching flux loops data")
81-
d3d.magnetics_floops_data(ods, $shot)
82-
83-
printe("- Fetching magnetic probes data")
84-
d3d.magnetics_probes_data(ods, $shot)
85-
86-
printe("- Fetching Thomson scattering data")
87-
d3d.thomson_scattering_data(ods, $shot)
88-
89-
printe("- Fetching interferometer data")
90-
d3d.interferometer_hardware(ods, $shot)
91-
d3d.interferometer_data(ods, $shot)
92-
93-
printe("- Fetching charge exchange data")
94-
d3d.charge_exchange_data(ods, $shot, analysis_type="$(CER_analysis_type)")
95-
96-
printe("- Fetching summary data")
97-
d3d.summary(ods, $shot)
98-
99-
printe("- Fetching equilibrium data")
100-
with ods.open('d3d', $efit_shot, options={'EFIT_tree': '$EFIT_tree'}):
101-
for k in range(len(ods["equilibrium.time"])):
102-
ods["equilibrium.time_slice"][k]["time"]
103-
ods["equilibrium.time_slice"][k]["global_quantities.ip"]
104-
ods["equilibrium.time_slice"][k]["profiles_1d.psi"]
105-
ods["equilibrium.time_slice"][k]["profiles_1d.f"]
106-
ods["equilibrium.time_slice"][k]["profiles_1d.pressure"]
107-
ods["equilibrium.time_slice"][k]["profiles_2d[0].psi"]
108-
ods["equilibrium.time_slice"][k]["profiles_2d[0].grid.dim1"]
109-
ods["equilibrium.time_slice"][k]["profiles_2d[0].grid.dim2"]
110-
ods["equilibrium.time_slice"][k]["profiles_2d[0].grid_type.index"] = 1
111-
ods["equilibrium.vacuum_toroidal_field.r0"]
112-
ods["equilibrium.vacuum_toroidal_field.b0"]
113-
114-
printe(f"Data fetched via OMAS in {time.time()-tic:.2f} [s]")
115-
"""
116-
117-
# variables used for data fetching
118-
remote_omas_root = "\$OMAS_ROOT"
119-
if !isempty(omega_omas_root)
120-
remote_omas_root = omega_omas_root
121-
end
122-
remote_omfit_root = "\$OMFIT_ROOT"
123-
if !isempty(omega_omfit_root)
124-
remote_omfit_root = omega_omfit_root
125-
end
126-
remote_host = "$(omega_user)@somega.gat.com"
127-
phash = hash((EFIT_tree, PROFILES_tree, CER_analysis_type, omega_user, omega_omfit_root, omega_omas_root, omas_fetching))
128-
remote_path = "/cscratch/$(omega_user)/d3d_data/$shot"
129-
filename = "D3D_$(shot)_$(phash).h5"
130-
if occursin(r"somega.*.gat.com", get(ENV, "HOSTNAME", "Unknown"))
131-
local_path = remote_path
40+
if omfit_host == "localhost"
41+
phash = hash((EFIT_tree, PROFILES_tree, CER_analysis_type, ENV["USER"], omfit_root, omas_root))
42+
filename = "D3D_$(shot)_$(phash).h5"
43+
local_path = joinpath(tempdir(), ENV["USER"]*"_D3D_$(shot)")
13244
else
133-
local_path = joinpath(tempdir(), "$(omega_user)_D3D_$(shot)")
45+
# Resolve remote username using the ssh config
46+
output = read(`ssh -G $omfit_host`, String)
47+
omfit_user = nothing
48+
for line in split(output, '\n')
49+
if startswith(line, "user ")
50+
omfit_user = strip(split(line, ' ', limit=2)[2])
51+
break
52+
end
53+
end
54+
if isnothing(omfit_user)
55+
throw(ErrorException("Need to add $omfit_host to ~/.ssh"))
56+
end
57+
omfit_host = "$omfit_user@$omfit_host"
58+
phash = hash((EFIT_tree, PROFILES_tree, CER_analysis_type, omfit_user, omfit_root, omas_root))
59+
remote_path = get(ENV, "FUSE_SCRATCH", "/cscratch/"*omfit_user*"/d3d_data/$shot")
60+
filename = "D3D_$(shot)_$(phash).h5"
61+
local_path = joinpath(tempdir(), "$(omfit_user)_D3D_$(shot)")
13462
end
13563
if isdir(local_path) && !use_local_cache
13664
rm(local_path; recursive=true)
@@ -139,83 +67,107 @@ function case_parameters(::Val{:D3D}, shot::Int;
13967
mkdir(local_path)
14068
end
14169

142-
# remote omas script
143-
omas_py = omas_fetching * """
144-
printe("Saving ODS to $filename", end="")
145-
tic = time.time()
146-
ods.save("$filename")
147-
printe(f" Done in {time.time()-tic:.2f} [s]")
148-
"""
149-
open(joinpath(local_path, "omas_data_fetch.py"), "w") do io
150-
return write(io, omas_py)
70+
71+
# to get user EFITs use (shot, USER01) to get (shot01, EFIT)
72+
if contains(EFIT_tree, "USER")
73+
efit_shot = parse(Int, "$(shot)$(EFIT_tree[5:end])")
74+
EFIT_tree = "EFIT"
75+
else
76+
efit_shot = shot
15177
end
15278

153-
# remote bash/slurm script
154-
remote_slurm = """#!/bin/bash -l
155-
#SBATCH --job-name=fetch_d3d_omas
156-
#SBATCH --partition=short
157-
#SBATCH --cpus-per-task=1
158-
#SBATCH --ntasks=2
159-
#SBATCH --output=$remote_path/%j.out
160-
#SBATCH --error=$remote_path/%j.err
161-
#SBATCH --wait
162-
163-
# Load any required modules
79+
if omfit_host == "localhost"
80+
setup_block = """#!/bin/bash -l
16481
module purge
165-
module load omfit/unstable
82+
module load omfit
83+
cd $local_path
84+
export PYTHONPATH=$(omas_root):\$PYTHONPATH
85+
"""
86+
omfit_block = """
87+
python -u $(omfit_root)/omfit/omfit.py $(omfit_root)/modules/RABBIT/SCRIPTS/rabbit_input_no_gui.py "shot=$shot" "output_path='$local_path'" > /dev/null 2> /dev/null
88+
"""
89+
omas_block = """
90+
python -u $(omas_root)/omas/examples/fuse_data_export.py $local_path/$filename d3d $shot $EFIT_tree $PROFILES_tree --CER_ANALYSIS_TYPE=$CER_analysis_type"""
91+
if length(EFIT_run_id) >0
92+
omas_block *= " --EFIT_RUN_ID $EFIT_run_id"
93+
end
94+
if length(PROFILES_run_id) >0
95+
omas_block *= " --PROFILES_RUN_ID $PROFILES_run_id"
96+
end
97+
omfit_sh = joinpath(local_path, "omfit.sh")
98+
open(omfit_sh, "w") do io
99+
return write(io, setup_block*omfit_block)
100+
end
101+
omas_sh = joinpath(local_path, "omas.sh")
102+
open(omas_sh, "w") do io
103+
return write(io, setup_block*omas_block)
104+
end
105+
Base.run(`chmod +x $omfit_sh`)
106+
Base.run(`chmod +x $omas_sh`)
107+
task = @async Base.run(`$omfit_sh`)
108+
Base.run(`$omas_sh`)
109+
wait(task)
110+
else
111+
# remote bash/slurm script
112+
remote_slurm = """#!/bin/bash -l
113+
#SBATCH --job-name=fetch_d3d_omas
114+
#SBATCH --partition=short
115+
#SBATCH --cpus-per-task=1
116+
#SBATCH --ntasks=2
117+
#SBATCH --output=$remote_path/%j.out
118+
#SBATCH --error=$remote_path/%j.err
119+
#SBATCH --wait
166120
167-
echo "Starting parallel tasks..." >&2
121+
# Load any required modules
122+
module purge
123+
module load omfit/unstable
168124
169-
# Run both tasks in parallel
170-
cd $remote_path
171-
export PYTHONPATH=$(remote_omas_root):\$PYTHONPATH
125+
echo "Starting parallel tasks..." >&2
172126
173-
python -u $(remote_omfit_root)/omfit/omfit.py $(remote_omfit_root)/modules/RABBIT/SCRIPTS/rabbit_input_no_gui.py "shot=$shot" "output_path='$remote_path'" 2>&1 > "$remote_path/omfit_log.txt" &
127+
# Run both tasks in parallel
128+
mkdir -p $remote_path
129+
cd $remote_path
174130
175-
python -u omas_data_fetch.py 2>&1 | tee "$remote_path/omas_log.txt"
131+
export PYTHONPATH=$(omas_root):\$PYTHONPATH
176132
177-
echo "Waiting for OMFIT D3D BEAMS data fetching to complete..." >&2
178-
wait
179-
echo "Transfering data from the remote" >&2
180-
"""
181-
open(joinpath(local_path, "remote_slurm.sh"), "w") do io
182-
return write(io, remote_slurm)
183-
end
133+
python -u $(omfit_root)/omfit/omfit.py $(omfit_root)/modules/RABBIT/SCRIPTS/rabbit_input_no_gui.py "shot=$shot" "output_path='$remote_path'" > /dev/null 2> /dev/null &
184134
185-
if occursin(r"somega.*.gat.com", get(ENV, "HOSTNAME", "Unknown"))
186-
# local driver script
187-
local_driver = """
188-
#!/bin/bash
189-
module load omfit; cd $remote_path && bash remote_slurm.sh
135+
python -u $(omas_root)/omas/examples/fuse_data_export.py $remote_path/$(filename) d3d $shot EFIT02 ZIPFIT01
136+
137+
echo "Waiting for OMFIT D3D BEAMS data fetching to complete..." >&2
138+
wait
139+
echo "Transfering data from remote" >&2
190140
"""
191-
else
141+
open(joinpath(local_path, "remote_slurm.sh"), "w") do io
142+
return write(io, remote_slurm)
143+
end
192144
# local driver script
193145
local_driver = """
194146
#!/bin/bash
195147
196148
# Use rsync to create directory if it doesn't exist and copy the script
197-
$(ssh_command(remote_host, "\"mkdir -p $remote_path\""))
198-
$(upsync_command(remote_host, ["$(local_path)/remote_slurm.sh", "$(local_path)/omas_data_fetch.py"], remote_path))
149+
$(ssh_command(omfit_host, "\"mkdir -p $remote_path\""))
150+
$(upsync_command(omfit_host, ["$(local_path)/remote_slurm.sh", "$(local_path)/omas_data_fetch.py"], remote_path))
199151
200152
# Execute script remotely
201-
$(ssh_command(remote_host, "\"module load omfit; cd $remote_path && bash remote_slurm.sh\""))
153+
$(ssh_command(omfit_host, "\"module load omfit; cd $remote_path && bash remote_slurm.sh\""))
202154
203155
# Retrieve results using rsync
204-
$(downsync_command(remote_host, ["$remote_path/$(filename)", "$remote_path/nbi_ods_$shot.h5", "$remote_path/beams_$shot.dat"], local_path))
156+
$(downsync_command(omfit_host, ["$remote_path/$(filename)", "$remote_path/nbi_ods_$shot.h5", "$remote_path/beams_$shot.dat"], local_path))
205157
"""
206-
end
207-
open(joinpath(local_path, "local_driver.sh"), "w") do io
208-
return write(io, local_driver)
209-
end
158+
159+
open(joinpath(local_path, "local_driver.sh"), "w") do io
160+
return write(io, local_driver)
161+
end
210162

211-
# run data fetching
212-
@info("Remote D3D data fetching for shot $shot")
213-
@info("Path on OMEGA: $remote_path")
214-
@info("Path on Localhost: $local_path")
215-
if !isfile(joinpath(local_path, filename)) || !use_local_cache
216-
Base.run(`bash $local_path/local_driver.sh`)
163+
# run data fetching
164+
@info("Remote D3D data fetching for shot $shot")
165+
@info("Path on $omfit_host: $remote_path")
166+
@info("Path on Localhost: $local_path")
167+
if !isfile(joinpath(local_path, filename)) || !use_local_cache
168+
Base.run(`bash $local_path/local_driver.sh`)
169+
end
217170
end
218-
219171
# load experimental ods
220172
ini.ods.filename = "$(ini.ods.filename),$(joinpath(local_path,filename)),$(joinpath(local_path,"nbi_ods_$shot.h5"))"
221173
@info("Loading files: $(join(map(basename,split(ini.ods.filename,","))," ; "))")

src/utils_begin.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,7 @@ function parallel_environment(
332332
else
333333
error("Cluster `$cluster` is unknown. Use `localhost` or add `$cluster` to the FUSE.parallel_environment")
334334
end
335+
335336
# import FUSE and IJulia on workers
336337
if workers_import_fuse
337338
if isdefined(Main, :IJulia)

0 commit comments

Comments
 (0)