vmecpp package

class vmecpp.JxBOut(**data)

Bases: BaseModel

Parameters:

data (Any)

amaxfor: jt.Float[np.ndarray, ' dim1']
aminfor: jt.Float[np.ndarray, ' dim1']
avforce: jt.Float[np.ndarray, ' dim1']
bdotb: jt.Float[np.ndarray, ' dim1']
bdotgradv: jt.Float[np.ndarray, ' dim1']
bdotk: jt.Float[np.ndarray, 'num_full nZnT']
bsubs3: jt.Float[np.ndarray, 'num_full nZnT']
bsubu3: jt.Float[np.ndarray, 'num_half nZnT']
bsubv3: jt.Float[np.ndarray, 'num_half nZnT']
bsupu3: jt.Float[np.ndarray, 'num_full nZnT']
bsupv3: jt.Float[np.ndarray, 'num_full nZnT']
itheta: jt.Float[np.ndarray, 'num_full nZnT']
izeta: jt.Float[np.ndarray, 'num_full nZnT']
jcrossb: jt.Float[np.ndarray, 'num_full nZnT']
jdotb: jt.Float[np.ndarray, ' dim1']
jdotb_sqrtg: jt.Float[np.ndarray, 'num_full nZnT']
jpar2: jt.Float[np.ndarray, ' dim1']
jperp2: jt.Float[np.ndarray, ' dim1']
jsups3: jt.Float[np.ndarray, 'num_half nZnT']
jsupu3: jt.Float[np.ndarray, 'num_full nZnT']
jsupv3: jt.Float[np.ndarray, 'num_full nZnT']
jxb_gradp: jt.Float[np.ndarray, 'num_full nZnT']
model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'forbid'}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

phin: jt.Float[np.ndarray, ' dim1']
pprim: jt.Float[np.ndarray, ' dim1']
sqrtg3: jt.Float[np.ndarray, 'num_full nZnT']
class vmecpp.Mercier(**data)

Bases: BaseModel

Parameters:

data (Any)

DMerc: jt.Float[np.ndarray, ' dim1']
Dcurr: jt.Float[np.ndarray, ' dim1']
Dgeod: jt.Float[np.ndarray, ' dim1']
Dshear: jt.Float[np.ndarray, ' dim1']
Dwell: jt.Float[np.ndarray, ' dim1']
d_pressure_d_s: jt.Float[np.ndarray, ' dim1']
d_toroidal_current_d_s: jt.Float[np.ndarray, ' dim1']
d_volume_d_s: jt.Float[np.ndarray, ' dim1']
iota: jt.Float[np.ndarray, ' dim1']
model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'forbid'}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

pressure: jt.Float[np.ndarray, ' dim1']
s: jt.Float[np.ndarray, ' dim1']
shear: jt.Float[np.ndarray, ' dim1']
toroidal_current: jt.Float[np.ndarray, ' dim1']
toroidal_flux: jt.Float[np.ndarray, ' dim1']
well: jt.Float[np.ndarray, ' dim1']
class vmecpp.Threed1Volumetrics(**data)

Bases: BaseModel

Parameters:

data (Any)

avg_bpol: float
avg_btor: float
avg_ekin: float
avg_modb: float
avg_p: float
int_bpol: float
int_btor: float
int_ekin: float
int_modb: float
int_p: float
model_config: ClassVar[ConfigDict] = {'extra': 'forbid'}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class vmecpp.VmecInput(**data)

Bases: BaseModel

The input to a VMEC++ run. Contains settings as well as the definition of the plasma boundary.

Python equivalent of a VMEC++ JSON input file or a classic INDATA file (e.g. “input.best”).

Deserialize from JSON and serialize to JSON using the usual pydantic methods: model_validate_json and model_dump_json.

Parameters:

data (Any)

ac: jt.Float[np.ndarray, ' ac_len']

Enclosed toroidal current profile coefficients.

ac_aux_f: jt.Float[np.ndarray, ' ac_aux_len']

values at knots

Type:

Spline toroidal current profile

ac_aux_s: jt.Float[np.ndarray, ' ac_aux_len']

knot locations in s

Type:

Spline toroidal current profile

ai: jt.Float[np.ndarray, ' ai_len']

Iota profile coefficients.

ai_aux_f: jt.Float[np.ndarray, ' ai_aux_len']

values at knots

Type:

Spline iota profile

ai_aux_s: jt.Float[np.ndarray, ' ai_aux_len']

knot locations in s

Type:

Spline iota profile

am: jt.Float[np.ndarray, ' am_len']

Mass/pressure profile coefficients.

am_aux_f: jt.Float[np.ndarray, ' am_aux_len']

values at knots

Type:

Spline mass/pressure profile

am_aux_s: jt.Float[np.ndarray, ' am_aux_len']

