Scan and build a database¶
This section illustrates how to 1) prepare a scan, 2) submit a job with DAKOTA or massive serial, 3) collect output files, and 4) build a database. We will use a 2D scan example - aspect ratio and heating power.
Prepare a scan¶
Command line
grid.py --input=grid.json --nsim=32
This will generate the input file for DAKOTA (dakota.in) and massive serial (inscan).
The option --nsim
specifies the number of cocurrent runs for DAKOTA.
grid.json
{
"scan": {
"aratio": {"type": "range", "ymin":2.5, "ymax":3.5, "ndata":8},
"pinj" : {"type": "list", "data":[20.0, 30.0, 40.0, 50.0]}
},
"const": {
"a" : 1.3333,
"kappa" : 2.0,
"delta" : 0.6,
"bt" : 4.0,
"ip" : 8.1,
"xwid" : 0.08,
"xmid" : 0.96,
"nepeak" : 1.75,
"fgw_ped" : 0.9,
"f_nesep" : 0.5,
"h98" : 1.35,
"f_pinj_e": 0.75
},
"model": {
"r" : ["expr", "a * aratio" ],
"betan_ped" : ["base", {} ],
"te_ped" : ["base", {"dependency":"betan_ped"} ],
"ti_ped" : ["expr", "te_ped" ],
"te_axis" : ["expr", "5.75 * te_ped" ],
"ti_axis" : ["expr", "5.0 * ti_ped" ],
"ngw" : ["base", {} ],
"ne_ped" : ["expr", "fgw_ped * ngw" ],
"ne_axis" : ["expr", "nepeak * ne_ped" ],
"ne_sep" : ["expr", "f_nesep * ne_ped" ],
"pinj_e" : ["expr", "pinj * f_pinj_e" ],
"pinj_i" : ["expr", "pinj * ( 1.0 - f_pinj_e ) " ]
},
"io": {
"index" : ["efit" , "TIME_ID" ],
"r" : ["fastran_init", "R0" ],
"a" : ["fastran_init", "A0" ],
"kappa" : ["fastran_init", "KAPPA" ],
"delta" : ["fastran_init", "DELTA" ],
"bt" : ["fastran_init", "B0" ],
"ip" : ["fastran_init", "IP" ],
"xwid" : ["fastran_init", "XWID" ],
"xmid" : ["fastran_init", "XMID" ],
"ne_axis" : ["fastran_init", "NE_AXIS" ],
"ne_ped" : ["fastran_init", "NE_PED" ],
"ne_sep" : ["fastran_init", "NE_SEP" ],
"te_axis" : ["fastran_init", "TE_AXIS" ],
"te_ped" : ["fastran_init", "TE_PED" ],
"ti_axis" : ["fastran_init", "TI_AXIS" ],
"ti_ped" : ["fastran_init", "TI_PED" ],
"h98" : ["fastran_init", "H98_TARGET" ],
"pinj_e" : ["hcd_model" , "INHCD_PE_0" ],
"pinj_i" : ["hcd_model" , "INHCD_PI_0" ]
}
}
The TokDesigner variables consist of the variables defined in the scan
, const
, and model
sections.
Scan section
aratio
(aspect ratio) : ndata points (8) between the minimum value (2.5) and the maximum value (3.5)pinj
(injection power, MW) : 4 points are given by the user input list [20.0, 30.0, 40.0, 50.0]- Number of total scan = 8 * 4 = 32
Const section
The const
section defines the constant TokDesigner variables.
Model section
The variables in the model section are determined by the predefined models or user defined formula.
For instance, the major radius r
has the type expr
(expression type), so will be specified by the expression r = aratio * a
.
Note that we defined aratio
as a scan variable and a
as a constant variable to calculate r
.
Exercise: aspect ratio scan with the fixed major radius r
{
"scan": {
"aratio": {"type": "range", "ymin":2.5, "ymax":3.5, "ndata":8},
...
}
"constant" {
"r: 4.0,
...
}
"model": {
"a": ["expr", "r / aratio"],
...
}
...
}
TokDesigner provides a range of simplified models. In this example, the pedestal betan betan_ped
is a base
model variable, where betan_ped
is calculated by the TokDesigner model (Phil Snyder’s simple triangularity delta
scaling):
import numpy as np
from kernel.base.tokamak_parameter import TokamakParameter
# normalized beta at pedestal
class betan_ped_model(TokamakParameter):
def __init__(self, model='base'):
TokamakParameter.__init__(self, model)
self.dependency = ["delta"]
def base_model(self, ps):
delta = ps["delta"]
betanped = 0.2 + 1.3*delta
return betanped
Then, the pedestal electron temperature te_ped
is calculated by the base
model, which is a simple conversion from betan_ped
to te_ped
. Instead, users may use the euivalent expr
:
"model": {
...
"te_ped": ["expr", "1.2424 * ip * bt / ( ne_ped * a )"],
...
}
This example assumes that the ion pedestal temperature ti_ped
is same to te_ped
.
"model": {
...
"ti_ped" : ["expr", "te_ped"],
...
}
Note
The model is also outcome of the TokDeisgner workflows, which can be used to generate the next scan. This iterative and recursive process is one of the key concepts of TokDesigner.
Io section
This defines a map between the TokDesigner variables and the IPS-FASTRAN/CESOL simulation variables.
For example, the R0
value of the instate file in the fastran_init component will be updated by the TokDesigner Variable r
.
"r" : ["fastran_init", "R0"],
See more details :ref:ingrid_io_reference.
Job submission on CORI¶
This example submitjob.ex2
uses a DAKOTA scan with the scan file dakota.in
generated by grid.py
. Single CORI node (32 cores) is allocated, which will be shared by 32 single core IPS-FASTRAN runs simultaneously.
#!/bin/bash -l
#SBATCH -p debug
#SBATCH -N 1
#SBATCH -t 00:10:00
#SBATCH -J ips_fastran
#SBATCH -e ips.err
#SBATCH -o ips.out
#SBATCH -C haswell
module load python
source activate /global/common/software/atom/cori/cesol_conda/t0.14b
export SHOT_NUMBER=000001
export TIME_ID=00001
ips_dakota_dynamic.py --dakotaconfig=dakota.in --simulation=fastran_scenario.config --platform=cori_haswell_node.conf --log=ips_sweep.log
conda deactivate
See also how to use a massive serial for a larger ensemble of simulation.
Collect output files¶
Command line
collect.py --rdir0=. --rdir=SCAN --sdir=SUMMARY --input=collect.json
This will collect output files in the simulation directory SCAN
into the summary directory SUMMARY
.
See convention of the directory structure and how to modify the run directory name.
collect.json
{
"output" : [
["fastran_tr0_fastran", "fastran.nc" , "f", "result" ],
["fastran_eq0_efit", "g??????.?????", "g", "result" ],
["fastran_eq0_efit", "a??????.?????", "a", "result" ],
["fastran_eq0_efit", "s??????.?????", "s", "result" ],
["fastran_tr0_fastran", "i??????.?????", "i", "result" ]
],
"input" : [
"fastran_scenario.config"
]
}
The collect.json
defines which output files to archive. For example, the fastran0
solver component ([fastran0]
), which is identified as fastran_tr0_fastran
(CLASS
+ _
+ SUB_CLASS
+ _
+ NAME
), archives fastran.nc
with the name: f
+ SHOT_NUMBER
+ .
+ TIME_ID
(like f123456.00001), where the TIME_ID
is the identifier in dakota.in
or inscan
.
See the fastran0
componenet definition in the fastran_scenario.config
.
[fastran0]
CLASS = fastran
SUB_CLASS = tr0
NAME = fastran
...
OUTPUT_FILES = fastran.nc xfastran.log ${CURRENT_INSTATE}
....
Build a database¶
Command line
makedb.py --input=makedb.json --output=db.dat --rdir=SUMMARY
This will generate a database file db.dat
using the IPS-FASTRAN/CESOL output files archived in the SUMMARY
directory (note collect.py .. --sdir=SUMMARY ..
)
makedb.json
The makedb.json
defines the database variables. For the illustration purpose, only a few variables are included - r, a, aratio, bt, ip, pinj, q95, betan, fbs, li, tau98, tauth, h98, pfus.
{
"variable": {
"r" : ["instate" , "r0" , "input" ],
"a" : ["instate" , "a0" , "input" ],
"bt" : ["instate" , "b0" , "input" ],
"ip" : ["instate" , "ip" , "input" ],
"q95" : ["aeqdsk" , "q95" , "output"],
"li" : ["aeqdsk" , "li" , "output"],
"betap" : ["aeqdsk" , "betap" , "output"],
"betat" : ["aeqdsk" , "betat" , "output"],
"ne_ped" : ["instate" , "ne_ped" , "input" ],
"nebar" : ["fastran" , "nebar" , "output"],
"betan" : ["fastran" , "betan" , "output"],
"pfuse" : ["fastran" , "pfuse" , "output"],
"pfusi" : ["fastran" , "pfusi" , "output"],
"ibs" : ["fastran" , "ibs" , "output"]
},
"model": {
"aratio" : ["expr", "r / a" ],
"pfus" : ["expr", "5.0 * ( pfuse + pfusi )"],
"fbs" : ["expr", "ibs / ip"]
}
}
- The major radius
r
is read from theinstate
file (i<shot_number>.<time_id>
) - The q95 value
q95
is read from the EFIT “aeqdsk`` file (a<shot_number>.<time_id>
) - The alpha fusion power to electron
pfuse
is read from thefastran
output netcdf file (f<shot_number>.<time_id>
)
Note that the model
method can be used as in the grid.py
.
- The aspect ratio
araio = r / a
- The bootstrap current
fbs = ibs / ip
See the table for the typical TokDesigner variables.