knot locations in s

Type:

Spline mass/pressure profile

aphi: jt.Float[np.ndarray, ' aphi_len']

Radial flux zoning profile coefficients.

bloat: float

Bloating factor (for constrained toroidal current)

curtor: float

Toroidal current in A.

delt: float

Initial value for artificial time step in iterative solver.

extcur: jt.Float[np.ndarray, ' extcur_len']

Coil currents in A.

static from_file(input_file)

Build a VmecInput from either a VMEC++ JSON input file or a classic INDATA file.

Parameters:

input_file (str | Path)

Return type:

VmecInput

ftol_array: jt.Float[np.ndarray, ' num_grids']

Requested force tolerance for convergence per multigrid step.

gamma: float

Adiabatic index.

lasym: bool

Flag to indicate non-stellarator-symmetry.

lforbal: bool

directly compute innermost flux surface geometry from radial force balance

Type:

Hack

lfreeb: bool

Flag to indicate free-boundary.

mgrid_file: str

Full path for vacuum Green’s function data.

model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'ser_json_inf_nan': 'strings'}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

mpol: int

Number of poloidal Fourier harmonics; m = 0, 1, …, (mpol-1)

ncurr: int

constrained-current

Type:

Select constraint on iota or enclosed toroidal current profiles 0

Type:

constrained-iota; 1

nfp: int

Number of toroidal field periods (=1 for Tokamak)

niter_array: jt.Int[np.ndarray, ' num_grids']

Maximum number of iterations per multigrid step.

ns_array: jt.Int[np.ndarray, ' num_grids']

Number of flux surfaces per multigrid step.

nstep: int

Printout interval.

ntheta: int

is rounded to next smaller even number.

Type:

Number of poloidal grid points; if odd

ntor: int

Number of toroidal Fourier harmonics; n = -ntor, -ntor+1, …, -1, 0, 1, …, ntor-1, ntor.

nvacskip: int

Number of iterations between full vacuum calculations.

nzeta: int

Number of toroidal grid points; must match nzeta of mgrid file if using free- boundary.

pcurr_type: str

Parametrization of toroidal current profile.

phiedge: float

Total enclosed toroidal magnetic flux in Vs == Wb.

piota_type: str

Parametrization of iota profile.

pmass_type: str

Parametrization of mass/pressure profile.

pres_scale: float

Global scaling factor for mass/pressure profile.

raxis_c: jt.Float[np.ndarray, ' ntor_plus_1']

Magnetic axis coefficients for R ~ cos(n*v); stellarator-symmetric.

raxis_s: jt.Float[np.ndarray, ' ntor_plus_1']

Magnetic axis coefficients for R ~ sin(n*v); non-stellarator-symmetric.

rbc: jt.Float[np.ndarray, ' mpol two_ntor_plus_one']

Boundary coefficients for R ~ cos(m*u - n*v); stellarator-symmetric

rbs: jt.Float[np.ndarray, ' mpol two_ntor_plus_one']

Boundary coefficients for R ~ sin(m*u - n*v); non-stellarator-symmetric

spres_ped: float

Location of pressure pedestal in s.

tcon0: float

Constraint force scaling factor for ns –> 0.

zaxis_c: jt.Float[np.ndarray, ' ntor_plus_1']

Magnetic axis coefficients for Z ~ cos(n*v); non-stellarator-symmetric.

zaxis_s: jt.Float[np.ndarray, ' ntor_plus_1']

Magnetic axis coefficients for Z ~ sin(n*v); stellarator-symmetric.

zbc: jt.Float[np.ndarray, ' mpol two_ntor_plus_one']

Boundary coefficients for Z ~ cos(m*u - n*v); non-stellarator-symmetric

zbs: jt.Float[np.ndarray, ' mpol two_ntor_plus_one']

Boundary coefficients for Z ~ sin(m*u - n*v); stellarator-symmetric

class vmecpp.VmecOutput(**data)

Bases: BaseModel

Container for the full output of a VMEC run.

Parameters:

data (Any)

input: VmecInput

The input to the VMEC run that produced this output.

jxbout: JxBOut

Python equivalent of VMEC’s “jxbout” file.

mercier: Mercier

Python equivalent of VMEC’s “mercier” file.

model_config: ClassVar[ConfigDict] = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

threed1_volumetrics: Threed1Volumetrics

Python equivalent of VMEC’s volumetrics section in the “threed1” file.

wout: VmecWOut

Python equivalent of VMEC’s “wout” file.

class vmecpp.VmecWOut(**data)

Bases: BaseModel

Python equivalent of a VMEC “wout file”.

VmecWOut exposes the layout that SIMSOPT expects. The save method produces a NetCDF file compatible with SIMSOPT/Fortran VMEC.

Parameters:

data (Any)

Aminor_p: float
DCurr: jt.Float[np.ndarray, '...']
DGeod: jt.Float[np.ndarray, '...']
DMerc: jt.Float[np.ndarray, ' dim1']
DShear: jt.Float[np.ndarray, '...']
DWell: jt.Float[np.ndarray, '...']
IonLarmor: float
Rmajor_p: float
aspect: float
b0: float
bdotgradv: jt.Float[np.ndarray, ' dim1']
beta_vol: jt.Float[np.ndarray, '...']
betapol: float
betator: float
betatotal: float
betaxis: float
bmnc: jt.Float[np.ndarray, 'dim1 dim2']
bsubsmns: jt.Float[np.ndarray, 'dim1 dim2']
bsubumnc: jt.Float[np.ndarray, 'dim1 dim2']
bsubvmnc: jt.Float[np.ndarray, 'dim1 dim2']
bsupumnc: jt.Float[np.ndarray, 'dim1 dim2']
bsupvmnc: jt.Float[np.ndarray, 'dim1 dim2']
buco: jt.Float[np.ndarray, ' dim1']
bvco: jt.Float[np.ndarray, ' dim1']
chi: jt.Float[np.ndarray, '...']
chipf: jt.Float[np.ndarray, ' dim1']
ctor: float
equif: jt.Float[np.ndarray, ' dim1']
fsql: float
fsqr: float
fsqz: float
ftolv: float
gamma: float
gmnc: jt.Float[np.ndarray, 'dim1 dim2']
ier_flag: int
iotaf: jt.Float[np.ndarray, '...']
iotas: jt.Float[np.ndarray, '...']
jcuru: jt.Float[np.ndarray, ' dim1']
jcurv: jt.Float[np.ndarray, ' dim1']
jdotb: jt.Float[np.ndarray, ' dim1']
lasym: bool
property lasym__logical__

This is how the attribute is called in the Fortran wout file.

lfreeb: bool
property lfreeb__logical__

This is how the attribute is called in the Fortran wout file.

lmns: jt.Float[np.ndarray, 'mnmax n_surfaces']
lmns_full: jt.Float[np.ndarray, 'mnmax n_surfaces']
mass: jt.Float[np.ndarray, ' dim1']
mgrid_file: str
mnmax: int
mnmax_nyq: int
model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'forbid'}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

mpol: int
nfp: int
niter: int
ns: int
ntor: int
over_r: jt.Float[np.ndarray, '...']
pcurr_type: str
phi: jt.Float[np.ndarray, '...']
phipf: jt.Float[np.ndarray, ' dim1']
phips: jt.Float[np.ndarray, ' dim1']
piota_type: str
pmass_type: str
pres: jt.Float[np.ndarray, '...']
presf: jt.Float[np.ndarray, '...']
q_factor: jt.Float[np.ndarray, '...']
raxis_cc: jt.Float[np.ndarray, '...']
rbtor: float
rbtor0: float
rmax_surf: float
rmin_surf: float
rmnc: jt.Float[np.ndarray, 'dim1 dim2']
save(out_path)

Save contents in NetCDF3 format.

This is the format used by Fortran VMEC implementations and the one expected by SIMSOPT.

Parameters:

out_path (str | Path)

Return type:

None

signgs: int
specw: jt.Float[np.ndarray, '...']
version_: float
volavgB: float
volume: float
property volume_p

The attribute is called volume_p in the Fortran wout file, while simsopt.mhd.Vmec.wout uses volume.

We expose both.

vp: jt.Float[np.ndarray, '...']
wb: float
wp: float
xm: jt.Int[np.ndarray, ' dim1']
xm_nyq: jt.Int[np.ndarray, ' dim1']
xn: jt.Int[np.ndarray, ' dim1']
xn_nyq: jt.Int[np.ndarray, ' dim1']
zaxis_cs: jt.Float[np.ndarray, '...']
zmax_surf: float
zmns: jt.Float[np.ndarray, 'dim1 dim2']
vmecpp.run(input, max_threads=None, verbose=True, restart_from=None)

Run VMEC++ using the provided input.

Parameters:
  • input (VmecInput) – a VmecInput instance, corresponding to the contents of a classic VMEC input file

  • max_threads (Optional[int]) – maximum number of threads that VMEC++ should spawn. The actual number might still be lower that this in case there are too few flux surfaces to keep these many threads busy. If None, a number of threads equal to the number of logical cores is used.

  • verbose (bool) – if True, VMEC++ logs its progress to standard output.

  • restart_from (Optional[VmecOutput]) – if present, VMEC++ is initialized using the converged equilibrium from the provided VmecOutput. This can dramatically decrease the number of iterations to convergence when running VMEC++ on a configuration that is very similar to the restart_from equilibrium.

Return type:

VmecOutput

Submodules