diff --git a/CMakeLists.txt b/CMakeLists.txt
index db15c7829e..f61d5f6a4d 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -124,6 +124,7 @@ LIST(APPEND PROCESS_SRCS
stellarator.f90
stellarator_configuration.f90
stellarator_fwbs.f90
+ startup_variables.f90
)
PREPROCESS()
diff --git a/process/current_drive.py b/process/current_drive.py
index 0daaf7f148..856d190bba 100644
--- a/process/current_drive.py
+++ b/process/current_drive.py
@@ -946,7 +946,7 @@ def cudriv(self, output: bool):
po.ovarrf(
self.outfile,
"Total",
- "(current_drive_variables.plasipf+physics_variables.faccd+physics_variables.facoh)",
+ "(plasipf+faccd+facoh)",
current_drive_variables.plasipf
+ physics_variables.faccd
+ physics_variables.facoh,
diff --git a/process/output.py b/process/output.py
index 76980cc51b..46cdbabd2b 100644
--- a/process/output.py
+++ b/process/output.py
@@ -46,17 +46,17 @@ def write(models, outfile):
models.availability.run(output=True)
# Writing the output from physics.f90 into OUT.DAT + MFILE.DAT
- ft.physics_module.outplas(outfile)
+ models.physics.outplas()
# TODO what is this? not in caller.f90
- ft.physics_module.igmarcal(outfile)
+ models.physics.igmarcal()
# TODO what is this? Not in caller.f90?
models.current_drive.cudriv(output=True)
# Pulsed reactor model
models.pulse.run(output=True)
- ft.physics_module.outtim(outfile)
+ models.physics.outtim()
models.divertor.run(output=True)
diff --git a/process/physics.py b/process/physics.py
index ba12778ebe..39d9564430 100644
--- a/process/physics.py
+++ b/process/physics.py
@@ -1,23 +1,31 @@
-import numpy
+import numpy as np
+import scipy.integrate as integrate
+from scipy.optimize import root_scalar
import math
import process.physics_functions as physics_funcs
-from process.fortran import constraint_variables
-from process.fortran import reinke_variables
-from process.fortran import reinke_module
-from process.fortran import impurity_radiation_module
-from process.fortran import constants
-from process.fortran import physics_functions_module
-from process.fortran import physics_variables
-from process.fortran import physics_module
-from process.fortran import pulse_variables
-from process.fortran import times_variables
-from process.fortran import current_drive_variables
-from process.fortran import error_handling
-from process.fortran import fwbs_variables
-from process.fortran import build_variables
-from process.fortran import divertor_variables
-from process.fortran import numerics
-from process.fortran import process_output as po
+from process.utilities.f2py_string_patch import f2py_compatible_to_string
+from process.fortran import (
+ constraint_variables,
+ reinke_variables,
+ reinke_module,
+ impurity_radiation_module,
+ constants,
+ physics_functions_module,
+ physics_variables,
+ physics_module,
+ pulse_variables,
+ times_variables,
+ current_drive_variables,
+ error_handling,
+ fwbs_variables,
+ build_variables,
+ divertor_variables,
+ numerics,
+ stellarator_variables,
+ process_output as po,
+ profiles_module,
+ startup_variables,
+)
class Physics:
@@ -41,12 +49,12 @@ def physics(self):
https://inis.iaea.org/search/search.aspx?orig_q=RN:45031642
"""
# kappaa_IPB = physics_variables.vol / (
- # 2.0e0
- # * numpy.pi
- # * numpy.pi
- # * physics_variables.rminor
- # * physics_variables.rminor
- # * physics_variables.rmajor
+ # 2.0e0
+ # * numpy.pi
+ # * numpy.pi
+ # * physics_variables.rminor
+ # * physics_variables.rminor
+ # * physics_variables.rmajor
# )
if physics_variables.icurr == 2:
@@ -60,14 +68,16 @@ def physics(self):
# Calculate plasma composition
# Issue #261 Remove old radiation model (imprad_model=0)
- physics_module.plasma_composition()
+ self.plasma_composition()
- # Calculate plasma current
+ # Calculate plasma current
(
+ physics_variables.alphaj,
+ physics_variables.rli,
physics_variables.bp,
physics_variables.qstar,
physics_variables.plascur,
- ) = physics_module.culcur(
+ ) = self.culcur(
physics_variables.alphaj,
physics_variables.alphap,
physics_variables.bt,
@@ -88,16 +98,16 @@ def physics(self):
physics_variables.triang95,
)
- # Calculate density and temperature profile quantities
- # If physics_variables.ipedestal = 1 then set pedestal density to
- # physics_variables.fgwped * Greenwald density limit
- # Note: this used to be done before plasma current
+ # Calculate density and temperature profile quantities
+ # If physics_variables.ipedestal = 1 then set pedestal density to
+ # physics_variables.fgwped * Greenwald density limit
+ # Note: this used to be done before plasma current
if (physics_variables.ipedestal == 1) and (physics_variables.fgwped >= 0e0):
physics_variables.neped = (
physics_variables.fgwped
* 1.0e14
* physics_variables.plascur
- / (numpy.pi * physics_variables.rminor * physics_variables.rminor)
+ / (np.pi * physics_variables.rminor * physics_variables.rminor)
)
if (physics_variables.ipedestal == 1) and (physics_variables.fgwsep >= 0e0):
@@ -105,7 +115,7 @@ def physics(self):
physics_variables.fgwsep
* 1.0e14
* physics_variables.plascur
- / (numpy.pi * physics_variables.rminor * physics_variables.rminor)
+ / (np.pi * physics_variables.rminor * physics_variables.rminor)
)
self.plasma_profile.run()
@@ -116,7 +126,7 @@ def physics(self):
# Calculate physics_variables.beta poloidal [-]
physics_variables.betap = physics_functions_module.beta_poloidal()
- # Set PF coil ramp times
+ # Set PF coil ramp times
if pulse_variables.lpulse != 1:
if times_variables.tohsin == 0.0e0:
times_variables.tohs = physics_variables.plascur / 5.0e5
@@ -132,20 +142,20 @@ def physics(self):
times_variables.tqnch = times_variables.tohs
else:
- # times_variables.tohs is set either in INITIAL or INPUT, or by being
- # iterated using limit equation 41.
+ # times_variables.tohs is set either in INITIAL or INPUT, or by being
+ # iterated using limit equation 41.
times_variables.tramp = max(times_variables.tramp, times_variables.tohs)
# tqnch = max(tqnch,tohs)
times_variables.tqnch = times_variables.tohs
- # Reset second times_variables.tburn value (times_variables.tburn0).
- # This is used to ensure that the burn time is used consistently;
- # see convergence loop in fcnvmc1, evaluators.f90
+ # Reset second times_variables.tburn value (times_variables.tburn0).
+ # This is used to ensure that the burn time is used consistently;
+ # see convergence loop in fcnvmc1, evaluators.f90
times_variables.tburn0 = times_variables.tburn
- # Pulse and down times : The reactor is assumed to be 'down'
- # at all times outside of the plasma current flat-top period.
- # The pulse length is the duration of non-zero plasma current
+ # Pulse and down times : The reactor is assumed to be 'down'
+ # at all times outside of the plasma current flat-top period.
+ # The pulse length is the duration of non-zero plasma current
times_variables.tpulse = (
times_variables.tohs
+ times_variables.theat
@@ -159,7 +169,7 @@ def physics(self):
+ times_variables.tdwell
)
- # Total cycle time
+ # Total cycle time
times_variables.tcycle = (
times_variables.tramp
+ times_variables.tohs
@@ -169,8 +179,8 @@ def physics(self):
+ times_variables.tdwell
)
- # Calculate bootstrap current fraction using various models
- current_drive_variables.bscf_iter89 = physics_module.bootstrap_fraction_iter89(
+ # Calculate bootstrap current fraction using various models
+ current_drive_variables.bscf_iter89 = self.bootstrap_fraction_iter89(
physics_variables.aspect,
physics_variables.beta,
physics_variables.btot,
@@ -189,7 +199,7 @@ def physics(self):
)
current_drive_variables.bscf_nevins = (
current_drive_variables.cboot
- * physics_module.bootstrap_fraction_nevins(
+ * self.bootstrap_fraction_nevins(
physics_variables.alphan,
physics_variables.alphat,
betat,
@@ -205,13 +215,13 @@ def physics(self):
)
)
- # Wilson scaling uses thermal poloidal beta, not total
+ # Wilson scaling uses thermal poloidal beta, not total
betpth = (
physics_variables.beta - physics_variables.betaft - physics_variables.betanb
) * (physics_variables.btot / physics_variables.bp) ** 2
current_drive_variables.bscf_wilson = (
current_drive_variables.cboot
- * physics_module.bootstrap_fraction_wilson(
+ * self.bootstrap_fraction_wilson(
physics_variables.alphaj,
physics_variables.alphap,
physics_variables.alphat,
@@ -224,22 +234,22 @@ def physics(self):
)
# Hender scaling for diamagnetic current at tight physics_variables.aspect ratio
- current_drive_variables.diacf_hender = (
- physics_module.diamagnetic_fraction_hender(physics_variables.beta)
+ current_drive_variables.diacf_hender = self.diamagnetic_fraction_hender(
+ physics_variables.beta
)
# SCENE scaling for diamagnetic current
- current_drive_variables.diacf_scene = physics_module.diamagnetic_fraction_scene(
+ current_drive_variables.diacf_scene = self.diamagnetic_fraction_scene(
physics_variables.beta, physics_variables.q95, physics_variables.q0
)
# Pfirsch-Schlüter scaling for diamagnetic current
- current_drive_variables.pscf_scene = physics_module.ps_fraction_scene(
+ current_drive_variables.pscf_scene = self.ps_fraction_scene(
physics_variables.beta
)
current_drive_variables.bscf_sauter = (
- current_drive_variables.cboot * physics_module.bootstrap_fraction_sauter()
+ current_drive_variables.cboot * self.bootstrap_fraction_sauter()
)
if current_drive_variables.bscfmax < 0.0e0:
@@ -279,11 +289,11 @@ def physics(self):
+ current_drive_variables.psipf
)
- # Plasma driven current fraction (Bootstrap + Diamagnetic
- # + Pfirsch-Schlüter) constrained to be less than
- # or equal to the total fraction of the plasma current
- # produced by non-inductive means (which also includes
- # the current drive proportion)
+ # Plasma driven current fraction (Bootstrap + Diamagnetic
+ # + Pfirsch-Schlüter) constrained to be less than
+ # or equal to the total fraction of the plasma current
+ # produced by non-inductive means (which also includes
+ # the current drive proportion)
physics_module.err243 = 0
if current_drive_variables.plasipf > physics_variables.fvsbrnni:
current_drive_variables.plasipf = min(
@@ -291,14 +301,14 @@ def physics(self):
)
physics_module.err243 = 1
- # Fraction of plasma current produced by inductive means
+ # Fraction of plasma current produced by inductive means
physics_variables.facoh = max(1.0e-10, (1.0e0 - physics_variables.fvsbrnni))
- # Fraction of plasma current produced by auxiliary current drive
+ # Fraction of plasma current produced by auxiliary current drive
physics_variables.faccd = (
physics_variables.fvsbrnni - current_drive_variables.plasipf
)
- # Auxiliary current drive power calculations
+ # Auxiliary current drive power calculations
if current_drive_variables.irfcd != 0:
self.current_drive.cudriv(False)
@@ -315,8 +325,8 @@ def physics(self):
physics_variables.pdhe3 = physics_module.pdhe3pv * physics_variables.vol
physics_variables.pdd = physics_module.pddpv * physics_variables.vol
- # Calculate neutral beam slowing down effects
- # If ignited, then ignore beam fusion effects
+ # Calculate neutral beam slowing down effects
+ # If ignited, then ignore beam fusion effects
if (current_drive_variables.cnbeam != 0.0e0) and (
physics_variables.ignite == 0
@@ -390,8 +400,8 @@ def physics(self):
physics_variables.palppv,
)
- # Nominal mean neutron wall load on entire first wall area including divertor and beam holes
- # Note that 'fwarea' excludes these, so they have been added back in.
+ # Nominal mean neutron wall load on entire first wall area including divertor and beam holes
+ # Note that 'fwarea' excludes these, so they have been added back in.
if physics_variables.iwalld == 1:
physics_variables.wallmw = (
physics_variables.ffwal
@@ -414,9 +424,9 @@ def physics(self):
/ build_variables.fwarea
)
- # Calculate ion/electron equilibration power
+ # Calculate ion/electron equilibration power
- physics_variables.piepv = physics_module.rether(
+ physics_variables.piepv = self.rether(
physics_variables.alphan,
physics_variables.alphat,
physics_variables.dene,
@@ -426,7 +436,7 @@ def physics(self):
physics_variables.zeffai,
)
- # Calculate radiation power
+ # Calculate radiation power
radpwrdata = physics_funcs.radpwr(self.plasma_profile)
physics_variables.pbrempv = radpwrdata.pbrempv
@@ -444,13 +454,13 @@ def physics(self):
)
physics_variables.pradmw = physics_variables.pradpv * physics_variables.vol
- # Calculate ohmic power
+ # Calculate ohmic power
(
physics_variables.pohmpv,
physics_variables.pohmmw,
physics_variables.rpfac,
physics_variables.rplas,
- ) = physics_module.pohm(
+ ) = self.pohm(
physics_variables.facoh,
physics_variables.kappa95,
physics_variables.plascur,
@@ -461,7 +471,7 @@ def physics(self):
physics_variables.zeff,
)
- # Calculate L- to H-mode power threshold for different scalings
+ # Calculate L- to H-mode power threshold for different scalings
physics_variables.pthrmw = physics_functions_module.pthresh(
physics_variables.dene,
@@ -474,15 +484,15 @@ def physics(self):
physics_variables.aspect,
)
- # Enforced L-H power threshold value (if constraint 15 is turned on)
+ # Enforced L-H power threshold value (if constraint 15 is turned on)
physics_variables.plhthresh = physics_variables.pthrmw[
physics_variables.ilhthresh - 1
]
- # Power transported to the divertor by charged particles,
- # i.e. excludes neutrons and radiation, and also NBI orbit loss power,
- # which is assumed to be absorbed by the first wall
+ # Power transported to the divertor by charged particles,
+ # i.e. excludes neutrons and radiation, and also NBI orbit loss power,
+ # which is assumed to be absorbed by the first wall
if physics_variables.ignite == 0:
pinj = current_drive_variables.pinjmw
else:
@@ -496,8 +506,8 @@ def physics(self):
- physics_variables.pradmw
)
- # The following line is unphysical, but prevents -ve sqrt argument
- # Should be obsolete if constraint eqn 17 is turned on
+ # The following line is unphysical, but prevents -ve sqrt argument
+ # Should be obsolete if constraint eqn 17 is turned on
physics_variables.pdivt = max(0.001e0, physics_variables.pdivt)
# if double null configuration share the power
@@ -515,13 +525,13 @@ def physics(self):
# Resistive diffusion time = current penetration time ~ mu0.a^2/resistivity
physics_variables.res_time = physics_functions_module.res_diff_time()
- # Power transported to the first wall by escaped alpha particles
+ # Power transported to the first wall by escaped alpha particles
physics_variables.palpfwmw = physics_variables.palpmw * (
1.0e0 - physics_variables.falpha
)
- # Density limit
- physics_variables.dlimit, physics_variables.dnelimt = physics_module.culdlm(
+ # Density limit
+ physics_variables.dlimit, physics_variables.dnelimt = self.culdlm(
physics_variables.bt,
physics_variables.idensl,
physics_variables.pdivt,
@@ -535,8 +545,8 @@ def physics(self):
physics_variables.zeff,
)
- # Calculate transport losses and energy confinement time using the
- # chosen scaling law
+ # Calculate transport losses and energy confinement time using the
+ # chosen scaling law
(
physics_variables.kappaa,
physics_variables.ptrepv,
@@ -545,7 +555,7 @@ def physics(self):
physics_variables.taueff,
physics_variables.tauei,
physics_variables.powerht,
- ) = physics_module.pcond(
+ ) = self.pcond(
physics_variables.afuel,
physics_variables.palpmw,
physics_variables.aspect,
@@ -578,7 +588,7 @@ def physics(self):
physics_variables.ptremw = physics_variables.ptrepv * physics_variables.vol
physics_variables.ptrimw = physics_variables.ptripv * physics_variables.vol
- # Total transport power from scaling law (MW)
+ # Total transport power from scaling law (MW)
# pscalingmw = physics_variables.ptremw + physics_variables.ptrimw #KE - why is this commented?
# Calculate Volt-second requirements
@@ -589,7 +599,7 @@ def physics(self):
physics_variables.vsind,
physics_variables.vsres,
physics_variables.vsstt,
- ) = physics_module.vscalc(
+ ) = self.vscalc(
physics_variables.csawth,
physics_variables.eps,
physics_variables.facoh,
@@ -603,7 +613,7 @@ def physics(self):
physics_variables.rli,
)
- # Calculate auxiliary physics related information
+ # Calculate auxiliary physics related information
sbar = 1.0e0
(
physics_variables.burnup,
@@ -613,7 +623,7 @@ def physics(self):
physics_variables.qfuel,
physics_variables.rndfuel,
physics_variables.taup,
- ) = physics_module.phyaux(
+ ) = self.phyaux(
physics_variables.aspect,
physics_variables.dene,
physics_variables.deni,
@@ -628,15 +638,15 @@ def physics(self):
# ptremw = physics_variables.ptrepv*physics_variables.vol
# ptrimw = physics_variables.ptripv*physics_variables.vol
- # Total transport power from scaling law (MW)
+ # Total transport power from scaling law (MW)
physics_variables.pscalingmw = (
physics_variables.ptremw + physics_variables.ptrimw
)
- # Calculate physics_variables.beta limit
+ # Calculate physics_variables.beta limit
if physics_variables.iprofile == 0:
if physics_variables.gtscale == 1:
- # Original scaling law
+ # Original scaling law
physics_variables.dnbeta = 2.7e0 * (
1.0e0 + 5.0e0 * physics_variables.eps**3.5e0
)
@@ -652,11 +662,11 @@ def physics(self):
)
else:
- # Relation between physics_variables.beta limit and plasma internal inductance
- # Hartmann and Zohm
+ # Relation between physics_variables.beta limit and plasma internal inductance
+ # Hartmann and Zohm
physics_variables.dnbeta = 4.0e0 * physics_variables.rli
- physics_variables.betalim = physics_module.culblm(
+ physics_variables.betalim = self.culblm(
physics_variables.bt,
physics_variables.dnbeta,
physics_variables.plascur,
@@ -664,8 +674,8 @@ def physics(self):
)
# MDK
- # Nominal mean photon wall load on entire first wall area including divertor and beam holes
- # Note that 'fwarea' excludes these, so they have been added back in.
+ # Nominal mean photon wall load on entire first wall area including divertor and beam holes
+ # Note that 'fwarea' excludes these, so they have been added back in.
if physics_variables.iwalld == 1:
physics_variables.photon_wall = (
physics_variables.ffwal
@@ -725,9 +735,7 @@ def physics(self):
2.0e0
/ (
1.0e0
- + numpy.exp(
- -((physics_module.drsep / physics_module.lambdaio) ** 2)
- )
+ + np.exp(-((physics_module.drsep / physics_module.lambdaio) ** 2))
)
)
)
@@ -816,3 +824,5151 @@ def physics(self):
f" 'fzactual, frac, reinke_variables.impvardiv = {reinke_variables.fzactual}, {impurity_radiation_module.impurity_arr_frac(reinke_variables.impvardiv)}, {reinke_variables.impvardiv}"
),
)
+
+ def culdlm(
+ self, bt, idensl, pdivt, plascur, prn1, qcyl, q95, rmajor, rminor, sarea, zeff
+ ):
+ """Density limit calculation
+ author: P J Knight, CCFE, Culham Science Centre
+ bt : input real : toroidal field on axis (T)
+ idensl : input/output integer : switch denoting which formula to enforce
+ pdivt : input real : power flowing to the edge plasma via
+ charged particles (MW)
+ plascur : input real : plasma current (A)
+ prn1 : input real : edge density / average plasma density
+ qcyl : input real : equivalent cylindrical safety factor (qstar)
+ q95 : input real : safety factor at 95% surface
+ rmajor : input real : plasma major radius (m)
+ rminor : input real : plasma minor radius (m)
+ sarea : input real : plasma surface area (m**2)
+ zeff : input real : plasma effective charge
+ dlimit(7): output real array : average plasma density limit using
+ seven different models (m**-3)
+ dnelimt : output real : enforced average plasma density limit (m**-3)
+ This routine calculates several different formulae for the
+ density limit, and enforces the one chosen by the user.
+ AEA FUS 172: Physics Assessment for the European Reactor Study
+ AEA FUS 251: A User's Guide to the PROCESS Systems Code
+ """
+ if idensl < 1 or idensl > 7:
+ error_handling.idiags[0] = idensl
+ error_handling.report_error(79)
+
+ dlimit = np.empty((7,))
+
+ # Power per unit area crossing the plasma edge
+ # (excludes radiation and neutrons)
+
+ qperp = pdivt / sarea
+
+ # Old ASDEX density limit formula
+ # This applies to the density at the plasma edge, so must be scaled
+ # to give the density limit applying to the average plasma density.
+
+ dlim = 1.54e20 * qperp**0.43 * bt**0.31 / (q95 * rmajor) ** 0.45
+ dlimit[0] = dlim / prn1
+
+ # Borrass density limit model for ITER (I)
+ # This applies to the density at the plasma edge, so must be scaled
+ # to give the density limit applying to the average plasma density.
+ # Borrass et al, ITER-TN-PH-9-6 (1989)
+
+ dlim = 1.8e20 * qperp**0.53 * bt**0.31 / (q95 * rmajor) ** 0.22
+ dlimit[1] = dlim / prn1
+
+ # Borrass density limit model for ITER (II)
+ # This applies to the density at the plasma edge, so must be scaled
+ # to give the density limit applying to the average plasma density.
+ # This formula is (almost) identical to that in the original routine
+ # denlim (now deleted).
+
+ dlim = 0.5e20 * qperp**0.57 * bt**0.31 / (q95 * rmajor) ** 0.09
+ dlimit[2] = dlim / prn1
+
+ # JET edge radiation density limit model
+ # This applies to the density at the plasma edge, so must be scaled
+ # to give the density limit applying to the average plasma density.
+ # qcyl=qstar here, but literature is not clear.
+
+ denom = (zeff - 1.0) * (1.0 - 4.0 / (3.0 * qcyl))
+ if denom <= 0.0:
+ if idensl == 4:
+ error_handling.fdiags[0] = denom
+ error_handling.fdiags[1] = qcyl
+ error_handling.report_error(80)
+ idensl = 5
+
+ dlimit[3] = 0.0
+ else:
+ dlim = 1.0e20 * np.sqrt(pdivt / denom)
+ dlimit[3] = dlim / prn1
+
+ # JET simplified density limit model
+ # This applies to the density at the plasma edge, so must be scaled
+ # to give the density limit applying to the average plasma density.
+
+ dlim = 0.237e20 * bt * np.sqrt(pdivt) / rmajor
+ dlimit[4] = dlim / prn1
+
+ # Hugill-Murakami M.q limit
+ # qcyl=qstar here, which is okay according to the literature
+
+ dlimit[5] = 3.0e20 * bt / (rmajor * qcyl)
+
+ # Greenwald limit
+
+ dlimit[6] = 1.0e14 * plascur / (np.pi * rminor * rminor)
+
+ # Enforce the chosen density limit
+
+ return dlimit, dlimit[idensl - 1]
+
+ def plasma_composition(self):
+ """Calculates various plasma component fractional makeups
+ author: P J Knight, CCFE, Culham Science Centre
+
+ This subroutine determines the various plasma component
+ fractional makeups. It is the replacement for the original
+ It is the replacement for the original routine betcom,
+ and is used in conjunction with the new impurity radiation model
+ """
+ # Alpha ash portion
+ physics_variables.dnalp = physics_variables.dene * physics_variables.ralpne
+
+ # Protons
+ # This calculation will be wrong on the first call as the particle
+ # production rates are evaluated later in the calling sequence
+ # Issue #557 Allow protium impurity to be specified: 'protium'
+ # This will override the calculated value which is a minimum.
+ if physics_variables.alpharate < 1.0e-6: # not calculated yet...
+ physics_variables.dnprot = max(
+ physics_variables.protium * physics_variables.dene,
+ physics_variables.dnalp * (physics_variables.fhe3 + 1.0e-3),
+ ) # rough estimate
+ else:
+ physics_variables.dnprot = max(
+ physics_variables.protium * physics_variables.dene,
+ physics_variables.dnalp
+ * physics_variables.protonrate
+ / physics_variables.alpharate,
+ )
+
+ # Beam hot ion component
+ # If ignited, prevent beam fusion effects
+ if physics_variables.ignite == 0:
+ physics_variables.dnbeam = physics_variables.dene * physics_variables.rnbeam
+ else:
+ physics_variables.dnbeam = 0.0
+
+ # Sum of Zi.ni for all impurity ions (those with charge > helium)
+ znimp = 0.0
+ for imp in range(impurity_radiation_module.nimp):
+ if impurity_radiation_module.impurity_arr_z[imp] > 2:
+ znimp += impurity_radiation_module.zav_of_te(
+ imp + 1, physics_variables.te
+ ) * (
+ impurity_radiation_module.impurity_arr_frac[imp]
+ * physics_variables.dene
+ )
+
+ # Fuel portion - conserve charge neutrality
+ # znfuel is the sum of Zi.ni for the three fuel ions
+ znfuel = (
+ physics_variables.dene
+ - 2.0 * physics_variables.dnalp
+ - physics_variables.dnprot
+ - physics_variables.dnbeam
+ - znimp
+ )
+
+ # Fuel ion density, deni
+ # For D-T-He3 mix, deni = nD + nT + nHe3, while znfuel = nD + nT + 2*nHe3
+ # So deni = znfuel - nHe3 = znfuel - fhe3*deni
+ physics_variables.deni = znfuel / (1.0 + physics_variables.fhe3)
+
+ # Set hydrogen and helium impurity fractions for
+ # radiation calculations
+ impurity_radiation_module.impurity_arr_frac[
+ impurity_radiation_module.element2index("H_") - 1
+ ] = (
+ physics_variables.dnprot
+ + (physics_variables.fdeut + physics_variables.ftrit)
+ * physics_variables.deni
+ + physics_variables.dnbeam
+ ) / physics_variables.dene
+
+ impurity_radiation_module.impurity_arr_frac[
+ impurity_radiation_module.element2index("He") - 1
+ ] = (
+ physics_variables.fhe3 * physics_variables.deni / physics_variables.dene
+ + physics_variables.ralpne
+ )
+
+ # Total impurity density
+ physics_variables.dnz = 0.0
+ for imp in range(impurity_radiation_module.nimp):
+ if impurity_radiation_module.impurity_arr_z[imp] > 2:
+ physics_variables.dnz += (
+ impurity_radiation_module.impurity_arr_frac[imp]
+ * physics_variables.dene
+ )
+
+ # Total ion density
+ physics_variables.dnitot = (
+ physics_variables.deni
+ + physics_variables.dnalp
+ + physics_variables.dnprot
+ + physics_variables.dnbeam
+ + physics_variables.dnz
+ )
+
+ # Set some (obsolescent) impurity fraction variables
+ # for the benefit of other routines
+ physics_variables.rncne = impurity_radiation_module.impurity_arr_frac[
+ impurity_radiation_module.element2index("C_")
+ ]
+ physics_variables.rnone = impurity_radiation_module.impurity_arr_frac[
+ impurity_radiation_module.element2index("O_")
+ ]
+ physics_variables.rnfene = (
+ impurity_radiation_module.impurity_arr_frac[
+ impurity_radiation_module.element2index("Fe")
+ ]
+ + impurity_radiation_module.impurity_arr_frac[
+ impurity_radiation_module.element2index("Ar")
+ ]
+ )
+
+ # Effective charge
+ # Calculation should be sum(ni.Zi^2) / sum(ni.Zi),
+ # but ne = sum(ni.Zi) through quasineutrality
+ physics_variables.zeff = 0.0
+ for imp in range(impurity_radiation_module.nimp):
+ physics_variables.zeff += (
+ impurity_radiation_module.impurity_arr_frac[imp]
+ * impurity_radiation_module.zav_of_te(imp + 1, physics_variables.te)
+ ** 2
+ )
+
+ # Define coulomb logarithm
+ # (collisions: ion-electron, electron-electron)
+ physics_variables.dlamee = (
+ 31.0
+ - (np.log(physics_variables.dene) / 2.0)
+ + np.log(physics_variables.te * 1000.0)
+ )
+ physics_variables.dlamie = (
+ 31.3
+ - (np.log(physics_variables.dene) / 2.0)
+ + np.log(physics_variables.te * 1000.0)
+ )
+
+ # Fraction of alpha energy to ions and electrons
+ # From Max Fenstermacher
+ # (used with electron and ion power balance equations only)
+ # No consideration of pchargepv here...
+
+ # pcoef now calculated in plasma_profiles, after the very first
+ # call of plasma_composition; use old parabolic profile estimate
+ # in this case
+ if physics_module.first_call == 1:
+ pc = (
+ (1.0 + physics_variables.alphan)
+ * (1.0 + physics_variables.alphat)
+ / (1.0 + physics_variables.alphan + physics_variables.alphat)
+ )
+ physics_module.first_call = 0
+ else:
+ pc = physics_variables.pcoef
+
+ physics_variables.falpe = 0.88155 * np.exp(-physics_variables.te * pc / 67.4036)
+ physics_variables.falpi = 1.0 - physics_variables.falpe
+
+ # Average atomic masses
+ physics_variables.afuel = (
+ 2.0 * physics_variables.fdeut
+ + 3.0 * physics_variables.ftrit
+ + 3.0 * physics_variables.fhe3
+ )
+ physics_variables.abeam = (
+ 2.0 * (1.0 - current_drive_variables.ftritbm)
+ + 3.0 * current_drive_variables.ftritbm
+ )
+
+ # Density weighted mass
+ physics_variables.aion = (
+ physics_variables.afuel * physics_variables.deni
+ + 4.0 * physics_variables.dnalp
+ + physics_variables.dnprot
+ + physics_variables.abeam * physics_variables.dnbeam
+ )
+ for imp in range(impurity_radiation_module.nimp):
+ if impurity_radiation_module.impurity_arr_z[imp] > 2:
+ physics_variables.aion += (
+ physics_variables.dene
+ * impurity_radiation_module.impurity_arr_frac[imp]
+ * impurity_radiation_module.impurity_arr_amass[imp]
+ )
+
+ physics_variables.aion = physics_variables.aion / physics_variables.dnitot
+
+ # Mass weighted plasma effective charge
+ physics_variables.zeffai = (
+ physics_variables.fdeut * physics_variables.deni / 2.0
+ + physics_variables.ftrit * physics_variables.deni / 3.0
+ + 4.0 * physics_variables.fhe3 * physics_variables.deni / 3.0
+ + physics_variables.dnalp
+ + physics_variables.dnprot
+ + (1.0 - current_drive_variables.ftritbm) * physics_variables.dnbeam / 2.0
+ + current_drive_variables.ftritbm * physics_variables.dnbeam / 3.0
+ ) / physics_variables.dene
+ for imp in range(impurity_radiation_module.nimp):
+ if impurity_radiation_module.impurity_arr_z[imp] > 2:
+ physics_variables.zeffai += (
+ impurity_radiation_module.impurity_arr_frac[imp]
+ * impurity_radiation_module.zav_of_te(imp + 1, physics_variables.te)
+ ** 2
+ / impurity_radiation_module.impurity_arr_amass[imp]
+ )
+
+ def phyaux(
+ self,
+ aspect,
+ dene,
+ deni,
+ fusionrate,
+ alpharate,
+ plascur,
+ sbar,
+ dnalp,
+ taueff,
+ vol,
+ ):
+ """Auxiliary physics quantities
+ author: P J Knight, CCFE, Culham Science Centre
+ aspect : input real : plasma aspect ratio
+ dene : input real : electron density (/m3)
+ deni : input real : fuel ion density (/m3)
+ dnalp : input real : alpha ash density (/m3)
+ fusionrate : input real : fusion reaction rate (/m3/s)
+ alpharate : input real : alpha particle production rate (/m3/s)
+ plascur: input real : plasma current (A)
+ sbar : input real : exponent for aspect ratio (normally 1)
+ taueff : input real : global energy confinement time (s)
+ vol : input real : plasma volume (m3)
+ burnup : output real : fractional plasma burnup
+ dntau : output real : plasma average n-tau (s/m3)
+ figmer : output real : physics figure of merit
+ fusrat : output real : number of fusion reactions per second
+ qfuel : output real : fuelling rate for D-T (nucleus-pairs/sec)
+ rndfuel: output real : fuel burnup rate (reactions/s)
+ taup : output real : (alpha) particle confinement time (s)
+ This subroutine calculates extra physics related items
+ needed by other parts of the code
+ AEA FUS 251: A User's Guide to the PROCESS Systems Code
+ """
+
+ figmer = 1e-6 * plascur * aspect**sbar
+
+ dntau = taueff * dene
+
+ # Fusion reactions per second
+
+ fusrat = fusionrate * vol
+
+ # Alpha particle confinement time (s)
+ # Number of alphas / alpha production rate
+
+ if alpharate != 0.0:
+ taup = dnalp / alpharate
+ else: # only likely if DD is only active fusion reaction
+ taup = 0.0
+
+ # Fractional burnup
+
+ # (Consider detailed model in: G. L. Jackson, V. S. Chan, R. D. Stambaugh,
+ # Fusion Science and Technology, vol.64, no.1, July 2013, pp.8-12)
+
+ # The ratio of ash to fuel particle confinement times is given by
+ # tauratio
+ # Possible logic...
+ # burnup = fuel ion-pairs burned/m3 / initial fuel ion-pairs/m3;
+ # fuel ion-pairs burned/m3 = alpha particles/m3 (for both D-T and D-He3 reactions)
+ # initial fuel ion-pairs/m3 = burnt fuel ion-pairs/m3 + unburnt fuel-ion pairs/m3
+ # Remember that unburnt fuel-ion pairs/m3 = 0.5 * unburnt fuel-ions/m3
+ if physics_variables.burnup_in <= 1.0e-9:
+ burnup = dnalp / (dnalp + 0.5 * deni) / physics_variables.tauratio
+ else:
+ burnup = physics_variables.burnup_in
+ # Fuel burnup rate (reactions/second) (previously Amps)
+
+ rndfuel = fusrat
+
+ # Required fuelling rate (fuel ion pairs/second) (previously Amps)
+
+ qfuel = rndfuel / burnup
+
+ return burnup, dntau, figmer, fusrat, qfuel, rndfuel, taup
+
+ def rether(self, alphan, alphat, dene, dlamie, te, ti, zeffai):
+ """Routine to find the equilibration power between the
+ ions and electrons
+ author: P J Knight, CCFE, Culham Science Centre
+ alphan : input real : density profile index
+ alphat : input real : temperature profile index
+ dene : input real : electron density (/m3)
+ dlamie : input real : ion-electron coulomb logarithm
+ te : input real : electron temperature (keV)
+ ti : input real : ion temperature (keV)
+ zeffai : input real : mass weighted plasma effective charge
+ piepv : output real : ion/electron equilibration power (MW/m3)
+ This routine calculates the equilibration power between the
+ ions and electrons.
+ Unknown origin
+ """
+ profie = (1.0 + alphan) ** 2 / (
+ (2.0 * alphan - 0.5 * alphat + 1.0) * np.sqrt(1.0 + alphat)
+ )
+ conie = 2.42165e-41 * dlamie * dene**2 * zeffai * profie
+
+ return conie * (ti - te) / (te**1.5)
+
+ def pohm(self, facoh, kappa95, plascur, rmajor, rminor, ten, vol, zeff):
+ # Density weighted electron temperature in 10 keV units
+
+ t10 = ten / 10.0
+
+ # Plasma resistance, from loop voltage calculation in IPDG89
+
+ rplas = (
+ physics_variables.plasma_res_factor
+ * 2.15e-9
+ * zeff
+ * rmajor
+ / (kappa95 * rminor**2 * t10**1.5)
+ )
+
+ # Neo-classical resistivity enhancement factor
+ # Taken from N. A. Uckan et al, Fusion Technology 13 (1988) p.411.
+ # The expression is valid for aspect ratios in the range 2.5--4.
+
+ rpfac = 4.3 - 0.6 * rmajor / rminor
+ rplas = rplas * rpfac
+
+ # Check to see if plasma resistance is negative
+ # (possible if aspect ratio is too high)
+
+ if rplas <= 0.0:
+ error_handling.fdiags[0] = rplas
+ error_handling.fdiags[1] = physics_variables.aspect
+ error_handling.report_error(83)
+
+ # Ohmic heating power per unit volume
+ # Corrected from: pohmpv = (facoh*plascur)**2 * ...
+
+ pohmpv = facoh * plascur**2 * rplas * 1.0e-6 / vol
+
+ # Total ohmic heating power
+
+ pohmmw = pohmpv * vol
+
+ return pohmpv, pohmmw, rpfac, rplas
+
+ def vscalc(
+ self,
+ csawth,
+ eps,
+ facoh,
+ gamma,
+ kappa,
+ rmajor,
+ rplas,
+ plascur,
+ theat,
+ tburn,
+ rli,
+ ):
+ """Volt-second requirements
+ author: P J Knight, CCFE, Culham Science Centre
+ csawth : input real : coefficient for sawteeth effects
+ eps : input real : inverse aspect ratio
+ facoh : input real : fraction of plasma current produced inductively
+ gamma : input real : Ejima coeff for resistive start-up V-s component
+ kappa : input real : plasma elongation
+ plascur: input real : plasma current (A)
+ rli : input real : plasma normalised inductivity
+ rmajor : input real : plasma major radius (m)
+ rplas : input real : plasma resistance (ohm)
+ theat : input real : heating time (s)
+ tburn : input real : burn time (s)
+ phiint : output real : internal plasma volt-seconds (Wb)
+ rlp : output real : plasma inductance (H)
+ vsbrn : output real : volt-seconds needed during flat-top (heat+burn) (Wb)
+ vsind : output real : internal and external plasma inductance V-s (Wb)
+ vsres : output real : resistive losses in start-up volt-seconds (Wb)
+ vsstt : output real : total volt-seconds needed (Wb)
+ This subroutine calculates the volt-second requirements and some
+ other related items.
+ AEA FUS 251: A User's Guide to the PROCESS Systems Code
+ """
+ # Internal inductance
+
+ rlpint = constants.rmu0 * rmajor * rli / 2.0
+ phiint = rlpint * plascur
+
+ # Start-up resistive component
+ # Uses ITER formula without the 10 V-s add-on
+
+ vsres = gamma * constants.rmu0 * plascur * rmajor
+
+ # Hirshman, Neilson: Physics of Fluids, 29 (1986) p790
+ # fit for external inductance
+
+ aeps = (1.0 + 1.81 * np.sqrt(eps) + 2.05 * eps) * np.log(8.0 / eps) - (
+ 2.0 + 9.25 * np.sqrt(eps) - 1.21 * eps
+ )
+ beps = (
+ 0.73
+ * np.sqrt(eps)
+ * (1.0 + 2.0 * eps**4 - 6.0 * eps**5 + 3.7 * eps**6)
+ )
+ rlpext = (
+ rmajor * constants.rmu0 * aeps * (1.0 - eps) / (1.0 - eps + beps * kappa)
+ )
+
+ rlp = rlpext + rlpint
+
+ # Inductive V-s component
+
+ vsind = rlp * plascur
+ vsstt = vsres + vsind
+
+ # Loop voltage during flat-top
+ # Include enhancement factor in flattop V-s requirement
+ # to account for MHD sawtooth effects.
+
+ vburn = plascur * rplas * facoh * csawth
+
+ # N.B. tburn on first iteration will not be correct
+ # if the pulsed reactor option is used, but the value
+ # will be correct on subsequent calls.
+
+ vsbrn = vburn * (theat + tburn)
+ vsstt = vsstt + vsbrn
+
+ return phiint, rlp, vsbrn, vsind, vsres, vsstt
+
+ def culblm(self, bt, dnbeta, plascur, rminor):
+ """Beta scaling limit
+ author: P J Knight, CCFE, Culham Science Centre
+ bt : input real : toroidal B-field on plasma axis (T)
+ dnbeta : input real : Troyon-like g coefficient
+ plascur : input real : plasma current (A)
+ rminor : input real : plasma minor axis (m)
+ betalim : output real : beta limit as defined below
+ This subroutine calculates the beta limit, using
+ the algorithm documented in AEA FUS 172.
+ The limit applies to beta defined with respect to the total B-field.
+ Switch iculbl determines which components of beta to include.
+
+ If iculbl = 0, then the limit is applied to the total beta
+ If iculbl = 1, then the limit is applied to the thermal beta only
+ If iculbl = 2, then the limit is applied to the thermal + neutral beam beta components
+ If iculbl = 3, then the limit is applied to the toroidal beta
+
+ The default value for the g coefficient is dnbeta = 3.5
+ AEA FUS 172: Physics Assessment for the European Reactor Study
+ AEA FUS 251: A User's Guide to the PROCESS Systems Code
+ """
+
+ return 0.01 * dnbeta * (plascur / 1.0e6) / (rminor * bt)
+
+ def culcur(
+ self,
+ alphaj,
+ alphap,
+ bt,
+ eps,
+ icurr,
+ iprofile,
+ kappa,
+ kappa95,
+ p0,
+ pperim,
+ q0,
+ qpsi,
+ rli,
+ rmajor,
+ rminor,
+ sf,
+ triang,
+ triang95,
+ ):
+ """Routine to calculate the plasma current
+ author: P J Knight, CCFE, Culham Science Centre
+ alphaj : input/output real : current profile index
+ alphap : input real : pressure profile index
+ bt : input real : toroidal field on axis (T)
+ eps : input real : inverse aspect ratio
+ icurr : input integer : current scaling model to use
+ 1 = Peng analytic fit
+ 2 = Peng divertor scaling (TART)
+ 3 = simple ITER scaling
+ 4 = revised ITER scaling
+ 5 = Todd empirical scaling I
+ 6 = Todd empirical scaling II
+ 7 = Connor-Hastie model
+ iprofile : input integer : switch for current profile consistency
+ 0 = use input alphaj, rli
+ 1 = make these consistent with q, q0
+ kappa : input real : plasma elongation
+ kappa95 : input real : plasma elongation at 95% surface
+ p0 : input real : central plasma pressure (Pa)
+ pperim : input real : plasma perimeter length (m)
+ q0 : input real : plasma safety factor on axis
+ qpsi : input real : plasma edge safety factor (= q-bar for icurr=2)
+ rli : input/output real : plasma normalised internal inductance
+ rmajor : input real : major radius (m)
+ rminor : input real : minor radius (m)
+ sf : input real : shape factor for icurr=1 (=A/pi in documentation)
+ triang : input real : plasma triangularity
+ triang95 : input real : plasma triangularity at 95% surface
+ bp : output real : poloidal field (T)
+ qstar : output real : equivalent cylindrical safety factor (shaped)
+ plascur : output real : plasma current (A)
+ This routine performs the calculation of the
+ plasma current, with a choice of formula for the edge
+ safety factor. It will also make the current profile parameters
+ consistent with the q-profile if required.
+ AEA FUS 251: A User's Guide to the PROCESS Systems Code
+ J D Galambos, STAR Code : Spherical Tokamak Analysis and Reactor Code,
+ unpublished internal Oak Ridge document
+ Y.-K. M. Peng, J. Galambos and P.C. Shipe, 1992,
+ Fusion Technology, 21, 1729
+ ITER Physics Design Guidelines: 1989 [IPDG89], N. A. Uckan et al,
+ ITER Documentation Series No.10, IAEA/ITER/DS/10, IAEA, Vienna, 1990
+ M. Kovari et al, 2014, "PROCESS": A systems code for fusion power plants -
+ Part 1: Physics https://www.sciencedirect.com/science/article/pii/S0920379614005961
+ H. Zohm et al, 2013, On the Physics Guidelines for a Tokamak DEMO
+ https://iopscience.iop.org/article/10.1088/0029-5515/53/7/073019
+ T. Hartmann, 2013, Development of a modular systems code to analyse the
+ implications of physics assumptions on the design of a demonstration fusion power plant
+ https://inis.iaea.org/search/search.aspx?orig_q=RN:45031642
+ Sauter, Geometric formulas for systems codes..., FED 2016
+ """
+ # Aspect ratio
+
+ asp = 1.0 / eps
+
+ # Calculate the function Fq that scales the edge q from the
+ # circular cross-section cylindrical case
+
+ # First check for negative triangularity using unsuitable current scaling
+
+ if icurr != 8 and triang < 0.0:
+ raise ValueError(
+ f"Triangularity is negative without icurr = 8: {triang=}, {icurr=}"
+ )
+
+ if icurr == 1: # Peng analytical fit
+ fq = (1.22 - 0.68 * eps) / ((1.0 - eps * eps) ** 2) * sf**2
+ elif icurr == 2: # Peng scaling for double null divertor; TARTs [STAR Code]
+ curhat = (
+ 1.0e6 * physics_module.plasc(qpsi, asp, rminor, bt, kappa, triang) / bt
+ )
+ elif icurr == 3: # Simple ITER scaling (simply the cylindrical case)
+ fq = 1.0
+ elif icurr == 4: # ITER formula (IPDG89)
+ fq = (
+ 0.5
+ * (1.17 - 0.65 * eps)
+ / ((1.0 - eps * eps) ** 2)
+ * (
+ 1.0
+ + kappa95**2 * (1.0 + 2.0 * triang95**2 - 1.2 * triang95**3)
+ )
+ )
+ elif icurr in [5, 6]: # Todd empirical scalings
+ fq = (
+ (1.0 + 2.0 * eps * eps)
+ * 0.5
+ * (1.0 + kappa95**2)
+ * (
+ 1.24
+ - 0.54 * kappa95
+ + 0.3 * (kappa95**2 + triang95**2)
+ + 0.125 * triang95
+ )
+ )
+
+ fq *= 1 if icurr == 7 else (1.0 + (abs(kappa95 - 1.2)) ** 3)
+ elif icurr == 7: # Connor-Hastie asymptotically-correct expression
+ # N.B. If iprofile=1, alphaj will be wrong during the first call (only)
+ fq = physics_module.conhas(alphaj, alphap, bt, triang95, eps, kappa95, p0)
+ elif (
+ icurr == 8
+ ): # Sauter scaling allowing negative triangularity [FED May 2016]
+ # Assumes zero squareness, note takes kappa, delta at separatrix not _95
+
+ w07 = 1.0 # zero squareness - can be modified later if required
+
+ fq = (
+ (1.0 + 1.2 * (kappa - 1.0) + 0.56 * (kappa - 1.0) ** 2)
+ * (1.0 + 0.09 * triang + 0.16 * triang**2)
+ * (1.0 + 0.45 * triang * eps)
+ / (1.0 - 0.74 * eps)
+ * (1.0 + 0.55 * (w07 - 1.0))
+ )
+ elif icurr == 9:
+ fq = 0.538 * (1.0 + 2.440 * eps**2.736) * kappa**2.154 * triang**0.060
+ else:
+ raise ValueError(f"Invalid value {icurr=}")
+
+ if icurr == 8:
+ curhat = 4.1e6 * rminor**2 / (rmajor * qpsi) * fq
+ elif icurr != 2:
+ curhat = 5.0e6 * rminor**2 / (rmajor * qpsi) * fq
+ # == 2 case covered above
+
+ qstar = (
+ 5.0e6
+ * rminor**2
+ / (rmajor * curhat)
+ * 0.5
+ * (1.0 + kappa95**2 * (1.0 + 2.0 * triang95**2 - 1.2 * triang95**3))
+ )
+
+ plascur = curhat * bt
+ physics_variables.normalised_total_beta = (
+ 1.0e8 * physics_variables.beta * rminor * bt / plascur
+ )
+ bp = self.bpol(icurr, plascur, qpsi, asp, bt, kappa, triang, pperim)
+
+ # Ensure current profile consistency, if required
+ # This is as described in Hartmann and Zohm only if icurr = 4 as well...
+
+ if iprofile == 1:
+ alphaj = qstar / q0 - 1.0
+ rli = np.log(1.65 + 0.89 * alphaj) # Tokamaks 4th Edition, Wesson, page 116
+
+ return alphaj, rli, bp, qstar, plascur
+
+ def conhas(self, alphaj, alphap, bt, delta95, eps, kappa95, p0):
+ """Routine to calculate the F coefficient used for scaling the
+ plasma current
+ author: P J Knight, CCFE, Culham Science Centre
+ alphaj : input real : current profile index
+ alphap : input real : pressure profile index
+ bt : input real : toroidal field on axis (T)
+ delta95 : input real : plasma triangularity 95%
+ eps : input real : inverse aspect ratio
+ kappa95 : input real : plasma elongation 95%
+ p0 : input real : central plasma pressure (Pa)
+ fq : output real : scaling for edge q from circular
+ cross-section cylindrical case
+ This routine calculates the F coefficient used for scaling the
+ plasma current, using the Connor-Hastie scaling given in
+ AEA FUS 172.
+ AEA FUS 172: Physics Assessment for the European Reactor Study
+ AEA FUS 251: A User's Guide to the PROCESS Systems Code
+ """
+
+ # Exponent in Connor-Hastie current profile - matching total
+ # current gives the following trivial relation
+
+ lamda = alphaj
+
+ # Exponent in Connor-Hastie pressure profile
+
+ nu = alphap
+
+ # Central plasma beta
+
+ beta0 = 2.0 * constants.rmu0 * p0 / (bt**2)
+
+ # Plasma internal inductance
+
+ lamp1 = 1.0 + lamda
+ li = lamp1 / lamda * (lamp1 / lamda * np.log(lamp1) - 1.0)
+
+ # T/r in AEA FUS 172
+
+ kap1 = kappa95 + 1.0
+ tr = kappa95 * delta95 / kap1**2
+
+ # E/r in AEA FUS 172
+
+ er = (kappa95 - 1.0) / kap1
+
+ # T primed in AEA FUS 172
+
+ tprime = 2.0 * tr * lamp1 / (1.0 + 0.5 * lamda)
+
+ # E primed in AEA FUS 172
+
+ eprime = er * lamp1 / (1.0 + lamda / 3.0)
+
+ # Delta primed in AEA FUS 172
+
+ deltap = 0.5 * kap1 * eps * 0.5 * li + beta0 / (
+ 0.5 * kap1 * eps
+ ) * lamp1**2 / (1.0 + nu)
+
+ # Delta/R0 in AEA FUS 172
+
+ deltar = beta0 / 6.0 * (1.0 + 5.0 * lamda / 6.0 + 0.25 * lamda**2) + (
+ 0.5 * kap1 * eps
+ ) ** 2 * 0.125 * (1.0 - (lamda**2) / 3.0)
+
+ # F coefficient
+
+ return (0.5 * kap1) ** 2 * (
+ 1.0
+ + eps**2 * (0.5 * kap1) ** 2
+ + 0.5 * deltap**2
+ + 2.0 * deltar
+ + 0.5 * (eprime**2 + er**2)
+ + 0.5 * (tprime**2 + 4.0 * tr**2)
+ )
+
+ def plasc(self, qbar, aspect, rminor, bt, kappa, delta):
+ """Function to calculate plasma current (Peng scaling)
+ author: J Galambos, FEDC/ORNL
+ author: P J Knight, CCFE, Culham Science Centre
+ aspect : input real : plasma aspect ratio
+ bt : input real : toroidal field on axis (T)
+ delta : input real : plasma triangularity
+ kappa : input real : plasma elongation
+ qbar : input real : edge q-bar
+ rminor : input real : plasma minor radius (m)
+ This function calculates the plasma current in MA,
+ using a scaling from Peng, Galambos and Shipe (1992).
+ It is primarily used for Tight Aspect Ratio Tokamaks and is
+ selected via icurr=2.
+ J D Galambos, STAR Code : Spherical Tokamak Analysis and Reactor Code,
+ unpublished internal Oak Ridge document
+ Y.-K. M. Peng, J. Galambos and P.C. Shipe, 1992,
+ Fusion Technology, 21, 1729
+ """
+
+ eps = 1.0 / aspect
+
+ c1 = kappa**2 / (1.0 + delta) + delta
+ c2 = kappa**2 / (1.0 - delta) - delta
+
+ d1 = (kappa / (1.0 + delta)) ** 2 + 1.0
+ d2 = (kappa / (1.0 - delta)) ** 2 + 1.0
+
+ if aspect < c1:
+ y1 = np.sqrt((c1 * eps - 1.0) / (1.0 + eps)) * (1.0 + delta) / kappa
+ else:
+ y1 = np.sqrt((1.0 - c1 * eps) / (1.0 + eps)) * (1.0 + delta) / kappa
+
+ y2 = np.sqrt((c2 * eps + 1.0) / (1.0 - eps)) * (1.0 - delta) / kappa
+
+ e1 = 2.0 * kappa / (d1 * (1.0 + delta))
+ e2 = 2.0 * kappa / (d2 * (1.0 - delta))
+
+ h2 = (1.0 + (c2 - 1.0) * eps / 2.0) / np.sqrt((1.0 - eps) * (c2 * eps + 1.0))
+ f2 = (d2 * (1.0 - delta) * eps) / ((1.0 - eps) * (c2 * eps + 1.0))
+ g = eps * kappa / (1.0 - eps * delta)
+ ff2 = f2 * (g + 2.0 * h2 * np.arctan(y2))
+
+ if aspect < c1:
+ h1 = (1.0 + (1.0 - c1) * eps / 2.0) / np.sqrt(
+ (1.0 + eps) * (c1 * eps - 1.0)
+ )
+ f1 = (d1 * (1.0 + delta) * eps) / ((1.0 + eps) * (c1 * eps - 1.0))
+ ff1 = f1 * (g - h1 * np.log((1.0 + y1) / (1.0 - y1)))
+ else:
+ h1 = (1.0 + (1.0 - c1) * eps / 2.0) / np.sqrt(
+ (1.0 + eps) * (1.0 - c1 * eps)
+ )
+ f1 = -(d1 * (1.0 + delta) * eps) / ((1.0 + eps) * (c1 * eps - 1.0))
+ ff1 = f1 * (-g + 2.0 * h1 * np.arctan(y1))
+
+ return (
+ rminor
+ * bt
+ / qbar
+ * 5.0
+ * kappa
+ / (2.0 * np.pi**2)
+ * (np.arcsin(e1) / e1 + np.arcsin(e2) / e2)
+ * (ff1 + ff2)
+ )
+
+ def bpol(self, icurr, ip, qbar, aspect, bt, kappa, delta, perim):
+ """Function to calculate poloidal field
+ author: J Galambos, FEDC/ORNL
+ author: P J Knight, CCFE, Culham Science Centre
+ icurr : input integer : current scaling model to use
+ ip : input real : plasma current (A)
+ qbar : input real : edge q-bar
+ aspect : input real : plasma aspect ratio
+ bt : input real : toroidal field on axis (T)
+ kappa : input real : plasma elongation
+ delta : input real : plasma triangularity
+ perim : input real : plasma perimeter (m)
+ This function calculates the poloidal field in Tesla,
+ using a simple calculation using Stoke's Law for conventional
+ tokamaks, or for TARTs, a scaling from Peng, Galambos and
+ Shipe (1992).
+ J D Galambos, STAR Code : Spherical Tokamak Analysis and Reactor Code,
+ unpublished internal Oak Ridge document
+ Y.-K. M. Peng, J. Galambos and P.C. Shipe, 1992,
+ Fusion Technology, 21, 1729
+ """
+ if icurr != 2:
+ return constants.rmu0 * ip / perim
+
+ # Original coding, only suitable for TARTs [STAR Code]
+
+ eps = 1.0 / aspect
+
+ c1 = kappa**2 / (1.0 + delta) + delta
+ c2 = kappa**2 / (1.0 - delta) - delta
+
+ d1 = (kappa / (1.0 + delta)) ** 2 + 1.0
+ d2 = (kappa / (1.0 - delta)) ** 2 + 1.0
+
+ if aspect < c1:
+ y1 = np.sqrt((c1 * eps - 1.0) / (1.0 + eps)) * (1.0 + delta) / kappa
+ else:
+ y1 = np.sqrt((1.0 - c1 * eps) / (1.0 + eps)) * (1.0 + delta) / kappa
+
+ y2 = np.sqrt((c2 * eps + 1.0) / (1.0 - eps)) * (1.0 - delta) / kappa
+
+ h2 = (1.0 + (c2 - 1.0) * eps / 2.0) / np.sqrt((1.0 - eps) * (c2 * eps + 1.0))
+ f2 = (d2 * (1.0 - delta) * eps) / ((1.0 - eps) * (c2 * eps + 1.0))
+ g = eps * kappa / (1.0 - eps * delta)
+ ff2 = f2 * (g + 2.0 * h2 * np.arctan(y2))
+
+ if aspect < c1:
+ h1 = (1.0 + (1.0 - c1) * eps / 2.0) / np.sqrt(
+ (1.0 + eps) * (c1 * eps - 1.0)
+ )
+ f1 = (d1 * (1.0 + delta) * eps) / ((1.0 + eps) * (c1 * eps - 1.0))
+ ff1 = f1 * (g - h1 * np.log((1.0 + y1) / (1.0 - y1)))
+ else:
+ h1 = (1.0 + (1.0 - c1) * eps / 2.0) / np.sqrt(
+ (1.0 + eps) * (1.0 - c1 * eps)
+ )
+ f1 = -(d1 * (1.0 + delta) * eps) / ((1.0 + eps) * (c1 * eps - 1.0))
+ ff1 = f1 * (-g + 2.0 * h1 * np.arctan(y1))
+
+ return bt * (ff1 + ff2) / (2.0 * np.pi * qbar)
+
+ def bootstrap_fraction_iter89(
+ self, aspect, beta, bt, cboot, plascur, q95, q0, rmajor, vol
+ ):
+ """Original ITER calculation of bootstrap-driven fraction
+ of the plasma current.
+ author: P J Knight, CCFE, Culham Science Centre
+ aspect : input real : plasma aspect ratio
+ beta : input real : plasma total beta
+ bt : input real : toroidal field on axis (T)
+ cboot : input real : bootstrap current fraction multiplier
+ plascur : input real : plasma current (A)
+ q95 : input real : safety factor at 95% surface
+ q0 : input real : central safety factor
+ rmajor : input real : plasma major radius (m)
+ vol : input real : plasma volume (m3)
+ This routine performs the original ITER calculation of the
+ plasma current bootstrap fraction.
+ ITER Physics Design Guidelines: 1989 [IPDG89], N. A. Uckan et al,
+ ITER Documentation Series No.10, IAEA/ITER/DS/10, IAEA, Vienna, 1990
+ """
+ xbs = min(10, q95 / q0)
+ cbs = cboot * (1.32 - 0.235 * xbs + 0.0185 * xbs**2)
+ bpbs = (
+ constants.rmu0
+ * plascur
+ / (2 * np.pi * np.sqrt(vol / (2 * np.pi**2 * rmajor)))
+ )
+ betapbs = beta * bt**2 / bpbs**2
+
+ if betapbs <= 0.0: # only possible if beta <= 0.0
+ return 0.0
+ return cbs * (betapbs / np.sqrt(aspect)) ** 1.3
+
+ def bootstrap_fraction_nevins(
+ self,
+ alphan,
+ alphat,
+ betat,
+ bt,
+ dene,
+ plascur,
+ q95,
+ q0,
+ rmajor,
+ rminor,
+ ten,
+ zeff,
+ ):
+ """Bootstrap current fraction from Nevins et al scaling
+ author: P J Knight, CCFE, Culham Science Centre
+ alphan : input real : density profile index
+ alphat : input real : temperature profile index
+ betat : input real : total plasma beta (with respect to the toroidal
+ field)
+ bt : input real : toroidal field on axis (T)
+ dene : input real : electron density (/m3)
+ plascur: input real : plasma current (A)
+ q0 : input real : central safety factor
+ q95 : input real : safety factor at 95% surface
+ rmajor : input real : plasma major radius (m)
+ rminor : input real : plasma minor radius (m)
+ ten : input real : density weighted average plasma temperature (keV)
+ zeff : input real : plasma effective charge
+ This function calculates the bootstrap current fraction,
+ using the Nevins et al method, 4/11/90.
+ AEA FUS 251: A User's Guide to the PROCESS Systems Code
+ """
+ # Calculate peak electron beta
+
+ betae0 = (
+ physics_variables.ne0
+ * physics_variables.te0
+ * 1.0e3
+ * constants.echarge
+ / (bt**2 / (2.0 * constants.rmu0))
+ )
+
+ # Call integration routine
+
+ ainteg, _ = integrate.quad(
+ lambda y: self.bsinteg(
+ y, dene, ten, bt, rminor, rmajor, zeff, alphat, alphan, q0, q95, betat
+ ),
+ 0,
+ 0.999,
+ epsabs=0.001,
+ epsrel=0.001,
+ )
+
+ # Calculate bootstrap current and fraction
+
+ aibs = 2.5 * betae0 * rmajor * bt * q95 * ainteg
+ return 1.0e6 * aibs / plascur
+
+ def bsinteg(
+ self, y, dene, ten, bt, rminor, rmajor, zeff, alphat, alphan, q0, q95, betat
+ ):
+ """Integrand function for Nevins et al bootstrap current scaling
+ author: P J Knight, CCFE, Culham Science Centre
+ y : input real : abscissa of integration, = normalised minor radius
+ This function calculates the integrand function for the
+ Nevins et al bootstrap current scaling, 4/11/90.
+ AEA FUS 251: A User's Guide to the PROCESS Systems Code
+ """
+ # Constants for fit to q-profile
+
+ c1 = 1.0
+ c2 = 1.0
+ c3 = 1.0
+
+ # Compute average electron beta
+
+ betae = (
+ dene * ten * 1.0e3 * constants.echarge / (bt**2 / (2.0 * constants.rmu0))
+ )
+
+ nabla = rminor * np.sqrt(y) / rmajor
+ x = (1.46 * np.sqrt(nabla) + 2.4 * nabla) / (1.0 - nabla) ** 1.5
+ z = zeff
+ d = (
+ 1.414 * z
+ + z * z
+ + x * (0.754 + 2.657 * z + 2.0 * z * z)
+ + x * x * (0.348 + 1.243 * z + z * z)
+ )
+ al2 = -x * (0.884 + 2.074 * z) / d
+ a2 = alphat * (1.0 - y) ** (alphan + alphat - 1.0)
+ alphai = -1.172 / (1.0 + 0.462 * x)
+ a1 = (alphan + alphat) * (1.0 - y) ** (alphan + alphat - 1.0)
+ al1 = x * (0.754 + 2.21 * z + z * z + x * (0.348 + 1.243 * z + z * z)) / d
+
+ # q-profile
+
+ q = q0 + (q95 - q0) * (c1 * y + c2 * y * y + c3 * y**3) / (c1 + c2 + c3)
+
+ pratio = (betat - betae) / betae
+
+ return (q / q95) * (al1 * (a1 + pratio * (a1 + alphai * a2)) + al2 * a2)
+
+ def bootstrap_fraction_wilson(
+ self, alphaj, alphap, alphat, betpth, q0, qpsi, rmajor, rminor
+ ):
+ """Bootstrap current fraction from Wilson et al scaling
+ author: P J Knight, CCFE, Culham Science Centre
+ alphaj : input real : current profile index
+ alphap : input real : pressure profile index
+ alphat : input real : temperature profile index
+ beta : input real : total beta
+ betpth : input real : thermal component of poloidal beta
+ q0 : input real : safety factor on axis
+ qpsi : input real : edge safety factor
+ rmajor : input real : major radius (m)
+ rminor : input real : minor radius (m)
+ This function calculates the bootstrap current fraction
+ using the numerically fitted algorithm written by Howard Wilson.
+ AEA FUS 172: Physics Assessment for the European Reactor Study
+ H. R. Wilson, Nuclear Fusion 32 (1992) 257
+ """
+ term1 = np.log(0.5)
+ term2 = np.log(q0 / qpsi)
+
+ termp = 1.0 - 0.5 ** (1.0 / alphap)
+ termt = 1.0 - 0.5 ** (1.0 / alphat)
+ termj = 1.0 - 0.5 ** (1.0 / alphaj)
+
+ alfpnw = term1 / np.log(np.log((q0 + (qpsi - q0) * termp) / qpsi) / term2)
+ alftnw = term1 / np.log(np.log((q0 + (qpsi - q0) * termt) / qpsi) / term2)
+ aj = term1 / np.log(np.log((q0 + (qpsi - q0) * termj) / qpsi) / term2)
+
+ # Crude check for NaN errors or other illegal values...
+
+ if np.isnan(aj) or np.isnan(alfpnw) or np.isnan(alftnw) or aj < 0:
+ error_handling.fdiags[0] = aj
+ error_handling.fdiags[1] = alfpnw
+ error_handling.fdiags[2] = alftnw
+ error_handling.fdiags[3] = aj
+
+ error_handling.report_error(76)
+
+ # Ratio of ionic charge to electron charge
+
+ z = 1.0
+
+ # Inverse aspect ratio: r2 = maximum plasma radius, r1 = minimum
+
+ r2 = rmajor + rminor
+ r1 = rmajor - rminor
+ eps1 = (r2 - r1) / (r2 + r1)
+
+ # Coefficients fitted using least squares techniques
+
+ saj = np.sqrt(aj)
+
+ a = np.array(
+ [
+ 1.41 * (1.0 - 0.28 * saj) * (1.0 + 0.12 / z),
+ 0.36 * (1.0 - 0.59 * saj) * (1.0 + 0.8 / z),
+ -0.27 * (1.0 - 0.47 * saj) * (1.0 + 3.0 / z),
+ 0.0053 * (1.0 + 5.0 / z),
+ -0.93 * (1.0 - 0.34 * saj) * (1.0 + 0.15 / z),
+ -0.26 * (1.0 - 0.57 * saj) * (1.0 - 0.27 * z),
+ 0.064 * (1.0 - 0.6 * aj + 0.15 * aj * aj) * (1.0 + 7.6 / z),
+ -0.0011 * (1.0 + 9.0 / z),
+ -0.33 * (1.0 - aj + 0.33 * aj * aj),
+ -0.26 * (1.0 - 0.87 / saj - 0.16 * aj),
+ -0.14 * (1.0 - 1.14 / saj - 0.45 * saj),
+ -0.0069,
+ ]
+ )
+
+ seps1 = np.sqrt(eps1)
+
+ b = np.array(
+ [
+ 1.0,
+ alfpnw,
+ alftnw,
+ alfpnw * alftnw,
+ seps1,
+ alfpnw * seps1,
+ alftnw * seps1,
+ alfpnw * alftnw * seps1,
+ eps1,
+ alfpnw * eps1,
+ alftnw * eps1,
+ alfpnw * alftnw * eps1,
+ ]
+ )
+
+ # Empirical bootstrap current fraction
+
+ return seps1 * betpth * (a * b).sum()
+
+ def diamagnetic_fraction_hender(self, beta):
+ """author: S.I. Muldrew, CCFE, Culham Science Centre
+ Diamagnetic contribution at tight aspect ratio.
+ Tim Hender fit
+ """
+ return beta / 2.8
+
+ def diamagnetic_fraction_scene(self, beta, q95, q0):
+ """author: S.I. Muldrew, CCFE, Culham Science Centre
+ Diamagnetic fraction based on SCENE fit by Tim Hender
+ See Issue #992
+ """
+ return beta * (0.1 * q95 / q0 + 0.44) * 4.14e-1
+
+ def ps_fraction_scene(self, beta):
+ """author: S.I. Muldrew, CCFE, Culham Science Centre
+ Pfirsch-Schlüter fraction based on SCENE fit by Tim Hender
+ See Issue #992
+ """
+ return -9e-2 * beta
+
+ def bootstrap_fraction_sauter(self):
+ """Bootstrap current fraction from Sauter et al scaling
+ author: P J Knight, CCFE, Culham Science Centre
+ None
+ This function calculates the bootstrap current fraction
+ using the Sauter, Angioni and Lin-Liu scaling.
+
The code was supplied by Emiliano Fable, IPP Garching + (private communication). + O. Sauter, C. Angioni and Y. R. Lin-Liu, + Physics of Plasmas 6 (1999) 2834 + O. Sauter, C. Angioni and Y. R. Lin-Liu, (ERRATA) + Physics of Plasmas 9 (2002) 5140 + """ + NR = 200 + + roa = np.arange(1, NR + 1, step=1) / NR + + rho = np.sqrt(physics_variables.xarea / np.pi) * roa + sqeps = np.sqrt(roa * (physics_variables.rminor / physics_variables.rmajor)) + + ne = 1e-19 * np.vectorize( + lambda r: profiles_module.nprofile( + r, + physics_variables.rhopedn, + physics_variables.ne0, + physics_variables.neped, + physics_variables.nesep, + physics_variables.alphan, + ) + )(roa) + ni = (physics_variables.dnitot / physics_variables.dene) * ne + tempe = np.vectorize( + lambda r: profiles_module.tprofile( + r, + physics_variables.rhopedt, + physics_variables.te0, + physics_variables.teped, + physics_variables.tesep, + physics_variables.alphat, + physics_variables.tbeta, + ) + )(roa) + tempi = (physics_variables.ti / physics_variables.te) * tempe + + zef = np.full_like(tempi, physics_variables.zeff) # Flat Zeff profile assumed + + # mu = 1/safety factor + # Parabolic q profile assumed + mu = 1 / ( + physics_variables.q0 + + (physics_variables.q - physics_variables.q0) * roa**2 + ) + amain = np.full_like(mu, physics_variables.afuel) + zmain = np.full_like(mu, 1.0 + physics_variables.fhe3) + + if ne[NR - 1] == 0.0: + ne[NR - 1] = 1e-4 * ne[NR - 2] + ni[NR - 1] = 1e-4 * ni[NR - 2] + + if tempe[NR - 1] == 0.0: + tempe[NR - 1] = 1e-4 * tempe[NR - 2] + tempi[NR - 1] = 1e-4 * tempi[NR - 2] + + # Calculate total bootstrap current (MA) by summing along profiles + iboot = 0.0 + for ir in range(0, NR): + if ir + 1 == NR: + jboot = 0.0 + da = 0.0 + else: + drho = rho[ir + 1] - rho[ir] + da = 2 * np.pi * rho[ir] * drho # area of annulus + + dlogte_drho = (np.log(tempe[ir + 1]) - np.log(tempe[ir])) / drho + dlogti_drho = (np.log(tempi[ir + 1]) - np.log(tempi[ir])) / drho + dlogne_drho = (np.log(ne[ir + 1]) - np.log(ne[ir])) / drho + + # The factor of 0.5 below arises because in ASTRA the logarithms + # are coded as (e.g.): (Te(j+1)-Te(j))/(Te(j+1)+Te(j)), which + # actually corresponds to grad(log(Te))/2. So the factors dcsa etc. + # are a factor two larger than one might otherwise expect. + jboot = 0.5 * ( + self.dcsa( + ir + 1, + NR, + physics_variables.rmajor, + physics_variables.bt, + physics_variables.triang, + ne, + ni, + tempe, + tempi, + mu, + rho, + zef, + sqeps, + ) + * dlogne_drho + + self.hcsa( + ir + 1, + NR, + physics_variables.rmajor, + physics_variables.bt, + physics_variables.triang, + ne, + ni, + tempe, + tempi, + mu, + rho, + zef, + sqeps, + ) + * dlogte_drho + + self.xcsa( + ir + 1, + NR, + physics_variables.rmajor, + physics_variables.bt, + physics_variables.triang, + mu, + sqeps, + tempi, + tempe, + amain, + zmain, + ni, + ne, + rho, + zef, + ) + * dlogti_drho + ) + jboot = ( + -physics_variables.bt + / (0.2 * np.pi * physics_variables.rmajor) + * rho[ir] + * mu[ir] + * jboot + ) # MA/m2 + + iboot += da * jboot + return 1.0e6 * iboot / physics_variables.plascur + + def hcsa( + self, j, nr, rmajor, bt, triang, ne, ni, tempe, tempi, mu, rho, zef, sqeps + ): + """Grad(ln(Te)) coefficient in the Sauter bootstrap scaling + author: P J Knight, CCFE, Culham Science Centre + j : input integer : radial element index in range 1 to nr + nr : input integer : maximum value of j + This function calculates the coefficient scaling grad(ln(Te)) + in the Sauter bootstrap current scaling. + Code by Angioni, 29th May 2002. +
The code was supplied by Emiliano Fable, IPP Garching + (private communication). + O. Sauter, C. Angioni and Y. R. Lin-Liu, + Physics of Plasmas 6 (1999) 2834 + O. Sauter, C. Angioni and Y. R. Lin-Liu, (ERRATA) + Physics of Plasmas 9 (2002) 5140 + """ + + if j == 1: + return 0.0 + + zz = zef[j - 1] + zft = self.tpf(j, triang, sqeps) + zdf = 1.0 + 0.26 * (1.0 - zft) * np.sqrt( + self.nues(j, rmajor, zef, mu, sqeps, tempe, ne) + ) + zdf = zdf + 0.18 * (1.0 - 0.37 * zft) * self.nues( + j, rmajor, zef, mu, sqeps, tempe, ne + ) / np.sqrt(zz) + zfte = zft / zdf # $f^{32\_ee}_{teff}(\nu_{e*})$, Eq.15d + zfte2 = zfte * zfte + zfte3 = zfte * zfte2 + zfte4 = zfte2 * zfte2 + + zdf = 1.0 + (1.0 + 0.6 * zft) * np.sqrt( + self.nues(j, rmajor, zef, mu, sqeps, tempe, ne) + ) + zdf = zdf + 0.85 * (1.0 - 0.37 * zft) * self.nues( + j, rmajor, zef, mu, sqeps, tempe, ne + ) * (1.0 + zz) + zfti = zft / zdf # $f^{32\_ei}_{teff}(\nu_{e*})$, Eq.15e + zfti2 = zfti * zfti + zfti3 = zfti * zfti2 + zfti4 = zfti2 * zfti2 + + hcee = (0.05 + 0.62 * zz) / zz / (1.0 + 0.44 * zz) * (zfte - zfte4) + hcee = hcee + (zfte2 - zfte4 - 1.2 * (zfte3 - zfte4)) / (1.0 + 0.22 * zz) + hcee = hcee + 1.2 / (1.0 + 0.5 * zz) * zfte4 # $F_{32\_ee}(X)$, Eq.15b + + hcei = -(0.56 + 1.93 * zz) / zz / (1.0 + 0.44 * zz) * (zfti - zfti4) + hcei = hcei + 4.95 / (1.0 + 2.48 * zz) * ( + zfti2 - zfti4 - 0.55 * (zfti3 - zfti4) + ) + hcei = hcei - 1.2 / (1.0 + 0.5 * zz) * zfti4 # $F_{32\_ei}(Y)$, Eq.15c + + # Corrections suggested by Fable, 15/05/2015 + return self.beta_poloidal_local(j, nr, rmajor, bt, ne, tempe, mu, rho) * ( + hcee + hcei + ) + self.dcsa( + j, nr, rmajor, bt, triang, ne, ni, tempe, tempi, mu, rho, zef, sqeps + ) * self.beta_poloidal_local( + j, nr, rmajor, bt, ne, tempe, mu, rho + ) / self.beta_poloidal_local_total( + j, nr, rmajor, bt, ne, ni, tempe, tempi, mu, rho + ) + + def xcsa( + self, + j, + nr, + rmajor, + bt, + triang, + mu, + sqeps, + tempi, + tempe, + amain, + zmain, + ni, + ne, + rho, + zef, + ): + """Grad(ln(Ti)) coefficient in the Sauter bootstrap scaling + author: P J Knight, CCFE, Culham Science Centre + j : input integer : radial element index in range 1 to nr + nr : input integer : maximum value of j + This function calculates the coefficient scaling grad(ln(Ti)) + in the Sauter bootstrap current scaling. + Code by Angioni, 29th May 2002. +
The code was supplied by Emiliano Fable, IPP Garching + (private communication). + O. Sauter, C. Angioni and Y. R. Lin-Liu, + Physics of Plasmas 6 (1999) 2834 + O. Sauter, C. Angioni and Y. R. Lin-Liu, (ERRATA) + Physics of Plasmas 9 (2002) 5140 + """ + if j == 1: + return 0.0 + + zz = zef[j - 1] + zft = self.tpf(j, triang, sqeps) + zdf = 1.0 + (1.0 - 0.1 * zft) * np.sqrt( + self.nues(j, rmajor, zef, mu, sqeps, tempe, ne) + ) + zdf = ( + zdf + + 0.5 + * (1.0 - 0.5 * zft) + * self.nues(j, rmajor, zef, mu, sqeps, tempe, ne) + / zz + ) + zfte = zft / zdf # $f^{34}_{teff}(\nu_{e*})$, Eq.16b + + xcsa = (1.0 + 1.4 / (zz + 1.0)) * zfte - 1.9 / (zz + 1.0) * zfte * zfte + xcsa = xcsa + (0.3 * zfte * zfte + 0.2 * zfte * zfte * zfte) * zfte / ( + zz + 1.0 + ) # Eq.16a + + a0 = -1.17 * (1.0 - zft) + a0 = a0 / (1.0 - 0.22 * zft - 0.19 * zft * zft) # $\alpha_0$, Eq.17a + + alp = ( + a0 + + 0.25 + * (1.0 - zft * zft) + * np.sqrt(self.nuis(j, rmajor, mu, sqeps, tempi, amain, zmain, ni)) + ) / ( + 1.0 + + 0.5 * np.sqrt(self.nuis(j, rmajor, mu, sqeps, tempi, amain, zmain, ni)) + ) + a1 = ( + self.nuis(j, rmajor, mu, sqeps, tempi, amain, zmain, ni) + * self.nuis(j, rmajor, mu, sqeps, tempi, amain, zmain, ni) + * zft**6 + ) + alp = (alp + 0.315 * a1) / (1.0 + 0.15 * a1) # $\alpha(\nu_{i*})$, Eq.17b + + # Corrections suggested by Fable, 15/05/2015 + + return ( + self.beta_poloidal_local_total( + j, nr, rmajor, bt, ne, ni, tempe, tempi, mu, rho + ) + - self.beta_poloidal_local(j, nr, rmajor, bt, ne, tempe, mu, rho) + ) * (xcsa * alp) + self.dcsa( + j, nr, rmajor, bt, triang, ne, ni, tempe, tempi, mu, rho, zef, sqeps + ) * ( + 1.0 + - self.beta_poloidal_local(j, nr, rmajor, bt, ne, tempe, mu, rho) + / self.beta_poloidal_local_total( + j, nr, rmajor, bt, ne, ni, tempe, tempi, mu, rho + ) + ) + + def nuis(self, j, rmajor, mu, sqeps, tempi, amain, zmain, ni): + """Relative frequency of ion collisions + author: P J Knight, CCFE, Culham Science Centre + j : input integer : radial element index in range 1 to nr + This function calculates the relative frequency of ion + collisions: NU* = Nui*q*Rt/eps**1.5/Vti + The full ion collision frequency NUI is used. +
The code was supplied by Emiliano Fable, IPP Garching + (private communication). + Yushmanov, 30th April 1987 (?) + """ + return ( + 3.2e-6 + * self.nui(j, zmain, ni, tempi, amain) + * rmajor + / ( + abs(mu[j - 1] + 1.0e-4) + * sqeps[j - 1] ** 3 + * np.sqrt(tempi[j - 1] / amain[j - 1]) + ) + ) + + def nui(self, j, zmain, ni, tempi, amain): + """Full frequency of ion collisions + author: P J Knight, CCFE, Culham Science Centre + j : input integer : radial element index in range 1 to nr + This function calculates the full frequency of ion + collisions (Hz). +
The code was supplied by Emiliano Fable, IPP Garching + (private communication). + None + """ + # Coulomb logarithm = 15 is used + return ( + zmain[j - 1] ** 4 + * ni[j - 1] + * 322.0 + / (tempi[j - 1] * np.sqrt(tempi[j - 1] * amain[j - 1])) + ) + + def dcsa( + self, j, nr, rmajor, bt, triang, ne, ni, tempe, tempi, mu, rho, zef, sqeps + ): + """Grad(ln(ne)) coefficient in the Sauter bootstrap scaling + author: P J Knight, CCFE, Culham Science Centre + j : input integer : radial element index in range 1 to nr + nr : input integer : maximum value of j + This function calculates the coefficient scaling grad(ln(ne)) + in the Sauter bootstrap current scaling. + Code by Angioni, 29th May 2002. +
The code was supplied by Emiliano Fable, IPP Garching + (private communication). + O. Sauter, C. Angioni and Y. R. Lin-Liu, + Physics of Plasmas 6 (1999) 2834 + O. Sauter, C. Angioni and Y. R. Lin-Liu, (ERRATA) + Physics of Plasmas 9 (2002) 5140 + + DCSA $\\equiv \\mathcal{L}_{31}$, Eq.14a, Sauter et al, 1999 + """ + + if j == 1: + return 0.0 + + zz = zef[j - 1] + zft = self.tpf(j, triang, sqeps) + zdf = 1.0 + (1.0 - 0.1 * zft) * np.sqrt( + self.nues(j, rmajor, zef, mu, sqeps, tempe, ne) + ) + zdf = ( + zdf + + 0.5 * (1.0 - zft) * self.nues(j, rmajor, zef, mu, sqeps, tempe, ne) / zz + ) + zft = zft / zdf # $f^{31}_{teff}(\nu_{e*})$, Eq.14b + dcsa = ( + (1.0 + 1.4 / (zz + 1.0)) * zft + - 1.9 / (zz + 1.0) * zft * zft + + (0.3 * zft * zft + 0.2 * zft * zft * zft) * zft / (zz + 1.0) + ) + + # Corrections suggested by Fable, 15/05/2015 + return dcsa * self.beta_poloidal_local_total( + j, nr, rmajor, bt, ne, ni, tempe, tempi, mu, rho + ) + + def nues(self, j, rmajor, zef, mu, sqeps, tempe, ne): + """Relative frequency of electron collisions + author: P J Knight, CCFE, Culham Science Centre + j : input integer : radial element index in range 1 to nr + This function calculates the relative frequency of electron + collisions: NU* = Nuei*q*Rt/eps**1.5/Vte + The electron-ion collision frequency NUEI=NUEE*1.4*ZEF is + used. +
The code was supplied by Emiliano Fable, IPP Garching + (private communication). + Yushmanov, 30th April 1987 (?) + """ + return ( + self.nuee(j, tempe, ne) + * 1.4 + * zef[j - 1] + * rmajor + / abs(mu[j - 1] * (sqeps[j - 1] ** 3) * np.sqrt(tempe[j - 1]) * 1.875e7) + ) + + def nuee(self, j, tempe, ne): + """Frequency of electron-electron collisions + author: P J Knight, CCFE, Culham Science Centre + j : input integer : radial element index in range 1 to nr + This function calculates the frequency of electron-electron + collisions (Hz): NUEE = 4*SQRT(pi)/3*Ne*e**4*lambd/ + SQRT(Me)/Te**1.5 +
The code was supplied by Emiliano Fable, IPP Garching + (private communication). + Yushmanov, 25th April 1987 (?), + updated by Pereverzev, 9th November 1994 (?) + """ + return ( + 670.0 + * self.coulg(j, tempe, ne) + * ne[j - 1] + / (tempe[j - 1] * np.sqrt(tempe[j - 1])) + ) + + def coulg(self, j, tempe, ne): + """Coulomb logarithm + author: P J Knight, CCFE, Culham Science Centre + j : input integer : radial element index in range 1 to nr + This function calculates the Coulomb logarithm, valid + for e-e collisions (T_e > 0.01 keV), and for + e-i collisions (T_e > 0.01*Zeff^2) (Alexander, 9/5/1994). +
The code was supplied by Emiliano Fable, IPP Garching + (private communication). + C. A. Ordonez and M. I. Molina, Phys. Plasmas 1 (1994) 2515 + Rev. Mod. Phys., V.48, Part 1 (1976) 275 + """ + return 15.9 - 0.5 * np.log(ne[j - 1]) + np.log(tempe[j - 1]) + + def beta_poloidal_local(self, j, nr, rmajor, bt, ne, tempe, mu, rho): + """Local beta poloidal calculation + author: P J Knight, CCFE, Culham Science Centre + j : input integer : radial element index in range 1 to nr + nr : input integer : maximum value of j + This function calculates the local beta poloidal. +
The code was supplied by Emiliano Fable, IPP Garching + (private communication). +
beta poloidal = 4*pi*ne*Te/Bpo**2 + Pereverzev, 25th April 1989 (?) + """ + if j != nr: + beta_poloidal_local = ( + 1.6e-4 * np.pi * (ne[j] + ne[j - 1]) * (tempe[j] + tempe[j - 1]) + ) + else: + beta_poloidal_local = 6.4e-4 * np.pi * ne[j - 1] * tempe[j - 1] + + return ( + beta_poloidal_local + * (rmajor / (bt * rho[j - 1] * abs(mu[j - 1] + 1.0e-4))) ** 2 + ) + + def beta_poloidal_local_total( + self, j, nr, rmajor, bt, ne, ni, tempe, tempi, mu, rho + ): + """Local beta poloidal calculation, including ion pressure + author: P J Knight, CCFE, Culham Science Centre + j : input integer : radial element index in range 1 to nr + nr : input integer : maximum value of j + This function calculates the local total beta poloidal. +
The code was supplied by Emiliano Fable, IPP Garching + (private communication). +
beta poloidal = 4*pi*(ne*Te+ni*Ti)/Bpo**2 + where ni is the sum of all ion densities (thermal) + Pereverzev, 25th April 1989 (?) + E Fable, private communication, 15th May 2014 + """ + + if j != nr: + beta_poloidal_local_total = ( + 1.6e-4 + * np.pi + * ( + ((ne[j] + ne[j - 1]) * (tempe[j] + tempe[j - 1])) + + ((ni[j] + ni[j - 1]) * (tempi[j] + tempi[j - 1])) + ) + ) + else: + beta_poloidal_local_total = ( + 6.4e-4 * np.pi * (ne[j - 1] * tempe[j - 1] + ni[j - 1] * tempi[j - 1]) + ) + + return ( + beta_poloidal_local_total + * (rmajor / (bt * rho[j - 1] * abs(mu[j - 1] + 1.0e-4))) ** 2 + ) + + def tpf(self, j, triang, sqeps, fit=1): + """Trapped particle fraction + author: P J Knight, CCFE, Culham Science Centre + j : input integer : radial element index in range 1 to nr + fit : input integer : (1)=ASTRA method, 2=Equation from Sauter2002, 3=Equation from Sauter2013 + This function calculates the trapped particle fraction at + a given radius. +
A number of different fits are provided, but the one + to be used is hardwired prior to run-time. +
The code was supplied by Emiliano Fable, IPP Garching
+ (private communication).
+ O. Sauter et al, Plasma Phys. Contr. Fusion 44 (2002) 1999
+ O. Sauter, 2013:
+ http://infoscience.epfl.ch/record/187521/files/lrp_012013.pdf
+ """
+ s = sqeps[j - 1]
+ eps = s * s
+
+ if fit == 1:
+ # ASTRA method, from Emiliano Fable, private communication
+ # (Excluding h term which dominates for inverse aspect ratios < 0.5,
+ # and tends to take the trapped particle fraction to 1)
+
+ zz = 1.0 - eps
+ return 1.0 - zz * np.sqrt(zz) / (1.0 + 1.46 * s)
+ elif fit == 2:
+ # Equation 4 of Sauter 2002
+ # Similar to, but not quite identical to g above
+
+ return 1.0 - (1.0 - eps) ** 2 / (1.0 + 1.46 * s) / np.sqrt(1.0 - eps * eps)
+ elif fit == 3:
+ # Includes correction for triangularity
+
+ epseff = 0.67 * (1.0 - 1.4 * triang * abs(triang)) * eps
+
+ return 1.0 - np.sqrt((1.0 - eps) / (1.0 + eps)) * (1.0 - epseff) / (
+ 1.0 + 2.0 * np.sqrt(epseff)
+ )
+
+ raise RuntimeError(f"{fit=} is not valid. Must be 1, 2, or 3")
+
+ def eped_warning(self):
+ eped_warning = ""
+
+ if (physics_variables.triang < 0.399e0) or (physics_variables.triang > 0.601e0):
+ eped_warning += f"{physics_variables.triang = }"
+
+ if (physics_variables.kappa < 1.499e0) or (physics_variables.kappa > 2.001e0):
+ eped_warning += f"{physics_variables.kappa = }"
+
+ if (physics_variables.plascur < 9.99e6) or (
+ physics_variables.plascur > 20.01e6
+ ):
+ eped_warning += f"{physics_variables.plascur = }"
+
+ if (physics_variables.rmajor < 6.99e0) or (physics_variables.rmajor > 11.01e0):
+ eped_warning += f"{physics_variables.rmajor = }"
+
+ if (physics_variables.rminor < 1.99e0) or (physics_variables.rminor > 3.501e0):
+ eped_warning += f"{physics_variables.rminor = }"
+
+ if (physics_variables.normalised_total_beta < 1.99e0) or (
+ physics_variables.normalised_total_beta > 3.01e0
+ ):
+ eped_warning += f"{physics_variables.normalised_total_beta = }"
+
+ if physics_variables.tesep > 0.5:
+ eped_warning += f"{physics_variables.tesep = }"
+
+ return eped_warning
+
+ def outtim(self):
+ po.oheadr(self.outfile, "Times")
+
+ po.ovarrf(
+ self.outfile,
+ "Initial charge time for CS from zero current (s)",
+ "(tramp)",
+ times_variables.tramp,
+ )
+ po.ovarrf(
+ self.outfile,
+ "Plasma current ramp-up time (s)",
+ "(tohs)",
+ times_variables.tohs,
+ )
+ po.ovarrf(self.outfile, "Heating time (s)", "(theat)", times_variables.theat)
+ po.ovarre(
+ self.outfile, "Burn time (s)", "(tburn)", times_variables.tburn, "OP "
+ )
+ po.ovarrf(
+ self.outfile,
+ "Reset time to zero current for CS (s)",
+ "(tqnch)",
+ times_variables.tqnch,
+ )
+ po.ovarrf(
+ self.outfile, "Time between pulses (s)", "(tdwell)", times_variables.tdwell
+ )
+ po.oblnkl(self.outfile)
+ po.ovarre(
+ self.outfile,
+ "Total plant cycle time (s)",
+ "(tcycle)",
+ times_variables.tcycle,
+ "OP ",
+ )
+
+ def outplas(self):
+ """Subroutine to output the plasma physics information
+ author: P J Knight, CCFE, Culham Science Centre
+ self.outfile : input integer : Fortran output unit identifier
+ This routine writes the plasma physics information
+ to a file, in a tidy format.
+ AEA FUS 251: A User's Guide to the PROCESS Systems Code
+ """
+
+ # ###############################################
+ # Dimensionless plasma parameters. See reference below.
+ physics_module.nu_star = (
+ 1
+ / constants.rmu0
+ * (15.0e0 * constants.echarge**4 * physics_variables.dlamie)
+ / (4.0e0 * np.pi**1.5e0 * constants.epsilon0**2)
+ * physics_variables.vol**2
+ * physics_variables.rmajor**2
+ * physics_variables.bt
+ * np.sqrt(physics_variables.eps)
+ * physics_variables.dnla**3
+ * physics_variables.kappa
+ / (
+ physics_module.total_plasma_internal_energy**2
+ * physics_variables.plascur
+ )
+ )
+
+ physics_module.rho_star = np.sqrt(
+ 2.0e0
+ * constants.mproton
+ * physics_variables.aion
+ * physics_module.total_plasma_internal_energy
+ / (3.0e0 * physics_variables.vol * physics_variables.dnla)
+ ) / (
+ constants.echarge
+ * physics_variables.bt
+ * physics_variables.eps
+ * physics_variables.rmajor
+ )
+
+ physics_module.beta_mcdonald = (
+ 4.0e0
+ / 3.0e0
+ * constants.rmu0
+ * physics_module.total_plasma_internal_energy
+ / (physics_variables.vol * physics_variables.bt**2)
+ )
+
+ po.oheadr(self.outfile, "Plasma")
+
+ if stellarator_variables.istell == 0:
+ if physics_variables.idivrt == 0:
+ po.ocmmnt(self.outfile, "Plasma configuration = limiter")
+ elif physics_variables.idivrt == 1:
+ po.ocmmnt(self.outfile, "Plasma configuration = single null divertor")
+ elif physics_variables.idivrt == 2:
+ po.ocmmnt(self.outfile, "Plasma configuration = double null divertor")
+ else:
+ error_handling.idiags[0] = physics_variables.idivrt
+ po.report_error(85)
+ else:
+ po.ocmmnt(self.outfile, "Plasma configuration = stellarator")
+
+ if stellarator_variables.istell == 0:
+ if physics_variables.itart == 0:
+ physics_module.itart_r = physics_variables.itart
+ po.ovarrf(
+ self.outfile,
+ "Tokamak aspect ratio = Conventional, itart = 0",
+ "(itart)",
+ physics_module.itart_r,
+ )
+ elif physics_variables.itart == 1:
+ physics_module.itart_r = physics_variables.itart
+ po.ovarrf(
+ self.outfile,
+ "Tokamak aspect ratio = Spherical, itart = 1",
+ "(itart)",
+ physics_module.itart_r,
+ )
+
+ po.osubhd(self.outfile, "Plasma Geometry :")
+ po.ovarrf(
+ self.outfile, "Major radius (m)", "(rmajor)", physics_variables.rmajor
+ )
+ po.ovarrf(
+ self.outfile,
+ "Minor radius (m)",
+ "(rminor)",
+ physics_variables.rminor,
+ "OP ",
+ )
+ po.ovarrf(self.outfile, "Aspect ratio", "(aspect)", physics_variables.aspect)
+
+ if stellarator_variables.istell == 0:
+ if physics_variables.ishape in [0, 6, 8]:
+ po.ovarrf(
+ self.outfile,
+ "Elongation, X-point (input value used)",
+ "(kappa)",
+ physics_variables.kappa,
+ "IP ",
+ )
+ elif physics_variables.ishape == 1:
+ po.ovarrf(
+ self.outfile,
+ "Elongation, X-point (TART scaling)",
+ "(kappa)",
+ physics_variables.kappa,
+ "OP ",
+ )
+ elif physics_variables.ishape in [2, 3]:
+ po.ovarrf(
+ self.outfile,
+ "Elongation, X-point (Zohm scaling)",
+ "(kappa)",
+ physics_variables.kappa,
+ "OP ",
+ )
+ po.ovarrf(
+ self.outfile,
+ "Zohm scaling adjustment factor",
+ "(fkzohm)",
+ physics_variables.fkzohm,
+ )
+ elif physics_variables.ishape in [4, 5, 7]:
+ po.ovarrf(
+ self.outfile,
+ "Elongation, X-point (calculated from kappa95)",
+ "(kappa)",
+ physics_variables.kappa,
+ "OP ",
+ )
+ elif physics_variables.ishape == 9:
+ po.ovarrf(
+ self.outfile,
+ "Elongation, X-point (calculated from aspect ratio and li(3))",
+ "(kappa)",
+ physics_variables.kappa,
+ "OP ",
+ )
+ elif physics_variables.ishape == 10:
+ po.ovarrf(
+ self.outfile,
+ "Elongation, X-point (calculated from aspect ratio and stability margin)",
+ "(kappa)",
+ physics_variables.kappa,
+ "OP ",
+ )
+ elif physics_variables.ishape == 11:
+ po.ovarrf(
+ self.outfile,
+ "Elongation, X-point (calculated from aspect ratio via Menard 2016)",
+ "(kappa)",
+ physics_variables.kappa,
+ "OP ",
+ )
+ else:
+ error_handling.idiags[0] = physics_variables.ishape
+ po.report_error(86)
+
+ if physics_variables.ishape in [4, 5, 7]:
+ po.ovarrf(
+ self.outfile,
+ "Elongation, 95% surface (input value used)",
+ "(kappa95)",
+ physics_variables.kappa95,
+ "IP ",
+ )
+ else:
+ po.ovarrf(
+ self.outfile,
+ "Elongation, 95% surface (calculated from kappa)",
+ "(kappa95)",
+ physics_variables.kappa95,
+ "OP ",
+ )
+
+ po.ovarrf(
+ self.outfile,
+ "Elongation, area ratio calc.",
+ "(kappaa)",
+ physics_variables.kappaa,
+ "OP ",
+ )
+
+ if physics_variables.ishape in [0, 2, 6, 8, 9, 10, 11]:
+ po.ovarrf(
+ self.outfile,
+ "Triangularity, X-point (input value used)",
+ "(triang)",
+ physics_variables.triang,
+ "IP ",
+ )
+ elif physics_variables.ishape == 1:
+ po.ovarrf(
+ self.outfile,
+ "Triangularity, X-point (TART scaling)",
+ "(triang)",
+ physics_variables.triang,
+ "OP ",
+ )
+ else:
+ po.ovarrf(
+ self.outfile,
+ "Triangularity, X-point (calculated from triang95)",
+ "(triang)",
+ physics_variables.triang,
+ "OP ",
+ )
+
+ if physics_variables.ishape in [3, 4, 5, 7]:
+ po.ovarrf(
+ self.outfile,
+ "Triangularity, 95% surface (input value used)",
+ "(triang95)",
+ physics_variables.triang95,
+ "IP ",
+ )
+ else:
+ po.ovarrf(
+ self.outfile,
+ "Triangularity, 95% surface (calculated from triang)",
+ "(triang95)",
+ physics_variables.triang95,
+ "OP ",
+ )
+
+ po.ovarrf(
+ self.outfile,
+ "Plasma poloidal perimeter (m)",
+ "(pperim)",
+ physics_variables.pperim,
+ "OP ",
+ )
+
+ po.ovarrf(
+ self.outfile,
+ "Plasma cross-sectional area (m2)",
+ "(xarea)",
+ physics_variables.xarea,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Plasma surface area (m2)",
+ "(sarea)",
+ physics_variables.sarea,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Plasma volume (m3)",
+ "(vol)",
+ physics_variables.vol,
+ "OP ",
+ )
+
+ po.osubhd(self.outfile, "Current and Field :")
+
+ if stellarator_variables.istell == 0:
+ if physics_variables.iprofile == 0:
+ po.ocmmnt(
+ self.outfile,
+ "Consistency between q0,q,alphaj,rli,dnbeta is not enforced",
+ )
+ else:
+ po.ocmmnt(
+ self.outfile,
+ "Consistency between q0,q,alphaj,rli,dnbeta is enforced",
+ )
+
+ po.oblnkl(self.outfile)
+ po.ovarin(
+ self.outfile,
+ "Plasma current scaling law used",
+ "(icurr)",
+ physics_variables.icurr,
+ )
+
+ po.ovarrf(
+ self.outfile,
+ "Plasma current (MA)",
+ "(plascur/1D6)",
+ physics_variables.plascur / 1.0e6,
+ "OP ",
+ )
+
+ if physics_variables.iprofile == 1:
+ po.ovarrf(
+ self.outfile,
+ "Current density profile factor",
+ "(alphaj)",
+ physics_variables.alphaj,
+ "OP ",
+ )
+ else:
+ po.ovarrf(
+ self.outfile,
+ "Current density profile factor",
+ "(alphaj)",
+ physics_variables.alphaj,
+ )
+
+ po.ovarrf(
+ self.outfile,
+ "Plasma internal inductance, li",
+ "(rli)",
+ physics_variables.rli,
+ "OP ",
+ )
+ po.ovarrf(
+ self.outfile,
+ "Vertical field at plasma (T)",
+ "(bvert)",
+ physics_variables.bvert,
+ "OP ",
+ )
+
+ po.ovarrf(
+ self.outfile,
+ "Vacuum toroidal field at R (T)",
+ "(bt)",
+ physics_variables.bt,
+ )
+ po.ovarrf(
+ self.outfile,
+ "Average poloidal field (T)",
+ "(bp)",
+ physics_variables.bp,
+ "OP ",
+ )
+
+ po.ovarrf(
+ self.outfile,
+ "Total field (sqrt(bp^2 + bt^2)) (T)",
+ "(btot)",
+ physics_variables.btot,
+ "OP ",
+ )
+
+ if stellarator_variables.istell == 0:
+ po.ovarrf(
+ self.outfile, "Safety factor on axis", "(q0)", physics_variables.q0
+ )
+
+ if physics_variables.icurr == 2:
+ po.ovarrf(
+ self.outfile, "Mean edge safety factor", "(q)", physics_variables.q
+ )
+
+ po.ovarrf(
+ self.outfile,
+ "Safety factor at 95% flux surface",
+ "(q95)",
+ physics_variables.q95,
+ )
+
+ po.ovarrf(
+ self.outfile,
+ "Cylindrical safety factor (qcyl)",
+ "(qstar)",
+ physics_variables.qstar,
+ "OP ",
+ )
+
+ if physics_variables.ishape == 1:
+ po.ovarrf(
+ self.outfile,
+ "Lower limit for edge safety factor q",
+ "(qlim)",
+ physics_variables.qlim,
+ "OP ",
+ )
+
+ else:
+ po.ovarrf(
+ self.outfile,
+ "Rotational transform",
+ "(iotabar)",
+ stellarator_variables.iotabar,
+ )
+
+ po.osubhd(self.outfile, "Beta Information :")
+
+ betath = (
+ physics_variables.beta - physics_variables.betaft - physics_variables.betanb
+ )
+ gammaft = (physics_variables.betaft + physics_variables.betanb) / betath
+
+ po.ovarre(self.outfile, "Total plasma beta", "(beta)", physics_variables.beta)
+ po.ovarre(
+ self.outfile,
+ "Total poloidal beta",
+ "(betap)",
+ physics_variables.betap,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Total toroidal beta",
+ " ",
+ physics_variables.beta
+ * (physics_variables.btot / physics_variables.bt) ** 2,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile, "Fast alpha beta", "(betaft)", physics_variables.betaft, "OP "
+ )
+ po.ovarre(
+ self.outfile, "Beam ion beta", "(betanb)", physics_variables.betanb, "OP "
+ )
+ po.ovarre(
+ self.outfile,
+ "(Fast alpha + beam physics_variables.beta)/(thermal physics_variables.beta)",
+ "(gammaft)",
+ gammaft,
+ "OP ",
+ )
+
+ po.ovarre(self.outfile, "Thermal beta", " ", betath, "OP ")
+ po.ovarre(
+ self.outfile,
+ "Thermal poloidal beta",
+ " ",
+ betath * (physics_variables.btot / physics_variables.bp) ** 2,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Thermal toroidal physics_variables.beta (= beta-exp)",
+ " ",
+ betath * (physics_variables.btot / physics_variables.bt) ** 2,
+ "OP ",
+ )
+
+ po.ovarrf(
+ self.outfile,
+ "2nd stability physics_variables.beta : beta_p / (R/a)",
+ "(eps*betap)",
+ physics_variables.eps * physics_variables.betap,
+ "OP ",
+ )
+ po.ovarrf(
+ self.outfile,
+ "2nd stability physics_variables.beta upper limit",
+ "(epbetmax)",
+ physics_variables.epbetmax,
+ )
+
+ if stellarator_variables.istell == 0:
+ if physics_variables.iprofile == 1:
+ po.ovarrf(
+ self.outfile,
+ "Beta g coefficient",
+ "(dnbeta)",
+ physics_variables.dnbeta,
+ "OP ",
+ )
+ else:
+ po.ovarrf(
+ self.outfile,
+ "Beta g coefficient",
+ "(dnbeta)",
+ physics_variables.dnbeta,
+ )
+
+ po.ovarrf(
+ self.outfile,
+ "Normalised thermal beta",
+ " ",
+ 1.0e8
+ * betath
+ * physics_variables.rminor
+ * physics_variables.bt
+ / physics_variables.plascur,
+ "OP ",
+ )
+
+ po.ovarrf(
+ self.outfile,
+ "Normalised total beta",
+ " ",
+ physics_variables.normalised_total_beta,
+ "OP ",
+ )
+
+ normalised_toroidal_beta = (
+ physics_variables.normalised_total_beta
+ * (physics_variables.btot / physics_variables.bt) ** 2
+ )
+ po.ovarrf(
+ self.outfile,
+ "Normalised toroidal beta",
+ "(normalised_toroidal_beta)",
+ normalised_toroidal_beta,
+ "OP ",
+ )
+
+ if physics_variables.iculbl == 0:
+ po.ovarrf(
+ self.outfile,
+ "Limit on total beta",
+ "(betalim)",
+ physics_variables.betalim,
+ "OP ",
+ )
+ elif physics_variables.iculbl == 1:
+ po.ovarrf(
+ self.outfile,
+ "Limit on thermal beta",
+ "(betalim)",
+ physics_variables.betalim,
+ "OP ",
+ )
+ else:
+ po.ovarrf(
+ self.outfile,
+ "Limit on thermal + NB beta",
+ "(betalim)",
+ physics_variables.betalim,
+ "OP ",
+ )
+
+ po.ovarre(
+ self.outfile,
+ "Plasma thermal energy (J)",
+ " ",
+ 1.5e0
+ * betath
+ * physics_variables.btot
+ * physics_variables.btot
+ / (2.0e0 * constants.rmu0)
+ * physics_variables.vol,
+ "OP ",
+ )
+
+ po.ovarre(
+ self.outfile,
+ "Total plasma internal energy (J)",
+ "(total_plasma_internal_energy)",
+ physics_module.total_plasma_internal_energy,
+ "OP ",
+ )
+
+ po.osubhd(self.outfile, "Temperature and Density (volume averaged) :")
+ po.ovarrf(
+ self.outfile, "Electron temperature (keV)", "(te)", physics_variables.te
+ )
+ po.ovarrf(
+ self.outfile,
+ "Electron temperature on axis (keV)",
+ "(te0)",
+ physics_variables.te0,
+ "OP ",
+ )
+ po.ovarrf(self.outfile, "Ion temperature (keV)", "(ti)", physics_variables.ti)
+ po.ovarrf(
+ self.outfile,
+ "Ion temperature on axis (keV)",
+ "(ti0)",
+ physics_variables.ti0,
+ "OP ",
+ )
+ po.ovarrf(
+ self.outfile,
+ "Electron temp., density weighted (keV)",
+ "(ten)",
+ physics_variables.ten,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile, "Electron density (/m3)", "(dene)", physics_variables.dene
+ )
+ po.ovarre(
+ self.outfile,
+ "Electron density on axis (/m3)",
+ "(ne0)",
+ physics_variables.ne0,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Line-averaged electron density (/m3)",
+ "(dnla)",
+ physics_variables.dnla,
+ "OP ",
+ )
+
+ if stellarator_variables.istell == 0:
+ po.ovarre(
+ self.outfile,
+ "Line-averaged electron density / Greenwald density",
+ "(dnla_gw)",
+ physics_variables.dnla / physics_variables.dlimit[6],
+ "OP ",
+ )
+
+ po.ovarre(
+ self.outfile,
+ "Ion density (/m3)",
+ "(dnitot)",
+ physics_variables.dnitot,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile, "Fuel density (/m3)", "(deni)", physics_variables.deni, "OP "
+ )
+ po.ovarre(
+ self.outfile,
+ "Total impurity density with Z > 2 (no He) (/m3)",
+ "(dnz)",
+ physics_variables.dnz,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Helium ion density (thermalised ions only) (/m3)",
+ "(dnalp)",
+ physics_variables.dnalp,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Proton density (/m3)",
+ "(dnprot)",
+ physics_variables.dnprot,
+ "OP ",
+ )
+ if physics_variables.protium > 1.0e-10:
+ po.ovarre(
+ self.outfile,
+ "Seeded protium density / electron density",
+ "(protium)",
+ physics_variables.protium,
+ )
+
+ po.ovarre(
+ self.outfile,
+ "Hot beam density (/m3)",
+ "(dnbeam)",
+ physics_variables.dnbeam,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Density limit from scaling (/m3)",
+ "(dnelimt)",
+ physics_variables.dnelimt,
+ "OP ",
+ )
+ if (numerics.ioptimz > 0) and (numerics.active_constraints[4]):
+ po.ovarre(
+ self.outfile,
+ "Density limit (enforced) (/m3)",
+ "(boundu(9)*dnelimt)",
+ numerics.boundu[8] * physics_variables.dnelimt,
+ "OP ",
+ )
+
+ po.ovarre(
+ self.outfile,
+ "Helium ion density (thermalised ions only) / electron density",
+ "(ralpne)",
+ physics_variables.ralpne,
+ )
+ po.oblnkl(self.outfile)
+
+ po.ocmmnt(self.outfile, "Impurities")
+ po.oblnkl(self.outfile)
+ po.ocmmnt(self.outfile, "Plasma ion densities / electron density:")
+
+ for imp in range(impurity_radiation_module.nimp):
+ # MDK Update fimp, as this will make the ITV output work correctly.
+ impurity_radiation_module.fimp[
+ imp
+ ] = impurity_radiation_module.impurity_arr_frac[imp]
+ str1 = (
+ f2py_compatible_to_string(
+ impurity_radiation_module.impurity_arr_label[imp]
+ )
+ + " concentration"
+ )
+ str2 = f"(fimp({imp+1:02}))"
+ # MDK Add output flag for H which is calculated.
+ if imp == 0:
+ po.ovarre(
+ self.outfile, str1, str2, impurity_radiation_module.fimp[imp], "OP "
+ )
+ else:
+ po.ovarre(self.outfile, str1, str2, impurity_radiation_module.fimp[imp])
+
+ po.ovarre(
+ self.outfile,
+ "Average mass of all ions (amu)",
+ "(aion)",
+ physics_variables.aion,
+ "OP ",
+ )
+ # MDK Say which impurity is varied, if iteration variable fimpvar (102) is turned on
+ # if (any(ixc == 102)) :
+ # call ovarst(self.outfile,'Impurity used as an iteration variable' , '', '"' // impurity_arr(impvar)%label // '"')
+ # po.ovarre(self.outfile,'Fractional density of variable impurity (ion / electron density)','(fimpvar)',fimpvar)
+ #
+ po.oblnkl(self.outfile)
+ po.ovarrf(
+ self.outfile, "Effective charge", "(zeff)", physics_variables.zeff, "OP "
+ )
+
+ # Issue #487. No idea what zeffai is.
+ # I haven't removed it as it is used in subroutine rether,
+ # (routine to find the equilibration power between the ions and electrons)
+ # po.ovarrf(self.outfile,'Mass weighted effective charge','(zeffai)',zeffai, 'OP ')
+
+ po.ovarrf(
+ self.outfile, "Density profile factor", "(alphan)", physics_variables.alphan
+ )
+ po.ovarin(
+ self.outfile,
+ "Plasma profile model",
+ "(ipedestal)",
+ physics_variables.ipedestal,
+ )
+
+ if physics_variables.ipedestal >= 1:
+ if physics_variables.ne0 < physics_variables.neped:
+ error_handling.report_error(213)
+
+ po.ocmmnt(self.outfile, "Pedestal profiles are used.")
+ po.ovarrf(
+ self.outfile,
+ "Density pedestal r/a location",
+ "(rhopedn)",
+ physics_variables.rhopedn,
+ )
+ if physics_variables.fgwped >= 0e0:
+ po.ovarre(
+ self.outfile,
+ "Electron density pedestal height (/m3)",
+ "(neped)",
+ physics_variables.neped,
+ "OP ",
+ )
+ else:
+ po.ovarre(
+ self.outfile,
+ "Electron density pedestal height (/m3)",
+ "(neped)",
+ physics_variables.neped,
+ )
+
+ # This code is ODD# Don't change it# No explanation why fgwped and physics_variables.fgwsep
+ # must be assigned to their exisiting values#
+ fgwped_out = physics_variables.neped / physics_variables.dlimit[6]
+ fgwsep_out = physics_variables.nesep / physics_variables.dlimit[6]
+ if physics_variables.fgwped >= 0e0:
+ physics_variables.fgwped = (
+ physics_variables.neped / physics_variables.dlimit[6]
+ )
+ if physics_variables.fgwsep >= 0e0:
+ physics_variables.fgwsep = (
+ physics_variables.nesep / physics_variables.dlimit[6]
+ )
+
+ po.ovarre(
+ self.outfile,
+ "Electron density at pedestal / nGW",
+ "(fgwped_out)",
+ fgwped_out,
+ )
+ po.ovarrf(
+ self.outfile,
+ "Temperature pedestal r/a location",
+ "(rhopedt)",
+ physics_variables.rhopedt,
+ )
+ # Issue #413 Pedestal scaling
+ po.ovarin(
+ self.outfile,
+ "Pedestal scaling switch",
+ "(ieped)",
+ physics_variables.ieped,
+ )
+ if physics_variables.ieped == 1:
+ po.ocmmnt(
+ self.outfile,
+ "Saarelma 6-parameter pedestal temperature scaling is ON",
+ )
+
+ if self.eped_warning() != "":
+ po.ocmmnt(
+ self.outfile,
+ "WARNING: Pedestal parameters are outside the range of applicability of the scaling:",
+ )
+ po.ocmmnt(
+ self.outfile,
+ "triang: 0.4 - 0.6; physics_variables.kappa: 1.5 - 2.0; plascur: 10 - 20 MA, physics_variables.rmajor: 7 - 11 m;",
+ )
+ po.ocmmnt(
+ self.outfile,
+ "rminor: 2 - 3.5 m; tesep: 0 - 0.5 keV; normalised_total_beta: 2 - 3; ",
+ )
+ print(
+ "WARNING: Pedestal parameters are outside the range of applicability of the scaling:"
+ )
+ print(
+ "triang: 0.4 - 0.6; physics_variables.kappa: 1.5 - 2.0; plascur: 10 - 20 MA, physics_variables.rmajor: 7 - 11 m;"
+ )
+ print(
+ "rminor: 2 - 3.5 m; tesep: 0 - 0.5 keV; normalised_total_beta: 2 - 3"
+ )
+ print(self.eped_warning())
+
+ po.ovarrf(
+ self.outfile,
+ "Electron temp. pedestal height (keV)",
+ "(teped)",
+ physics_variables.teped,
+ )
+ if any(numerics.icc == 78):
+ po.ovarrf(
+ self.outfile,
+ "Electron temp. at separatrix (keV)",
+ "(tesep)",
+ physics_variables.tesep,
+ "OP ",
+ )
+ else:
+ po.ovarrf(
+ self.outfile,
+ "Electron temp. at separatrix (keV)",
+ "(tesep)",
+ physics_variables.tesep,
+ )
+
+ po.ovarre(
+ self.outfile,
+ "Electron density at separatrix (/m3)",
+ "(nesep)",
+ physics_variables.nesep,
+ )
+ po.ovarre(
+ self.outfile,
+ "Electron density at separatrix / nGW",
+ "(fgwsep_out)",
+ fgwsep_out,
+ )
+
+ # Issue 558 - addition of constraint 76 to limit the value of nesep, in proportion with the ballooning parameter and Greenwald density
+ if any(numerics.icc == 76):
+ po.ovarre(
+ self.outfile,
+ "Critical ballooning parameter value",
+ "(alpha_crit)",
+ physics_variables.alpha_crit,
+ )
+ po.ovarre(
+ self.outfile,
+ "Critical electron density at separatrix (/m3)",
+ "(nesep_crit)",
+ physics_variables.nesep_crit,
+ )
+
+ po.ovarrf(
+ self.outfile,
+ "Temperature profile index",
+ "(alphat)",
+ physics_variables.alphat,
+ )
+ po.ovarrf(
+ self.outfile,
+ "Temperature profile index beta",
+ "(tbeta)",
+ physics_variables.tbeta,
+ )
+
+ if stellarator_variables.istell == 0:
+ po.osubhd(self.outfile, "Density Limit using different models :")
+ po.ovarre(
+ self.outfile,
+ "Old ASDEX model",
+ "(dlimit(1))",
+ physics_variables.dlimit[0],
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Borrass ITER model I",
+ "(dlimit(2))",
+ physics_variables.dlimit[1],
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Borrass ITER model II",
+ "(dlimit(3))",
+ physics_variables.dlimit[2],
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "JET edge radiation model",
+ "(dlimit(4))",
+ physics_variables.dlimit[3],
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "JET simplified model",
+ "(dlimit(5))",
+ physics_variables.dlimit[4],
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Hugill-Murakami Mq model",
+ "(dlimit(6))",
+ physics_variables.dlimit[5],
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Greenwald model",
+ "(dlimit(7))",
+ physics_variables.dlimit[6],
+ "OP ",
+ )
+
+ po.osubhd(self.outfile, "Fuel Constituents :")
+ po.ovarrf(
+ self.outfile, "Deuterium fuel fraction", "(fdeut)", physics_variables.fdeut
+ )
+ po.ovarrf(
+ self.outfile, "Tritium fuel fraction", "(ftrit)", physics_variables.ftrit
+ )
+ if physics_variables.fhe3 > 1.0e-3:
+ po.ovarrf(
+ self.outfile, "3-Helium fuel fraction", "(fhe3)", physics_variables.fhe3
+ )
+
+ po.osubhd(self.outfile, "Fusion Power :")
+ po.ovarre(
+ self.outfile,
+ "Total fusion power (MW)",
+ "(powfmw)",
+ physics_variables.powfmw,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ " = D-T fusion power (MW)",
+ "(pdt)",
+ physics_variables.pdt,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ " + D-D fusion power (MW)",
+ "(pdd)",
+ physics_variables.pdd,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ " + D-He3 fusion power (MW)",
+ "(pdhe3)",
+ physics_variables.pdhe3,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Alpha power: total (MW)",
+ "(palpmw)",
+ physics_variables.palpmw,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Alpha power: beam-plasma (MW)",
+ "(palpnb)",
+ physics_variables.palpnb,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Neutron power (MW)",
+ "(pneutmw)",
+ physics_variables.pneutmw,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Charged particle power (excluding alphas) (MW)",
+ "(pchargemw)",
+ physics_variables.pchargemw,
+ "OP ",
+ )
+ tot_power_plasma = (
+ physics_variables.falpha * physics_variables.palpmw
+ + physics_variables.pchargemw
+ + physics_variables.pohmmw
+ + current_drive_variables.pinjmw
+ )
+ po.ovarre(
+ self.outfile,
+ "Total power deposited in plasma (MW)",
+ "(tot_power_plasma)",
+ tot_power_plasma,
+ "OP ",
+ )
+ # po.ovarre(self.outfile,'Total power deposited in plasma (MW)','()',falpha*palpmw+pchargemw+pohmmw+pinjmw, 'OP ')
+
+ po.osubhd(self.outfile, "Radiation Power (excluding SOL):")
+ po.ovarre(
+ self.outfile,
+ "Bremsstrahlung radiation power (MW)",
+ "(pbrempv*vol)",
+ physics_variables.pbrempv * physics_variables.vol,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Line radiation power (MW)",
+ "(plinepv*vol)",
+ physics_variables.plinepv * physics_variables.vol,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Synchrotron radiation power (MW)",
+ "(psyncpv*vol)",
+ physics_variables.psyncpv * physics_variables.vol,
+ "OP ",
+ )
+ po.ovarrf(
+ self.outfile,
+ "Synchrotron wall reflectivity factor",
+ "(ssync)",
+ physics_variables.ssync,
+ )
+ po.ovarre(
+ self.outfile,
+ "Normalised minor radius defining 'core'",
+ "(coreradius)",
+ impurity_radiation_module.coreradius,
+ )
+ po.ovarre(
+ self.outfile,
+ "Fraction of core radiation subtracted from P_L",
+ "(coreradiationfraction)",
+ impurity_radiation_module.coreradiationfraction,
+ )
+ po.ovarre(
+ self.outfile,
+ "Radiation power from inner zone (MW)",
+ "(pinnerzoneradmw)",
+ physics_variables.pinnerzoneradmw,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Radiation power from outer zone (MW)",
+ "(pouterzoneradmw)",
+ physics_variables.pouterzoneradmw,
+ "OP ",
+ )
+
+ if stellarator_variables.istell != 0:
+ po.ovarre(
+ self.outfile,
+ "SOL radiation power as imposed by f_rad (MW)",
+ "(psolradmw)",
+ physics_variables.psolradmw,
+ "OP ",
+ )
+
+ po.ovarre(
+ self.outfile,
+ "Total radiation power from inside LCFS (MW)",
+ "(pradmw)",
+ physics_variables.pradmw,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "LCFS radiation fraction = total radiation in LCFS / total power deposited in plasma",
+ "(rad_fraction_LCFS)",
+ physics_module.rad_fraction_lcfs,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Nominal mean radiation load on inside surface of reactor (MW/m2)",
+ "(photon_wall)",
+ physics_variables.photon_wall,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Peaking factor for radiation wall load",
+ "(peakfactrad)",
+ constraint_variables.peakfactrad,
+ "IP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Maximum permitted radiation wall load (MW/m^2)",
+ "(maxradwallload)",
+ constraint_variables.maxradwallload,
+ "IP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Peak radiation wall load (MW/m^2)",
+ "(peakradwallload)",
+ constraint_variables.peakradwallload,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Fast alpha particle power incident on the first wall (MW)",
+ "(palpfwmw)",
+ physics_variables.palpfwmw,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Nominal mean neutron load on inside surface of reactor (MW/m2)",
+ "(wallmw)",
+ physics_variables.wallmw,
+ "OP ",
+ )
+
+ if stellarator_variables.istell == 0:
+ po.oblnkl(self.outfile)
+ po.ovarre(
+ self.outfile,
+ "Power incident on the divertor targets (MW)",
+ "(ptarmw)",
+ physics_module.ptarmw,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Fraction of power to the lower divertor",
+ "(ftar)",
+ physics_variables.ftar,
+ "IP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Outboard side heat flux decay length (m)",
+ "(lambdaio)",
+ physics_module.lambdaio,
+ "OP ",
+ )
+ if physics_variables.idivrt == 2:
+ po.ovarre(
+ self.outfile,
+ "Midplane seperation of the two magnetic closed flux surfaces (m)",
+ "(drsep)",
+ physics_module.drsep,
+ "OP ",
+ )
+
+ po.ovarre(
+ self.outfile,
+ "Fraction of power on the inner targets",
+ "(fio)",
+ physics_module.fio,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Fraction of power incident on the lower inner target",
+ "(fLI)",
+ physics_module.fli,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Fraction of power incident on the lower outer target",
+ "(fLO)",
+ physics_module.flo,
+ "OP ",
+ )
+ if physics_variables.idivrt == 2:
+ po.ovarre(
+ self.outfile,
+ "Fraction of power incident on the upper inner target",
+ "(fUI)",
+ physics_module.fui,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Fraction of power incident on the upper outer target",
+ "(fUO)",
+ physics_module.fuo,
+ "OP ",
+ )
+
+ po.ovarre(
+ self.outfile,
+ "Power incident on the lower inner target (MW)",
+ "(pLImw)",
+ physics_module.plimw,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Power incident on the lower outer target (MW)",
+ "(pLOmw)",
+ physics_module.plomw,
+ "OP ",
+ )
+ if physics_variables.idivrt == 2:
+ po.ovarre(
+ self.outfile,
+ "Power incident on the upper innner target (MW)",
+ "(pUImw)",
+ physics_module.puimw,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Power incident on the upper outer target (MW)",
+ "(pUOmw)",
+ physics_module.puomw,
+ "OP ",
+ )
+
+ po.oblnkl(self.outfile)
+ po.ovarre(
+ self.outfile,
+ "Ohmic heating power (MW)",
+ "(pohmmw)",
+ physics_variables.pohmmw,
+ "OP ",
+ )
+ po.ovarrf(
+ self.outfile,
+ "Fraction of alpha power deposited in plasma",
+ "(falpha)",
+ physics_variables.falpha,
+ "OP ",
+ )
+ po.ovarrf(
+ self.outfile,
+ "Fraction of alpha power to electrons",
+ "(falpe)",
+ physics_variables.falpe,
+ "OP ",
+ )
+ po.ovarrf(
+ self.outfile,
+ "Fraction of alpha power to ions",
+ "(falpi)",
+ physics_variables.falpi,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Ion transport (MW)",
+ "(ptrimw)",
+ physics_variables.ptrimw,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Electron transport (MW)",
+ "(ptremw)",
+ physics_variables.ptremw,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Injection power to ions (MW)",
+ "(pinjimw)",
+ current_drive_variables.pinjimw,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Injection power to electrons (MW)",
+ "(pinjemw)",
+ current_drive_variables.pinjemw,
+ "OP ",
+ )
+ if physics_variables.ignite == 1:
+ po.ocmmnt(self.outfile, " (Injected power only used for start-up phase)")
+
+ po.ovarin(
+ self.outfile,
+ "Ignited plasma switch (0=not ignited, 1=ignited)",
+ "(ignite)",
+ physics_variables.ignite,
+ )
+
+ po.oblnkl(self.outfile)
+ po.ovarre(
+ self.outfile,
+ "Power into divertor zone via charged particles (MW)",
+ "(pdivt)",
+ physics_variables.pdivt,
+ "OP ",
+ )
+
+ if physics_variables.pdivt <= 0.001e0:
+ error_handling.fdiags[0] = physics_variables.pdivt
+ error_handling.report_error(87)
+ po.oblnkl(self.outfile)
+ po.ocmmnt(
+ self.outfile, " BEWARE: possible problem with high radiation power"
+ )
+ po.ocmmnt(
+ self.outfile, " Power into divertor zone is unrealistic;"
+ )
+ po.ocmmnt(self.outfile, " divertor calculations will be nonsense#")
+ po.ocmmnt(
+ self.outfile, " Set constraint 17 (Radiation fraction upper limit)."
+ )
+ po.oblnkl(self.outfile)
+
+ if physics_variables.idivrt == 2:
+ # Double null divertor configuration
+ po.ovarre(
+ self.outfile,
+ "Pdivt / R ratio (MW/m) (On peak divertor)",
+ "(pdivmax/physics_variables.rmajor)",
+ physics_variables.pdivmax / physics_variables.rmajor,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Pdivt Bt / qAR ratio (MWT/m) (On peak divertor)",
+ "(pdivmaxbt/qar)",
+ (
+ (physics_variables.pdivmax * physics_variables.bt)
+ / (
+ physics_variables.q95
+ * physics_variables.aspect
+ * physics_variables.rmajor
+ )
+ ),
+ "OP ",
+ )
+ else:
+ # Single null divertor configuration
+ po.ovarre(
+ self.outfile,
+ "Psep / R ratio (MW/m)",
+ "(pdivt/rmajor)",
+ physics_variables.pdivt / physics_variables.rmajor,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Psep Bt / qAR ratio (MWT/m)",
+ "(pdivtbt/qar)",
+ (
+ (physics_variables.pdivt * physics_variables.bt)
+ / (
+ physics_variables.q95
+ * physics_variables.aspect
+ * physics_variables.rmajor
+ )
+ ),
+ "OP ",
+ )
+
+ if stellarator_variables.istell == 0:
+ po.osubhd(self.outfile, "H-mode Power Threshold Scalings :")
+
+ po.ovarre(
+ self.outfile,
+ "ITER 1996 scaling: nominal (MW)",
+ "(pthrmw(1))",
+ physics_variables.pthrmw[0],
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "ITER 1996 scaling: upper bound (MW)",
+ "(pthrmw(2))",
+ physics_variables.pthrmw[1],
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "ITER 1996 scaling: lower bound (MW)",
+ "(pthrmw(3))",
+ physics_variables.pthrmw[2],
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "ITER 1997 scaling (1) (MW)",
+ "(pthrmw(4))",
+ physics_variables.pthrmw[3],
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "ITER 1997 scaling (2) (MW)",
+ "(pthrmw(5))",
+ physics_variables.pthrmw[4],
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Martin 2008 scaling: nominal (MW)",
+ "(pthrmw(6))",
+ physics_variables.pthrmw[5],
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Martin 2008 scaling: 95% upper bound (MW)",
+ "(pthrmw(7))",
+ physics_variables.pthrmw[6],
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Martin 2008 scaling: 95% lower bound (MW)",
+ "(pthrmw(8))",
+ physics_variables.pthrmw[7],
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Snipes 2000 scaling: nominal (MW)",
+ "(pthrmw(9))",
+ physics_variables.pthrmw[8],
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Snipes 2000 scaling: upper bound (MW)",
+ "(pthrmw(10))",
+ physics_variables.pthrmw[9],
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Snipes 2000 scaling: lower bound (MW)",
+ "(pthrmw(11))",
+ physics_variables.pthrmw[10],
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Snipes 2000 scaling (closed divertor): nominal (MW)",
+ "(pthrmw(12))",
+ physics_variables.pthrmw[11],
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Snipes 2000 scaling (closed divertor): upper bound (MW)",
+ "(pthrmw(13))",
+ physics_variables.pthrmw[12],
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Snipes 2000 scaling (closed divertor): lower bound (MW)",
+ "(pthrmw(14))",
+ physics_variables.pthrmw[13],
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Hubbard 2012 L-I threshold - nominal (MW)",
+ "(pthrmw(15))",
+ physics_variables.pthrmw[14],
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Hubbard 2012 L-I threshold - lower bound (MW)",
+ "(pthrmw(16))",
+ physics_variables.pthrmw[15],
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Hubbard 2012 L-I threshold - upper bound (MW)",
+ "(pthrmw(17))",
+ physics_variables.pthrmw[16],
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Hubbard 2017 L-I threshold",
+ "(pthrmw(18))",
+ physics_variables.pthrmw[17],
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Martin 2008 aspect ratio corrected scaling: nominal (MW)",
+ "(pthrmw(19))",
+ physics_variables.pthrmw[18],
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Martin 2008 aspect ratio corrected scaling: 95% upper bound (MW)",
+ "(pthrmw(20))",
+ physics_variables.pthrmw[19],
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Martin 2008 aspect ratio corrected scaling: 95% lower bound (MW)",
+ "(pthrmw(21))",
+ physics_variables.pthrmw[20],
+ "OP ",
+ )
+ po.oblnkl(self.outfile)
+ if physics_variables.ilhthresh in [9, 10, 11]:
+ if (physics_variables.bt < 0.78e0) or (physics_variables.bt > 7.94e0):
+ po.ocmmnt(
+ self.outfile,
+ "(physics_variables.bt outside Snipes 2000 fitted range)",
+ )
+ error_handling.report_error(201)
+
+ if (physics_variables.rminor < 0.15e0) or (
+ physics_variables.rminor > 1.15e0
+ ):
+ po.ocmmnt(self.outfile, "(rminor outside Snipes 2000 fitted range)")
+ error_handling.report_error(202)
+
+ if (physics_variables.rmajor < 0.55e0) or (
+ physics_variables.rmajor > 3.37e0
+ ):
+ po.ocmmnt(
+ self.outfile,
+ "(physics_variables.rmajor outside Snipes 2000 fitted range)",
+ )
+ error_handling.report_error(203)
+
+ if (physics_variables.dnla < 0.09e20) or (
+ physics_variables.dnla > 3.16e20
+ ):
+ po.ocmmnt(
+ self.outfile,
+ "(physics_variables.dnla outside Snipes 2000 fitted range)",
+ )
+ error_handling.report_error(204)
+
+ if (physics_variables.kappa < 1.0e0) or (
+ physics_variables.kappa > 2.04e0
+ ):
+ po.ocmmnt(
+ self.outfile,
+ "(physics_variables.kappa outside Snipes 2000 fitted range)",
+ )
+ error_handling.report_error(205)
+
+ if (physics_variables.triang < 0.07e0) or (
+ physics_variables.triang > 0.74e0
+ ):
+ po.ocmmnt(self.outfile, "(triang outside Snipes 2000 fitted range)")
+ error_handling.report_error(206)
+
+ po.oblnkl(self.outfile)
+
+ if physics_variables.ilhthresh in [12, 13, 14]:
+ po.ocmmnt(
+ self.outfile,
+ "(L-H threshold for closed divertor only. Limited data used in Snipes fit)",
+ )
+ po.oblnkl(self.outfile)
+ error_handling.report_error(207)
+
+ if (numerics.ioptimz > 0) and (numerics.active_constraints[14]):
+ po.ovarre(
+ self.outfile,
+ "L-H threshold power (enforced) (MW)",
+ "(boundl(103)*plhthresh)",
+ numerics.boundl[102] * physics_variables.plhthresh,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "L-H threshold power (MW)",
+ "(plhthresh)",
+ physics_variables.plhthresh,
+ "OP ",
+ )
+ else:
+ po.ovarre(
+ self.outfile,
+ "L-H threshold power (NOT enforced) (MW)",
+ "(plhthresh)",
+ physics_variables.plhthresh,
+ "OP ",
+ )
+
+ po.osubhd(self.outfile, "Confinement :")
+
+ if physics_variables.ignite == 1:
+ po.ocmmnt(
+ self.outfile,
+ "Device is assumed to be ignited for the calculation of confinement time",
+ )
+ po.oblnkl(self.outfile)
+
+ po.ocmmnt(
+ self.outfile,
+ f"Confinement scaling law: { physics_variables.tauscl[physics_variables.isc-1]}",
+ )
+
+ po.ovarrf(
+ self.outfile, "Confinement H factor", "(hfact)", physics_variables.hfact
+ )
+ po.ovarrf(
+ self.outfile,
+ "Global thermal energy confinement time (s)",
+ "(taueff)",
+ physics_variables.taueff,
+ "OP ",
+ )
+ po.ovarrf(
+ self.outfile,
+ "Ion energy confinement time (s)",
+ "(tauei)",
+ physics_variables.tauei,
+ "OP ",
+ )
+ po.ovarrf(
+ self.outfile,
+ "Electron energy confinement time (s)",
+ "(tauee)",
+ physics_variables.tauee,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "n.tau = Volume-average electron density x Energy confinement time (s/m3)",
+ "(dntau)",
+ physics_variables.dntau,
+ "OP ",
+ )
+ po.ocmmnt(
+ self.outfile,
+ "Triple product = Vol-average electron density x Vol-average & electron temperature x Energy confinement time:",
+ )
+ po.ovarre(
+ self.outfile,
+ "Triple product (keV s/m3)",
+ "(dntau*te)",
+ physics_variables.dntau * physics_variables.te,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Transport loss power assumed in scaling law (MW)",
+ "(powerht)",
+ physics_variables.powerht,
+ "OP ",
+ )
+ po.ovarin(
+ self.outfile,
+ "Switch for radiation loss term usage in power balance",
+ "(iradloss)",
+ physics_variables.iradloss,
+ )
+ if physics_variables.iradloss == 0:
+ po.ovarre(
+ self.outfile,
+ "Radiation power subtracted from plasma power balance (MW)",
+ "",
+ physics_variables.pradmw,
+ "OP ",
+ )
+ po.ocmmnt(self.outfile, " (Radiation correction is total radiation power)")
+ elif physics_variables.iradloss == 1:
+ po.ovarre(
+ self.outfile,
+ "Radiation power subtracted from plasma power balance (MW)",
+ "",
+ physics_variables.pinnerzoneradmw,
+ "OP ",
+ )
+ po.ocmmnt(self.outfile, " (Radiation correction is core radiation power)")
+ else:
+ po.ovarre(
+ self.outfile,
+ "Radiation power subtracted from plasma power balance (MW)",
+ "",
+ 0.0e0,
+ )
+ po.ocmmnt(self.outfile, " (No radiation correction applied)")
+
+ po.ovarrf(
+ self.outfile,
+ "Alpha particle confinement time (s)",
+ "(taup)",
+ physics_variables.taup,
+ "OP ",
+ )
+ # Note alpha confinement time is no longer equal to fuel particle confinement time.
+ po.ovarrf(
+ self.outfile,
+ "Alpha particle/energy confinement time ratio",
+ "(taup/taueff)",
+ physics_variables.taup / physics_variables.taueff,
+ "OP ",
+ )
+ po.ovarrf(
+ self.outfile,
+ "Lower limit on taup/taueff",
+ "(taulimit)",
+ constraint_variables.taulimit,
+ )
+ po.ovarrf(
+ self.outfile,
+ "Total energy confinement time including radiation loss (s)",
+ "(total_energy_conf_time)",
+ physics_module.total_energy_conf_time,
+ "OP ",
+ )
+ po.ocmmnt(
+ self.outfile,
+ " (= stored energy including fast particles / loss power including radiation",
+ )
+
+ if stellarator_variables.istell == 0:
+ # Issues 363 Output dimensionless plasma parameters MDK
+ po.osubhd(self.outfile, "Dimensionless plasma parameters")
+ po.ocmmnt(self.outfile, "For definitions see")
+ po.ocmmnt(
+ self.outfile,
+ "Recent progress on the development and analysis of the ITPA global H-mode confinement database",
+ )
+ po.ocmmnt(
+ self.outfile,
+ "D.C. McDonald et al, 2007 Nuclear Fusion v47, 147. (nu_star missing 1/mu0)",
+ )
+ po.ovarre(
+ self.outfile,
+ "Normalized plasma pressure beta as defined by McDonald et al",
+ "(beta_mcdonald)",
+ physics_module.beta_mcdonald,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Normalized ion Larmor radius",
+ "(rho_star)",
+ physics_module.rho_star,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Normalized collisionality",
+ "(nu_star)",
+ physics_module.nu_star,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Volume measure of elongation",
+ "(kappaa_IPB)",
+ physics_variables.kappaa_ipb,
+ "OP ",
+ )
+
+ po.osubhd(self.outfile, "Plasma Volt-second Requirements :")
+ po.ovarre(
+ self.outfile,
+ "Total volt-second requirement (Wb)",
+ "(vsstt)",
+ physics_variables.vsstt,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Inductive volt-seconds (Wb)",
+ "(vsind)",
+ physics_variables.vsind,
+ "OP ",
+ )
+ po.ovarrf(
+ self.outfile, "Ejima coefficient", "(gamma)", physics_variables.gamma
+ )
+ po.ovarre(
+ self.outfile,
+ "Start-up resistive (Wb)",
+ "(vsres)",
+ physics_variables.vsres,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Flat-top resistive (Wb)",
+ "(vsbrn)",
+ physics_variables.vsbrn,
+ "OP ",
+ )
+
+ po.ovarrf(
+ self.outfile,
+ "bootstrap current fraction multiplier",
+ "(cboot)",
+ current_drive_variables.cboot,
+ )
+ po.ovarrf(
+ self.outfile,
+ "Bootstrap fraction (ITER 1989)",
+ "(bscf_iter89)",
+ current_drive_variables.bscf_iter89,
+ "OP ",
+ )
+
+ po.ovarrf(
+ self.outfile,
+ "Bootstrap fraction (Sauter et al)",
+ "(bscf_sauter)",
+ current_drive_variables.bscf_sauter,
+ "OP ",
+ )
+
+ po.ovarrf(
+ self.outfile,
+ "Bootstrap fraction (Nevins et al)",
+ "(bscf_nevins)",
+ current_drive_variables.bscf_nevins,
+ "OP ",
+ )
+ po.ovarrf(
+ self.outfile,
+ "Bootstrap fraction (Wilson)",
+ "(bscf_wilson)",
+ current_drive_variables.bscf_wilson,
+ "OP ",
+ )
+ po.ovarrf(
+ self.outfile,
+ "Diamagnetic fraction (Hender)",
+ "(diacf_hender)",
+ current_drive_variables.diacf_hender,
+ "OP ",
+ )
+ po.ovarrf(
+ self.outfile,
+ "Diamagnetic fraction (SCENE)",
+ "(diacf_scene)",
+ current_drive_variables.diacf_scene,
+ "OP ",
+ )
+ po.ovarrf(
+ self.outfile,
+ "Pfirsch-Schlueter fraction (SCENE)",
+ "(pscf_scene)",
+ current_drive_variables.pscf_scene,
+ "OP ",
+ )
+ # Error to catch if bootstap fraction limit has been enforced
+ if physics_module.err242 == 1:
+ error_handling.report_error(242)
+
+ # Error to catch if self-driven current fraction limit has been enforced
+ if physics_module.err243 == 1:
+ error_handling.report_error(243)
+
+ if current_drive_variables.bscfmax < 0.0e0:
+ po.ocmmnt(
+ self.outfile, " (User-specified bootstrap current fraction used)"
+ )
+ elif physics_variables.ibss == 1:
+ po.ocmmnt(
+ self.outfile, " (ITER 1989 bootstrap current fraction model used)"
+ )
+ elif physics_variables.ibss == 2:
+ po.ocmmnt(
+ self.outfile,
+ " (Nevins et al bootstrap current fraction model used)",
+ )
+ elif physics_variables.ibss == 3:
+ po.ocmmnt(
+ self.outfile, " (Wilson bootstrap current fraction model used)"
+ )
+ elif physics_variables.ibss == 4:
+ po.ocmmnt(
+ self.outfile,
+ " (Sauter et al bootstrap current fraction model used)",
+ )
+
+ if physics_variables.idia == 0:
+ po.ocmmnt(
+ self.outfile, " (Diamagnetic current fraction not calculated)"
+ )
+ # Error to show if diamagnetic current is above 1% but not used
+ if current_drive_variables.diacf_scene > 0.01e0:
+ error_handling.report_error(244)
+
+ elif physics_variables.idia == 1:
+ po.ocmmnt(
+ self.outfile, " (Hender diamagnetic current fraction scaling used)"
+ )
+ elif physics_variables.idia == 2:
+ po.ocmmnt(
+ self.outfile, " (SCENE diamagnetic current fraction scaling used)"
+ )
+
+ if physics_variables.ips == 0:
+ po.ocmmnt(
+ self.outfile, " Pfirsch-Schluter current fraction not calculated"
+ )
+ elif physics_variables.ips == 1:
+ po.ocmmnt(
+ self.outfile,
+ " (SCENE Pfirsch-Schluter current fraction scaling used)",
+ )
+
+ po.ovarrf(
+ self.outfile,
+ "Bootstrap fraction (enforced)",
+ "(bootipf.)",
+ current_drive_variables.bootipf,
+ "OP ",
+ )
+ po.ovarrf(
+ self.outfile,
+ "Diamagnetic fraction (enforced)",
+ "(diaipf.)",
+ current_drive_variables.diaipf,
+ "OP ",
+ )
+ po.ovarrf(
+ self.outfile,
+ "Pfirsch-Schlueter fraction (enforced)",
+ "(psipf.)",
+ current_drive_variables.psipf,
+ "OP ",
+ )
+
+ po.ovarre(
+ self.outfile,
+ "Loop voltage during burn (V)",
+ "(vburn)",
+ physics_variables.plascur
+ * physics_variables.rplas
+ * physics_variables.facoh,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Plasma resistance (ohm)",
+ "(rplas)",
+ physics_variables.rplas,
+ "OP ",
+ )
+
+ po.ovarre(
+ self.outfile,
+ "Resistive diffusion time (s)",
+ "(res_time)",
+ physics_variables.res_time,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Plasma inductance (H)",
+ "(rlp)",
+ physics_variables.rlp,
+ "OP ",
+ )
+ po.ovarrf(
+ self.outfile,
+ "Coefficient for sawtooth effects on burn V-s requirement",
+ "(csawth)",
+ physics_variables.csawth,
+ )
+
+ po.osubhd(self.outfile, "Fuelling :")
+ po.ovarre(
+ self.outfile,
+ "Ratio of He and pellet particle confinement times",
+ "(tauratio)",
+ physics_variables.tauratio,
+ )
+ po.ovarre(
+ self.outfile,
+ "Fuelling rate (nucleus-pairs/s)",
+ "(qfuel)",
+ physics_variables.qfuel,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Fuel burn-up rate (reactions/s)",
+ "(rndfuel)",
+ physics_variables.rndfuel,
+ "OP ",
+ )
+ po.ovarrf(
+ self.outfile,
+ "Burn-up fraction",
+ "(burnup)",
+ physics_variables.burnup,
+ "OP ",
+ )
+
+ if any(numerics.icc == 78):
+ po.osubhd(self.outfile, "Reinke Criterion :")
+ po.ovarin(
+ self.outfile,
+ "index of impurity to be iterated for divertor detachment",
+ "(impvardiv)",
+ reinke_variables.impvardiv,
+ )
+ po.ovarre(
+ self.outfile,
+ "Minimum Impurity fraction from Reinke",
+ "(fzmin)",
+ reinke_variables.fzmin,
+ "OP ",
+ )
+ po.ovarre(
+ self.outfile,
+ "Actual Impurity fraction",
+ "(fzactual)",
+ reinke_variables.fzactual,
+ )
+
+ def igmarcal(self):
+ """Routine to calculate ignition margin
+ author: P J Knight, CCFE, Culham Science Centre
+ outfile : input integer : Fortran output unit identifier
+ This routine calculates the ignition margin at the final point
+ with different scalings.
+ AEA FUS 251: A User's Guide to the PROCESS Systems Code
+ """
+
+ po.oheadr(self.outfile, "Energy confinement times, and required H-factors :")
+ po.ocmmnt(
+ self.outfile,
+ f"{'':>5}{'scaling law':<25}{'confinement time (s)':<25}H-factor for",
+ )
+ po.ocmmnt(
+ self.outfile,
+ f"{'':>34}{'for H = 1':<20}power balance",
+ )
+
+ for iisc in range(32, 48):
+ (
+ physics_variables.kappaa,
+ ptrez,
+ ptriz,
+ taueez,
+ taueiz,
+ taueffz,
+ powerhtz,
+ ) = self.pcond(
+ physics_variables.afuel,
+ physics_variables.palpmw,
+ physics_variables.aspect,
+ physics_variables.bt,
+ physics_variables.dnitot,
+ physics_variables.dene,
+ physics_variables.dnla,
+ physics_variables.eps,
+ 1.0,
+ physics_variables.iinvqd,
+ iisc,
+ physics_variables.ignite,
+ physics_variables.kappa,
+ physics_variables.kappa95,
+ physics_variables.pchargemw,
+ current_drive_variables.pinjmw,
+ physics_variables.plascur,
+ physics_variables.pcoreradpv,
+ physics_variables.rmajor,
+ physics_variables.rminor,
+ physics_variables.te,
+ physics_variables.ten,
+ physics_variables.tin,
+ physics_variables.q,
+ physics_variables.qstar,
+ physics_variables.vol,
+ physics_variables.xarea,
+ physics_variables.zeff,
+ )
+
+ physics_variables.hfac[iisc - 1] = self.fhfac(iisc)
+
+ po.ocmmnt(
+ self.outfile,
+ f"{'':>2}{f2py_compatible_to_string(physics_variables.tauscl[iisc-1]):<32}"
+ f"{taueez:<26.3f}{physics_variables.hfac[iisc - 1]:.3f}",
+ )
+
+ def fhfac(self, is_):
+ """Function to find H-factor for power balance
+ author: P J Knight, CCFE, Culham Science Centre
+ is : input integer : confinement time scaling law of interest
+ This function calculates the H-factor required for power balance,
+ using the given energy confinement scaling law.
+ AEA FUS 251: A User's Guide to the PROCESS Systems Code
+ """
+ physics_module.iscz = is_
+
+ return root_scalar(self.fhz, bracket=(0.01, 100), xtol=0.003).root
+
+ def fhz(self, hhh):
+ """Function used to find power balance
+ author: P J Knight, CCFE, Culham Science Centre
+ hhh : input real : test value for confinement time H-factor
+ This function is used to find power balance.
+ FHZ is zero at power balance, which is achieved
+ using routine ZEROIN to adjust the
+ value of hhh, the confinement time H-factor.
+ AEA FUS 251: A User's Guide to the PROCESS Systems Code
+ """
+ (
+ physics_variables.kappaa,
+ ptrez,
+ ptriz,
+ taueezz,
+ taueiz,
+ taueffz,
+ powerhtz,
+ ) = self.pcond(
+ physics_variables.afuel,
+ physics_variables.palpmw,
+ physics_variables.aspect,
+ physics_variables.bt,
+ physics_variables.dnitot,
+ physics_variables.dene,
+ physics_variables.dnla,
+ physics_variables.eps,
+ hhh,
+ physics_variables.iinvqd,
+ physics_module.iscz,
+ physics_variables.ignite,
+ physics_variables.kappa,
+ physics_variables.kappa95,
+ physics_variables.pchargemw,
+ current_drive_variables.pinjmw,
+ physics_variables.plascur,
+ physics_variables.pcoreradpv,
+ physics_variables.rmajor,
+ physics_variables.rminor,
+ physics_variables.te,
+ physics_variables.ten,
+ physics_variables.tin,
+ physics_variables.q,
+ physics_variables.qstar,
+ physics_variables.vol,
+ physics_variables.xarea,
+ physics_variables.zeff,
+ )
+
+ # At power balance, fhz is zero.
+
+ fhz = (
+ ptrez
+ + ptriz
+ - physics_variables.falpha * physics_variables.palppv
+ - physics_variables.pchargepv
+ - physics_variables.pohmpv
+ )
+
+ # Take into account whether injected power is included in tau_e
+ # calculation (i.e. whether device is ignited)
+
+ if physics_variables.ignite == 0:
+ fhz = fhz - current_drive_variables.pinjmw / physics_variables.vol
+
+ # Include the radiation power if requested
+
+ if physics_variables.iradloss == 0:
+ fhz = fhz + physics_variables.pradpv
+ elif physics_variables.iradloss == 1:
+ fhz = fhz + physics_variables.pcoreradpv
+
+ return fhz
+
+ def pcond(
+ self,
+ afuel,
+ palpmw,
+ aspect,
+ bt,
+ dnitot,
+ dene,
+ dnla,
+ eps,
+ hfact,
+ iinvqd,
+ isc,
+ ignite,
+ kappa,
+ kappa95,
+ pchargemw,
+ pinjmw,
+ plascur,
+ pcoreradpv,
+ rmajor,
+ rminor,
+ te,
+ ten,
+ tin,
+ q,
+ qstar,
+ vol,
+ xarea,
+ zeff,
+ ):
+ """Routine to calculate the confinement times and
+ the transport power loss terms.
+ author: P J Knight, CCFE, Culham Science Centre
+ afuel : input real : average mass of fuel (amu)
+ palpmw : input real : alpha particle power (MW)
+ aspect : input real : aspect ratio
+ bt : input real : toroidal field on axis (T)
+ dene : input real : volume averaged electron density (/m3)
+ dnitot : input real : total ion density (/m3)
+ dnla : input real : line-averaged electron density (/m3)
+ eps : input real : inverse aspect ratio
+ hfact : input real : H factor on energy confinement scalings
+ iinvqd : input integer : switch for inverse quadrature
+ isc : input integer : switch for energy confinement scaling to use
+ ignite : input integer : switch for ignited calculation
+ kappa : input real : plasma elongation
+ kappa95 : input real : plasma elongation at 95% surface
+ kappaa : output real : plasma elongation calculated using area ratio
+ pchargemw : input real : non-alpha charged particle fusion power (MW)
+ pinjmw : input real : auxiliary power to ions and electrons (MW)
+ plascur : input real : plasma current (A)
+ pcoreradpv: input real : total core radiation power (MW/m3)
+ q : input real : edge safety factor (tokamaks), or
+ rotational transform iotabar (stellarators)
+ qstar : input real : equivalent cylindrical edge safety factor
+ rmajor : input real : plasma major radius (m)
+ rminor : input real : plasma minor radius (m)
+ te : input real : average electron temperature (keV)
+ ten : input real : density weighted average electron temp. (keV)
+ tin : input real : density weighted average ion temperature (keV)
+ vol : input real : plasma volume (m3)
+ xarea : input real : plasma cross-sectional area (m2)
+ zeff : input real : plasma effective charge
+ ptrepv : output real : electron transport power (MW/m3)
+ ptripv : output real : ion transport power (MW/m3)
+ tauee : output real : electron energy confinement time (s)
+ taueff : output real : global energy confinement time (s)
+ tauei : output real : ion energy confinement time (s)
+ powerht : output real : heating power (MW) assumed in calculation
+ This subroutine calculates the energy confinement time
+ using one of a large number of scaling laws, and the
+ transport power loss terms.
+ AEA FUS 251: A User's Guide to the PROCESS Systems Code
+ N. A. Uckan and ITER Physics Group,
+ "ITER Physics Design Guidelines: 1989",
+ ITER Documentation Series, No. 10, IAEA/ITER/DS/10 (1990)
+ ITER Documentation Series, No. 10, IAEA/ITER/DS/10 (1990)
+ A. Murari et al 2015 Nucl. Fusion, 55, 073009
+ C.C. Petty 2008 Phys. Plasmas, 15, 080501
+ P.T. Lang et al. 2012 IAEA conference proceeding EX/P4-01
+ ITER physics basis Chapter 2, 1999 Nuclear Fusion 39 2175
+ Nuclear Fusion corrections, 2008 Nuclear Fusion 48 099801
+ Menard 2019, Phil. Trans. R. Soc. A 377:20170440
+ Kaye et al. 2006, Nucl. Fusion 46 848
+ """
+ eps2 = eps / 2.0e0
+ str5 = 2.0e0 / (1.0e0 + (kappa**2))
+ ck2 = (0.66e0 + (1.88e0 * (np.sqrt(eps2))) - (1.54e0 * eps2)) * (
+ 1.0e0 + (1.5e0 * (eps2**2))
+ )
+ chii = (
+ (6.5e-22)
+ * ck2
+ * zeff
+ * (aspect**1.5e0)
+ * dene
+ * (q**2)
+ * str5
+ / ((np.sqrt(tin)) * (bt**2))
+ )
+ str2 = 2.0e0 * (kappa**2) / (1.0e0 + (kappa**2))
+ tauei = 0.375e0 * rminor**2 / chii * str2
+
+ # Calculate heating power (MW)
+ powerht = (
+ physics_variables.falpha * palpmw + pchargemw + physics_variables.pohmmw
+ )
+
+ # If the device is not ignited, add the injected auxiliary power
+ if ignite == 0:
+ powerht = powerht + pinjmw
+
+ # Include the radiation as a loss term if requested
+ if physics_variables.iradloss == 0:
+ powerht = powerht - physics_variables.pradpv * vol
+ elif physics_variables.iradloss == 1:
+ powerht = (
+ powerht - pcoreradpv * vol
+ ) # shouldn't this be vol_core instead of vol?
+ # else do not adjust powerht for radiation
+
+ # Ensure heating power is positive (shouldn't be necessary)
+ powerht = max(powerht, 1.0e-3)
+
+ # Line averaged electron density in scaled units
+ dnla20 = dnla * 1.0e-20
+ dnla19 = dnla * 1.0e-19
+
+ # Volume averaged electron density in units of 10**20 m**-3
+ n20 = dene / 1.0e20
+
+ # Plasma current in MA
+ pcur = plascur / 1.0e6
+
+ # Separatrix kappa defined with X-section for general use
+ kappaa = xarea / (np.pi * rminor * rminor)
+
+ # Separatrix kappa defined with plasma volume for IPB scalings
+ physics_variables.kappaa_ipb = vol / (
+ 2.0e0 * np.pi**2 * rminor * rminor * rmajor
+ )
+
+ # Calculate Neo-Alcator confinement time (used in several scalings)
+ taueena = 0.07e0 * n20 * rminor * rmajor * rmajor * qstar
+
+ # For reference (see startup.f90):
+ # startup_variables.gtaue = offset term in tauee scaling
+ # startup_variables.ptaue = exponent for density term in tauee scaling
+ # startup_variables.qtaue = exponent for temperature term in tauee scaling
+ # startup_variables.rtaue = exponent for power term in tauee scaling
+
+ # Electron energy confinement times
+
+ if isc == 1: # Neo-Alcator scaling (ohmic)
+ # tauee = taueena
+ tauee = hfact * taueena
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 1.0e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = 0.0e0
+
+ elif isc == 2: # Mirnov scaling (H-mode)
+ tauee = hfact * 0.2e0 * rminor * np.sqrt(kappa95) * pcur
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 0.0e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = 0.0e0
+
+ elif isc == 3: # Merezhkin-Muhkovatov scaling (L-mode)
+ tauee = (
+ hfact
+ * 3.5e-3
+ * rmajor**2.75e0
+ * rminor**0.25e0
+ * kappa95**0.125e0
+ * qstar
+ * dnla20
+ * np.sqrt(afuel)
+ / np.sqrt(ten / 10.0e0)
+ )
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 1.0e0
+ startup_variables.qtaue = -0.5e0
+ startup_variables.rtaue = 0.0e0
+
+ elif isc == 4: # Shimomura scaling (H-mode)
+ tauee = (
+ hfact
+ * 0.045e0
+ * rmajor
+ * rminor
+ * bt
+ * np.sqrt(kappa95)
+ * np.sqrt(afuel)
+ )
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 0.0e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = 0.0e0
+
+ elif isc == 5: # Kaye-Goldston scaling (L-mode)
+ tauee = (
+ hfact
+ * 0.055e0
+ * kappa95**0.28e0
+ * pcur**1.24e0
+ * n20**0.26e0
+ * rmajor**1.65e0
+ * np.sqrt(afuel / 1.5e0)
+ / (bt**0.09e0 * rminor**0.49e0 * powerht**0.58e0)
+ )
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 0.26e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -0.58e0
+ if iinvqd != 0:
+ tauee = 1.0e0 / np.sqrt(1.0e0 / taueena**2 + 1.0e0 / tauee**2)
+
+ elif isc == 6: # ITER Power scaling - ITER 89-P (L-mode)
+ tauee = (
+ hfact
+ * 0.048e0
+ * pcur**0.85e0
+ * rmajor**1.2e0
+ * rminor**0.3e0
+ * np.sqrt(kappa)
+ * dnla20**0.1e0
+ * bt**0.2e0
+ * np.sqrt(afuel)
+ / np.sqrt(powerht)
+ )
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 0.1e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -0.5e0
+
+ elif isc == 7: # ITER Offset linear scaling - ITER 89-O (L-mode)
+ term1 = (
+ 0.04e0
+ * pcur**0.5e0
+ * rmajor**0.3e0
+ * rminor**0.8e0
+ * kappa**0.6e0
+ * afuel**0.5e0
+ )
+ term2 = (
+ 0.064e0
+ * pcur**0.8e0
+ * rmajor**1.6e0
+ * rminor**0.6e0
+ * kappa**0.5e0
+ * dnla20**0.6e0
+ * bt**0.35e0
+ * afuel**0.2e0
+ / powerht
+ )
+ tauee = hfact * (term1 + term2)
+ startup_variables.gtaue = hfact * term1
+ startup_variables.ptaue = 0.6e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -1.0e0
+
+ elif isc == 8: # Rebut-Lallia offset linear scaling (L-mode)
+ rll = (rminor**2 * rmajor * kappa95) ** 0.333e0
+ tauee = (
+ hfact
+ * 1.65e0
+ * np.sqrt(afuel / 2.0e0)
+ * (
+ 1.2e-2 * pcur * rll**1.5e0 / np.sqrt(zeff)
+ + 0.146e0
+ * dnla20**0.75e0
+ * np.sqrt(pcur)
+ * np.sqrt(bt)
+ * rll**2.75e0
+ * zeff**0.25e0
+ / powerht
+ )
+ )
+ startup_variables.gtaue = (
+ hfact
+ * 1.65e0
+ * np.sqrt(afuel / 2.0e0)
+ * (1.2e-2 * pcur * rll**1.5e0 / np.sqrt(zeff))
+ )
+ startup_variables.ptaue = 0.75e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -1.0e0
+
+ elif isc == 9: # Goldston scaling (L-mode)
+ tauee = (
+ hfact
+ * 0.037e0
+ * pcur
+ * rmajor**1.75e0
+ * rminor ** (-0.37e0)
+ * np.sqrt(kappa95)
+ * np.sqrt(afuel / 1.5e0)
+ / np.sqrt(powerht)
+ )
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 0.0e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -0.5e0
+ if iinvqd != 0:
+ tauee = 1.0e0 / np.sqrt(1.0e0 / taueena**2 + 1.0e0 / tauee**2)
+
+ elif isc == 10: # T10 scaling
+ denfac = dnla20 * rmajor * qstar / (1.3e0 * bt)
+ denfac = min(1.0e0, denfac)
+ tauee = (
+ hfact
+ * 0.095e0
+ * rmajor
+ * rminor
+ * bt
+ * np.sqrt(kappa95)
+ * denfac
+ / powerht**0.4e0
+ * (
+ zeff**2
+ * pcur**4
+ / (rmajor * rminor * qstar**3 * kappa95**1.5e0)
+ )
+ ** 0.08e0
+ )
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 1.0e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -0.4e0
+
+ elif isc == 11: # JAERI scaling
+ gjaeri = (
+ zeff**0.4e0
+ * ((15.0e0 - zeff) / 20.0e0) ** 0.6e0
+ * (
+ 3.0e0
+ * qstar
+ * (qstar + 5.0e0)
+ / ((qstar + 2.0e0) * (qstar + 7.0e0))
+ )
+ ** 0.6e0
+ )
+ tauee = hfact * (
+ 0.085e0 * kappa95 * rminor**2 * np.sqrt(afuel)
+ + 0.069e0
+ * n20**0.6e0
+ * pcur
+ * bt**0.2e0
+ * rminor**0.4e0
+ * rmajor**1.6e0
+ * np.sqrt(afuel)
+ * gjaeri
+ * kappa95**0.2e0
+ / powerht
+ )
+ startup_variables.gtaue = (
+ hfact * 0.085e0 * kappa95 * rminor**2 * np.sqrt(afuel)
+ )
+ startup_variables.ptaue = 0.6e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -1.0e0
+
+ elif isc == 12: # Kaye-Big scaling
+ tauee = (
+ hfact
+ * 0.105e0
+ * np.sqrt(rmajor)
+ * rminor**0.8e0
+ * bt**0.3e0
+ * kappa95**0.25e0
+ * pcur**0.85e0
+ * n20**0.1e0
+ * afuel**0.5e0
+ / powerht**0.5e0
+ )
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 0.1e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -0.5e0
+
+ elif isc == 13: # ITER H-mode scaling - ITER H90-P
+ tauee = (
+ hfact
+ * 0.064e0
+ * pcur**0.87e0
+ * rmajor**1.82e0
+ * rminor ** (-0.12e0)
+ * kappa**0.35e0
+ * dnla20**0.09e0
+ * bt**0.15e0
+ * np.sqrt(afuel)
+ / np.sqrt(powerht)
+ )
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 0.09e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -0.5e0
+
+ elif isc == 14: # Minimum of ITER 89-P (isc=6) and ITER 89-O (isc=7)
+ tauit1 = (
+ hfact
+ * 0.048e0
+ * pcur**0.85e0
+ * rmajor**1.2e0
+ * rminor**0.3e0
+ * np.sqrt(kappa)
+ * dnla20**0.1e0
+ * bt**0.2e0
+ * np.sqrt(afuel)
+ / np.sqrt(powerht)
+ )
+ term1 = (
+ 0.04e0
+ * pcur**0.5e0
+ * rmajor**0.3e0
+ * rminor**0.8e0
+ * kappa**0.6e0
+ * afuel**0.5e0
+ )
+ term2 = (
+ 0.064e0
+ * pcur**0.8e0
+ * rmajor**1.6e0
+ * rminor**0.6e0
+ * kappa**0.5e0
+ * dnla20**0.6e0
+ * bt**0.35e0
+ * afuel**0.2e0
+ / powerht
+ )
+ tauit2 = hfact * (term1 + term2)
+ tauee = min(tauit1, tauit2)
+
+ if tauit1 < tauit2:
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 0.1e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -0.5e0
+ else:
+ startup_variables.gtaue = hfact * term1
+ startup_variables.ptaue = 0.6e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -1.0e0
+
+ elif isc == 15: # Riedel scaling (L-mode)
+ tauee = (
+ hfact
+ * 0.044e0
+ * pcur**0.93e0
+ * rmajor**1.37e0
+ * rminor ** (-0.049e0)
+ * kappa95**0.588e0
+ * dnla20**0.078e0
+ * bt**0.152e0
+ / powerht**0.537e0
+ )
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 0.078e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -0.537e0
+
+ elif isc == 16: # Christiansen et al scaling (L-mode)
+ tauee = (
+ hfact
+ * 0.24e0
+ * pcur**0.79e0
+ * rmajor**0.56e0
+ * rminor**1.46e0
+ * kappa95**0.73e0
+ * dnla20**0.41e0
+ * bt**0.29e0
+ / (powerht**0.79e0 * afuel**0.02e0)
+ )
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 0.41e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -0.79e0
+
+ elif isc == 17: # Lackner-Gottardi scaling (L-mode)
+ qhat = (1.0e0 + kappa95**2) * rminor**2 * bt / (0.4e0 * pcur * rmajor)
+ tauee = (
+ hfact
+ * 0.12e0
+ * pcur**0.8e0
+ * rmajor**1.8e0
+ * rminor**0.4e0
+ * kappa95
+ * (1.0e0 + kappa95) ** (-0.8e0)
+ * dnla20**0.6e0
+ * qhat**0.4e0
+ / powerht**0.6e0
+ )
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 0.6e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -0.6e0
+
+ elif isc == 18: # Neo-Kaye scaling (L-mode)
+ tauee = (
+ hfact
+ * 0.063e0
+ * pcur**1.12e0
+ * rmajor**1.3e0
+ * rminor ** (-0.04e0)
+ * kappa95**0.28e0
+ * dnla20**0.14e0
+ * bt**0.04e0
+ * np.sqrt(afuel)
+ / powerht**0.59e0
+ )
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 0.14e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -0.59e0
+
+ elif isc == 19: # Riedel scaling (H-mode)
+ tauee = (
+ hfact
+ * 0.1e0
+ * np.sqrt(afuel)
+ * pcur**0.884e0
+ * rmajor**1.24e0
+ * rminor ** (-0.23e0)
+ * kappa95**0.317e0
+ * bt**0.207e0
+ * dnla20**0.105e0
+ / powerht**0.486e0
+ )
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 0.105e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -0.486e0
+
+ elif isc == 20: # Amended version of ITER H90-P law
+ # Nuclear Fusion 32 (1992) 318
+ tauee = (
+ hfact
+ * 0.082e0
+ * pcur**1.02e0
+ * bt**0.15e0
+ * np.sqrt(afuel)
+ * rmajor**1.60e0
+ / (powerht**0.47e0 * kappa**0.19e0)
+ )
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 0.0e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -0.47e0
+
+ elif isc == 21: # Large Helical Device scaling (stellarators)
+ # S.Sudo, Y.Takeiri, H.Zushi et al., Nuclear Fusion 30 (1990) 11
+ tauee = (
+ hfact
+ * 0.17e0
+ * rmajor**0.75e0
+ * rminor**2
+ * dnla20**0.69e0
+ * bt**0.84e0
+ * powerht ** (-0.58e0)
+ )
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 0.69e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = 0.58e0
+
+ elif isc == 22: # Gyro-reduced Bohm scaling
+ # R.J.Goldston, H.Biglari, G.W.Hammett et al., Bull.Am.Phys.Society,
+ # volume 34, 1964 (1989)
+ tauee = (
+ hfact
+ * 0.25e0
+ * bt**0.8e0
+ * dnla20**0.6e0
+ * powerht ** (-0.6e0)
+ * rminor**2.4e0
+ * rmajor**0.6e0
+ )
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 0.6e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -0.6e0
+
+ elif isc == 23: # Lackner-Gottardi stellarator scaling
+ # K.Lackner and N.A.O.Gottardi, Nuclear Fusion, 30, p.767 (1990)
+ iotabar = q # dummy argument q is actual argument iotabar for stellarators
+ tauee = (
+ hfact
+ * 0.17e0
+ * rmajor
+ * rminor**2
+ * dnla20**0.6e0
+ * bt**0.8e0
+ * powerht ** (-0.6e0)
+ * iotabar**0.4e0
+ )
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 0.6e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -0.6e0
+
+ elif (
+ isc == 24
+ ): # ITER-93H scaling (ELM-free; multiply by 0.85 for ELMy version)
+ # S.Kaye and the ITER Joint Central Team and Home Teams, in Plasma
+ # Physics and Controlled Nuclear Fusion Research (Proc. 15th
+ # Int. Conf., Seville, 1994) IAEA-CN-60/E-P-3
+ tauee = (
+ hfact
+ * 0.053e0
+ * pcur**1.06e0
+ * bt**0.32e0
+ * powerht ** (-0.67e0)
+ * afuel**0.41e0
+ * rmajor**1.79e0
+ * dnla20**0.17e0
+ * aspect**0.11e0
+ * kappa**0.66e0
+ )
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 0.17e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -0.67e0
+
+ # Next two are ITER-97 H-mode scalings
+ # J. G. Cordey et al., EPS Berchtesgaden, 1997
+
+ elif isc == 26: # ELM-free: ITERH-97P
+ tauee = (
+ hfact
+ * 0.031e0
+ * pcur**0.95e0
+ * bt**0.25e0
+ * powerht ** (-0.67e0)
+ * dnla19**0.35e0
+ * rmajor**1.92e0
+ * aspect ** (-0.08e0)
+ * kappa**0.63e0
+ * afuel**0.42e0
+ )
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 0.35e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -0.67e0
+
+ elif isc == 27: # ELMy: ITERH-97P(y)
+ tauee = (
+ hfact
+ * 0.029e0
+ * pcur**0.90e0
+ * bt**0.20e0
+ * powerht ** (-0.66e0)
+ * dnla19**0.40e0
+ * rmajor**2.03e0
+ * aspect ** (-0.19e0)
+ * kappa**0.92e0
+ * afuel**0.2e0
+ )
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 0.4e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -0.66e0
+
+ elif isc == 28: # ITER-96P (= ITER-97L) L-mode scaling
+ # S.M.Kaye and the ITER Confinement Database Working Group,
+ # Nuclear Fusion 37 (1997) 1303
+ # N.B. tau_th formula used
+ tauee = (
+ hfact
+ * 0.023e0
+ * pcur**0.96e0
+ * bt**0.03e0
+ * kappa95**0.64e0
+ * rmajor**1.83e0
+ * aspect**0.06e0
+ * dnla19**0.40e0
+ * afuel**0.20e0
+ * powerht ** (-0.73e0)
+ )
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 0.4e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -0.73e0
+
+ elif isc == 29: # Valovic modified ELMy-H mode scaling
+ tauee = (
+ hfact
+ * 0.067e0
+ * pcur**0.9e0
+ * bt**0.17e0
+ * dnla19**0.45e0
+ * afuel**0.05e0
+ * rmajor**1.316e0
+ * rminor**0.79e0
+ * kappa**0.56e0
+ * powerht ** (-0.68e0)
+ )
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 0.45e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -0.68e0
+
+ elif isc == 30: # Kaye PPPL Workshop April 1998 L-mode scaling
+ tauee = (
+ hfact
+ * 0.021e0
+ * pcur**0.81e0
+ * bt**0.14e0
+ * kappa**0.7e0
+ * rmajor**2.01e0
+ * aspect ** (-0.18e0)
+ * dnla19**0.47e0
+ * afuel**0.25e0
+ * powerht ** (-0.73e0)
+ )
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 0.47e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -0.73e0
+
+ elif isc == 31: # ITERH-PB98P(y), ELMy H-mode scaling
+ tauee = (
+ hfact
+ * 0.0615e0
+ * pcur**0.9e0
+ * bt**0.1e0
+ * dnla19**0.4e0
+ * powerht ** (-0.66e0)
+ * rmajor**2
+ * kappaa**0.75e0
+ * aspect ** (-0.66e0)
+ * afuel**0.2e0
+ )
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 0.4e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -0.66e0
+
+ elif isc == 32: # IPB98(y), ELMy H-mode scaling
+ # Data selection : full ITERH.DB3
+ # Nuclear Fusion 39 (1999) 2175, Table 5
+ tauee = (
+ hfact
+ * 0.0365e0
+ * pcur**0.97e0
+ * bt**0.08e0
+ * dnla19**0.41e0
+ * powerht ** (-0.63e0)
+ * rmajor**1.93e0
+ * kappa**0.67e0
+ * aspect ** (-0.23e0)
+ * afuel**0.2e0
+ )
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 0.41e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -0.63e0
+
+ elif isc == 33: # IPB98(y,1), ELMy H-mode scaling
+ # Data selection : full ITERH.DB3
+ # Nuclear Fusion 39 (1999) 2175, Table 5
+ tauee = (
+ hfact
+ * 0.0503e0
+ * pcur**0.91e0
+ * bt**0.15e0
+ * dnla19**0.44e0
+ * powerht ** (-0.65e0)
+ * rmajor**2.05e0
+ * physics_variables.kappaa_ipb**0.72e0
+ * aspect ** (-0.57e0)
+ * afuel**0.13e0
+ )
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 0.44e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -0.65e0
+
+ elif isc == 34: # IPB98(y,2), ELMy H-mode scaling
+ # Data selection : ITERH.DB3, NBI only
+ # Nuclear Fusion 39 (1999) 2175, Table 5
+ tauee = (
+ hfact
+ * 0.0562e0
+ * pcur**0.93e0
+ * bt**0.15e0
+ * dnla19**0.41e0
+ * powerht ** (-0.69e0)
+ * rmajor**1.97e0
+ * physics_variables.kappaa_ipb**0.78e0
+ * aspect ** (-0.58e0)
+ * afuel**0.19e0
+ )
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 0.41e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -0.69e0
+
+ elif isc == 35: # IPB98(y,3), ELMy H-mode scaling
+ # Data selection : ITERH.DB3, NBI only, no C-Mod
+ # Nuclear Fusion 39 (1999) 2175, Table 5
+ tauee = (
+ hfact
+ * 0.0564e0
+ * pcur**0.88e0
+ * bt**0.07e0
+ * dnla19**0.40e0
+ * powerht ** (-0.69e0)
+ * rmajor**2.15e0
+ * physics_variables.kappaa_ipb**0.78e0
+ * aspect ** (-0.64e0)
+ * afuel**0.20e0
+ )
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 0.4e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -0.69e0
+
+ elif isc == 36: # IPB98(y,4), ELMy H-mode scaling
+ # Data selection : ITERH.DB3, NBI only, ITER like devices
+ # Nuclear Fusion 39 (1999) 2175, Table 5
+ tauee = (
+ hfact
+ * 0.0587e0
+ * pcur**0.85e0
+ * bt**0.29e0
+ * dnla19**0.39e0
+ * powerht ** (-0.70e0)
+ * rmajor**2.08e0
+ * physics_variables.kappaa_ipb**0.76e0
+ * aspect ** (-0.69e0)
+ * afuel**0.17e0
+ )
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 0.39e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -0.70e0
+
+ elif isc == 37: # ISS95 stellarator scaling
+ # U. Stroth et al., Nuclear Fusion, 36, p.1063 (1996)
+ # Assumes kappa = 1.0, triang = 0.0
+ iotabar = q # dummy argument q is actual argument iotabar for stellarators
+ tauee = (
+ hfact
+ * 0.079e0
+ * rminor**2.21e0
+ * rmajor**0.65e0
+ * dnla19**0.51e0
+ * bt**0.83e0
+ * powerht ** (-0.59e0)
+ * iotabar**0.4e0
+ )
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 0.51e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -0.59e0
+
+ elif isc == 38: # ISS04 stellarator scaling
+ # H. Yamada et al., Nuclear Fusion, 45, p.1684 (2005)
+ # Assumes kappa = 1.0, triang = 0.0
+ iotabar = q # dummy argument q is actual argument iotabar for stellarators
+ tauee = (
+ hfact
+ * 0.134e0
+ * rminor**2.28e0
+ * rmajor**0.64e0
+ * dnla19**0.54e0
+ * bt**0.84e0
+ * powerht ** (-0.61e0)
+ * iotabar**0.41e0
+ )
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 0.54e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -0.61e0
+
+ elif isc == 39: # DS03 beta-independent H-mode scaling
+ # T. C. Luce, C. C. Petty and J. G. Cordey,
+ # Plasma Phys. Control. Fusion 50 (2008) 043001, eqn.4.13, p.67
+ tauee = (
+ hfact
+ * 0.028e0
+ * pcur**0.83e0
+ * bt**0.07e0
+ * dnla19**0.49e0
+ * powerht ** (-0.55e0)
+ * rmajor**2.11e0
+ * kappa95**0.75e0
+ * aspect ** (-0.3e0)
+ * afuel**0.14e0
+ )
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 0.49e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -0.55e0
+
+ elif isc == 40: # "Non-power law" (NPL) Murari energy confinement scaling
+ # Based on the ITPA database of H-mode discharges
+ # A new approach to the formulation and validation of scaling expressions for plasma confinement in tokamaks
+ # A. Murari et al 2015 Nucl. Fusion 55 073009, doi:10.1088/0029-5515/55/7/073009
+ # Table 4. (Issue #311)
+ # Note that aspect ratio and M (afuel) do not appear, and B (bt) only
+ # appears in the "saturation factor" h.
+ h = dnla19**0.448e0 / (
+ 1.0e0 + np.exp(-9.403e0 * (bt / dnla19) ** 1.365e0)
+ )
+ tauee = (
+ hfact
+ * 0.0367e0
+ * pcur**1.006e0
+ * rmajor**1.731e0
+ * kappaa**1.450e0
+ * powerht ** (-0.735e0)
+ * h
+ )
+
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 0.448e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -0.735e0
+
+ elif isc == 41: # Beta independent dimensionless confinement scaling
+ # C.C. Petty 2008 Phys. Plasmas 15, 080501, equation 36
+ # Note that there is no dependence on the average fuel mass 'afuel'
+ tauee = (
+ hfact
+ * 0.052e0
+ * pcur**0.75e0
+ * bt**0.3e0
+ * dnla19**0.32e0
+ * powerht ** (-0.47e0)
+ * rmajor**2.09e0
+ * kappaa**0.88e0
+ * aspect ** (-0.84e0)
+ )
+
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 0.32e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -0.47e0
+
+ elif isc == 42: # High density relevant confinement scaling
+ # P.T. Lang et al. 2012, IAEA conference proceeding EX/P4-01
+ # q should be q95: incorrect if icurr = 2 (ST current scaling)
+ qratio = q / qstar
+ # Greenwald density in m^-3
+ nGW = 1.0e14 * plascur / (np.pi * rminor * rminor)
+ nratio = dnla / nGW
+ tauee = (
+ hfact
+ * 6.94e-7
+ * plascur**1.3678e0
+ * bt**0.12e0
+ * dnla**0.032236e0
+ * (powerht * 1.0e6) ** (-0.74e0)
+ * rmajor**1.2345e0
+ * physics_variables.kappaa_ipb**0.37e0
+ * aspect**2.48205e0
+ * afuel**0.2e0
+ * qratio**0.77e0
+ * aspect ** (-0.9e0 * np.log(aspect))
+ * nratio ** (-0.22e0 * np.log(nratio))
+ )
+
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 0.032236e0 - 0.22e0 * np.log(nratio)
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -0.74e0
+
+ elif isc == 43: # Hubbard et al. 2017 I-mode confinement time scaling - nominal
+ tauee = (
+ hfact
+ * 0.014e0
+ * (plascur / 1.0e6) ** 0.68e0
+ * bt**0.77e0
+ * dnla20**0.02e0
+ * powerht ** (-0.29e0)
+ )
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 0.02e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -0.29e0
+
+ elif isc == 44: # Hubbard et al. 2017 I-mode confinement time scaling - lower
+ tauee = (
+ hfact
+ * 0.014e0
+ * (plascur / 1.0e6) ** 0.60e0
+ * bt**0.70e0
+ * dnla20 ** (-0.03e0)
+ * powerht ** (-0.33e0)
+ )
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = -0.03e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -0.33e0
+
+ elif isc == 45: # Hubbard et al. 2017 I-mode confinement time scaling - upper
+ tauee = (
+ hfact
+ * 0.014e0
+ * (plascur / 1.0e6) ** 0.76e0
+ * bt**0.84e0
+ * dnla20**0.07
+ * powerht ** (-0.25e0)
+ )
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 0.07e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -0.25e0
+
+ elif isc == 46: # NSTX, ELMy H-mode scaling
+ # NSTX scaling with IPB98(y,2) for other variables
+ # Menard 2019, Phil. Trans. R. Soc. A 377:20170440
+ # Kaye et al. 2006, Nucl. Fusion 46 848
+ tauee = (
+ hfact
+ * 0.095e0
+ * pcur**0.57e0
+ * bt**1.08e0
+ * dnla19**0.44e0
+ * powerht ** (-0.73e0)
+ * rmajor**1.97e0
+ * physics_variables.kappaa_ipb**0.78e0
+ * aspect ** (-0.58e0)
+ * afuel**0.19e0
+ )
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 0.44e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -0.73e0
+
+ elif isc == 47: # NSTX-Petty08 Hybrid
+ # Linear interpolation between NSTX and Petty08 in eps
+ # Menard 2019, Phil. Trans. R. Soc. A 377:20170440
+ if (1.0e0 / aspect) <= 0.4e0:
+ # Petty08, i.e. case (41)
+ tauee = (
+ hfact
+ * 0.052e0
+ * pcur**0.75e0
+ * bt**0.3e0
+ * dnla19**0.32e0
+ * powerht ** (-0.47e0)
+ * rmajor**2.09e0
+ * kappaa**0.88e0
+ * aspect ** (-0.84e0)
+ )
+
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 0.32e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -0.47e0
+
+ elif (1.0e0 / aspect) >= 0.6e0:
+ # NSTX, i.e.case (46)
+ tauee = (
+ hfact
+ * 0.095e0
+ * pcur**0.57e0
+ * bt**1.08e0
+ * dnla19**0.44e0
+ * powerht ** (-0.73e0)
+ * rmajor**1.97e0
+ * physics_variables.kappaa_ipb**0.78e0
+ * aspect ** (-0.58e0)
+ * afuel**0.19e0
+ )
+
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 0.44e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -0.73e0
+
+ else:
+ taupetty = (
+ 0.052e0
+ * pcur**0.75e0
+ * bt**0.3e0
+ * dnla19**0.32e0
+ * powerht ** (-0.47e0)
+ * rmajor**2.09e0
+ * kappaa**0.88e0
+ * aspect ** (-0.84e0)
+ )
+ taunstx = (
+ 0.095e0
+ * pcur**0.57e0
+ * bt**1.08e0
+ * dnla19**0.44e0
+ * powerht ** (-0.73e0)
+ * rmajor**1.97e0
+ * physics_variables.kappaa_ipb**0.78e0
+ * aspect ** (-0.58e0)
+ * afuel**0.19e0
+ )
+
+ tauee = hfact * (
+ (((1.0e0 / aspect) - 0.4e0) / (0.6e0 - 0.4e0)) * taunstx
+ + ((0.6e0 - (1.0e0 / aspect)) / (0.6e0 - 0.4e0)) * taupetty
+ )
+
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = (
+ ((1.0e0 / aspect) - 0.4e0) / (0.6e0 - 0.4e0)
+ ) * 0.32e0 + ((0.6e0 - (1.0e0 / aspect)) / (0.6e0 - 0.4e0)) * 0.44e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = (
+ ((1.0e0 / aspect) - 0.4e0) / (0.6e0 - 0.4e0)
+ ) * (-0.47e0) + ((0.6e0 - (1.0e0 / aspect)) / (0.6e0 - 0.4e0)) * (
+ -0.73e0
+ )
+
+ elif isc == 48: # NSTX gyro-Bohm (Buxton)
+ # P F Buxton et al. 2019 Plasma Phys. Control. Fusion 61 035006
+ tauee = (
+ hfact
+ * 0.21e0
+ * pcur**0.54e0
+ * bt**0.91e0
+ * powerht ** (-0.38e0)
+ * rmajor**2.14e0
+ * dnla20 ** (-0.05e0)
+ )
+
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = -0.05e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = -0.38e0
+
+ elif isc == 49: # tauee is an input
+ tauee = hfact * physics_variables.tauee_in
+
+ startup_variables.gtaue = 0.0e0
+ startup_variables.ptaue = 0.0e0
+ startup_variables.qtaue = 0.0e0
+ startup_variables.rtaue = 0.0e0
+
+ else:
+ error_handling.idiags[0] = isc
+ error_handling.report_error(81)
+
+ # Ion energy confinement time
+ # N.B. Overwrites earlier calculation above
+
+ tauei = tauee
+
+ # Calculation of the transport power loss terms
+ # Transport losses in Watts/m3 are 3/2 * n.e.T / tau , with T in eV
+ # (here, tin and ten are in keV, and ptrepv and ptripv are in MW/m3)
+
+ ptripv = 2.403e-22 * dnitot * tin / tauei
+ ptrepv = 2.403e-22 * dene * ten / tauee
+
+ ratio = dnitot / dene * tin / ten
+
+ # Global energy confinement time
+
+ taueff = (ratio + 1.0e0) / (ratio / tauei + 1.0e0 / tauee)
+
+ # This is used only in subroutine startup, which is currently (r400)
+ # not used.
+ startup_variables.ftaue = (tauee - startup_variables.gtaue) / (
+ n20**startup_variables.ptaue
+ * (te / 10.0e0) ** startup_variables.qtaue
+ * powerht**startup_variables.rtaue
+ )
+
+ return kappaa, ptrepv, ptripv, tauee, tauei, taueff, powerht
diff --git a/source/fortran/maths_library.f90 b/source/fortran/maths_library.f90
index b207b71e06..27d38a96f0 100644
--- a/source/fortran/maths_library.f90
+++ b/source/fortran/maths_library.f90
@@ -701,161 +701,6 @@ end subroutine quanc8
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- function zeroin(ax,bx,fhz,tol)
-
- !! Root-finding algorithm
- !! author: P J Knight, CCFE, Culham Science Centre
- !! ax : input real : left endpoint of initial interval
- !! bx : input real : right endpoint of initial interval
- !! fhz : external real function : function subprogram which evaluates
- !! fhz(x) for any x in the interval ax,bx
- !! tol : input real : desired length of the interval of uncertainty
- !! of the final result ( >= 0 )
- !! A zero of the function fhz(x) is computed in the interval ax,bx
- !! It is assumed that fhz(ax) and fhz(bx) have opposite signs without a
- !! check. zeroin returns a zero x in the given interval ax,bx to
- !! within a tolerance 4*macheps*abs(x) + tol, where macheps is the
- !! relative machine precision. This function subprogram is a slightly
- !! modified translation of the algol 60 procedure zero given in
- !! Richard Brent, algorithms for minimization without derivatives,
- !! Prentice - Hall, inc. (1973).
- !! http://www.netlib.org/fmm/index.html :
- !! Computer Methods for Mathematical Computations,
- !! G E Forsythe, M A Malcolm, and C B Moler,
- !! Prentice-Hall, Englewood Cliffs, New Jersey
- !! 1977, ISBN 0-13-165332-6
- !
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- implicit none
-
- interface
- function fhz(hhh)
-#ifndef dp
- use, intrinsic :: iso_fortran_env, only: dp=>real64
-#endif
- real(dp), intent(in) :: hhh
- real(dp) :: fhz
- end function fhz
- end interface
-
- real(dp) :: zeroin
-
- ! Arguments
-
- external :: fhz
- real(dp), intent(in) :: ax,bx,tol
-
- ! Local variables
-
- real(dp) :: a,b,c,d,e,eps,fa,fb,fc,tol1,xm,p,q,r,s
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- ! Compute eps, the relative machine precision
-
- eps = 1.0D0
- do
- eps = eps/2.0D0
- tol1 = 1.0D0 + eps
- if (tol1 == 1.0D0) exit
- end do
-
- ! Initialization
-
- a = ax
- b = bx
- fa = fhz(a)
- fb = fhz(b)
-
- ! Begin step
-
- step: do
- c = a
- fc = fa
- d = b - a
- e = d
-
- inner_loop: do
-
- if (abs(fc) < abs(fb)) then
- a = b ; b = c ; c = a
- fa = fb ; fb = fc ; fc = fa
- end if
-
- ! Convergence test
-
- tol1 = 2.0D0 * eps * abs(b) + 0.5D0*tol
- xm = 0.5D0*(c - b)
-
- if ((abs(xm) <= tol1).or.(fb == 0.0D0)) then
- zeroin = b
- return
- end if
-
- ! Is bisection necessary
-
- if ( (abs(e) < tol1).or.(abs(fa) <= abs(fb)) ) then
- ! Bisection
- d = xm
- e = d
- else
-
- ! Is quadratic interpolation possible?
-
- if (a == c) then
- ! Linear interpolation
- s = fb/fa
- p = 2.0D0*xm*s
- q = 1.0D0 - s
- else
- ! Inverse quadratic interpolation
- q = fa/fc
- r = fb/fc
- s = fb/fa
- p = s*(2.0D0*xm*q*(q - r) - (b - a)*(r - 1.0D0))
- q = (q - 1.0D0)*(r - 1.0D0)*(s - 1.0D0)
- end if
-
- ! Adjust signs
-
- if (p > 0.0D0) q = -q
- p = abs(p)
-
- ! Is interpolation acceptable
-
- if ( ((2.0D0*p) >= (3.0D0*xm*q - abs(tol1*q))).or. &
- (p >= abs(0.5D0*e*q)) ) then
- ! Bisection
- d = xm
- e = d
- else
- e = d
- d = p/q
- end if
-
- end if
-
- ! Complete step
-
- a = b
- fa = fb
- if (abs(d) > tol1) then
- b = b + d
- else
- b = b + sign(tol1, xm)
- end if
- fb = fhz(b)
- if ((fb*(fc/abs(fc))) > 0.0D0) exit inner_loop
-
- end do inner_loop
-
- end do step
-
- end function zeroin
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
subroutine linesolv(a, ndim, b, x)
!! Routine to solve the linear equation system Ax = b
diff --git a/source/fortran/physics.f90 b/source/fortran/physics.f90
index c33af37688..530616996c 100644
--- a/source/fortran/physics.f90
+++ b/source/fortran/physics.f90
@@ -66,3887 +66,4 @@ subroutine init_physics_module
itart_r = 0.0D0
end subroutine init_physics_module
- subroutine subr(a, b)
- implicit none
- real, intent(in) :: a
- real, intent(out) :: b
- b = a
- end subroutine subr
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- function eped_warning()
- ! Issue #413. MDK 26/2/18: improved output
- use physics_variables, only: rminor, tesep, triang, rmajor, kappa, &
- normalised_total_beta, plascur
- implicit none
- character(len=100) :: eped_warning, info_string
- eped_warning=''
- info_string = ''
-
- if((triang<0.399d0).or.(triang>0.601d0)) then
- write(info_string , '(1pe13.4)') triang
- eped_warning='triang = '//trim(info_string)
- endif
- if((kappa<1.499d0).or.(kappa>2.001d0)) then
- write(info_string , '(1pe13.4)') kappa
- eped_warning=trim(eped_warning)//' kappa = '//trim(info_string)
- endif
- if((plascur<9.99d6).or.(plascur>20.01d6)) then
- write(info_string , '(1pe13.4)') plascur
- eped_warning=trim(eped_warning)//' plascur = '//trim(info_string)
- endif
- if((rmajor<6.99d0).or.(rmajor>11.01d0)) then
- write(info_string , '(1pe13.4)') rmajor
- eped_warning=trim(eped_warning)//' rmajor = '//trim(info_string)
- endif
- if((rminor<1.99d0).or.(rminor>3.501d0))then
- write(info_string , '(1pe13.4)') rminor
- eped_warning=trim(eped_warning)//' rminor = '//trim(info_string)
- endif
- if((normalised_total_beta<1.99d0).or.(normalised_total_beta>3.01d0))then
- write(info_string , '(1pe13.4)') normalised_total_beta
- eped_warning=trim(eped_warning)//' normalised_total_beta = '//trim(info_string)
- endif
- if(tesep>0.5)then
- write(info_string , '(1pe13.4)') tesep
- eped_warning=trim(eped_warning)//' tesep = '//trim(info_string)
- endif
- end function eped_warning
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- function bootstrap_fraction_iter89(aspect,beta,bt,cboot,plascur,q95,q0,rmajor,vol)
-
- !! Original ITER calculation of bootstrap-driven fraction
- !! of the plasma current.
- !! author: P J Knight, CCFE, Culham Science Centre
- !! aspect : input real : plasma aspect ratio
- !! beta : input real : plasma total beta
- !! bt : input real : toroidal field on axis (T)
- !! cboot : input real : bootstrap current fraction multiplier
- !! plascur : input real : plasma current (A)
- !! q95 : input real : safety factor at 95% surface
- !! q0 : input real : central safety factor
- !! rmajor : input real : plasma major radius (m)
- !! vol : input real : plasma volume (m3)
- !! This routine performs the original ITER calculation of the
- !! plasma current bootstrap fraction.
- !! ITER Physics Design Guidelines: 1989 [IPDG89], N. A. Uckan et al,
- !! ITER Documentation Series No.10, IAEA/ITER/DS/10, IAEA, Vienna, 1990
- !
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-
- use constants, only: pi, rmu0
- implicit none
-
- real(dp) :: bootstrap_fraction_iter89
-
- ! Arguments
-
- real(dp), intent(in) :: aspect, beta, bt, cboot, &
- plascur, q95, q0, rmajor, vol
-
- ! Local variables
-
- real(dp) :: betapbs, bpbs, cbs, xbs, bootipf
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- xbs = min(10.0D0, q95/q0)
- cbs = cboot * (1.32D0 - 0.235D0*xbs + 0.0185D0*xbs**2)
- bpbs = rmu0*plascur/(2.0D0*pi*sqrt(vol/(2.0D0* pi**2 *rmajor)) )
- betapbs = beta*bt**2 / bpbs**2
-
- if (betapbs <= 0.0D0) then ! only possible if beta <= 0.0
- bootipf = 0.0D0
- else
- bootipf = cbs * ( betapbs/sqrt(aspect) )**1.3D0
- end if
-
- bootstrap_fraction_iter89 = bootipf
-
- end function bootstrap_fraction_iter89
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- function bootstrap_fraction_nevins(alphan,alphat,betat,bt,dene,plascur, &
- q95,q0,rmajor,rminor,ten,zeff)
-
- !! Bootstrap current fraction from Nevins et al scaling
- !! author: P J Knight, CCFE, Culham Science Centre
- !! alphan : input real : density profile index
- !! alphat : input real : temperature profile index
- !! betat : input real : total plasma beta (with respect to the toroidal
- !! field)
- !! bt : input real : toroidal field on axis (T)
- !! dene : input real : electron density (/m3)
- !! plascur: input real : plasma current (A)
- !! q0 : input real : central safety factor
- !! q95 : input real : safety factor at 95% surface
- !! rmajor : input real : plasma major radius (m)
- !! rminor : input real : plasma minor radius (m)
- !! ten : input real : density weighted average plasma temperature (keV)
- !! zeff : input real : plasma effective charge
- !! This function calculates the bootstrap current fraction,
- !! using the Nevins et al method, 4/11/90.
- !! AEA FUS 251: A User's Guide to the PROCESS Systems Code
- !
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- use physics_variables, only: te0, ne0
- use constants, only: rmu0, echarge
- use maths_library, only: quanc8
- implicit none
-
- real(dp) :: bootstrap_fraction_nevins
-
- ! Arguments
-
- real(dp), intent(in) :: alphan,alphat,betat,bt,dene,plascur, &
- q0,q95,rmajor,rminor,ten,zeff
-
- ! Local variables
-
- integer :: nofun
- real(dp) :: aibs,ainteg,betae0,dum1,fibs,flag
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- ! Calculate peak electron beta
-
- betae0 = ne0 * te0 * 1.0D3*echarge / ( bt**2 /(2.0D0*rmu0) )
-
- ! Call integration routine
-
- call quanc8(bsinteg,0.0D0,0.999D0,0.001D0,0.001D0,ainteg,dum1, &
- nofun,flag)
-
- ! Calculate bootstrap current and fraction
-
- aibs = 2.5D0 * betae0 * rmajor * bt * q95 * ainteg
- fibs = 1.0D6 * aibs / plascur
-
- bootstrap_fraction_nevins = fibs
-
- contains
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- function bsinteg(y)
-
- !! Integrand function for Nevins et al bootstrap current scaling
- !! author: P J Knight, CCFE, Culham Science Centre
- !! y : input real : abscissa of integration, = normalised minor radius
- !! This function calculates the integrand function for the
- !! Nevins et al bootstrap current scaling, 4/11/90.
- !! AEA FUS 251: A User's Guide to the PROCESS Systems Code
- !
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- implicit none
-
- real(dp) :: bsinteg
-
- ! Arguments
-
- real(dp), intent(in) :: y
-
- ! Local variables
-
- real(dp) :: alphai,al1,al2,a1,a2,betae,c1,c2,c3, &
- d,del,pratio,q,x,z
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- ! Constants for fit to q-profile
-
- c1 = 1.0D0
- c2 = 1.0D0
- c3 = 1.0D0
-
- ! Compute average electron beta
-
- betae = dene*ten*1.0D3*echarge/(bt**2/(2.0D0*rmu0))
-
- del = rminor*sqrt(y)/rmajor
- x = (1.46D0*sqrt(del) + 2.4D0*del)/(1.0D0 - del)**1.5D0
- z = zeff
- d = 1.414D0*z + z*z + x*(0.754D0 + 2.657D0*z + 2.0D0*z*z) &
- + x*x*(0.348D0 + 1.243D0*z + z*z)
- al2 = -x*(0.884D0 + 2.074D0*z)/d
- a2 = alphat*(1.0D0-y)**(alphan+alphat-1.0D0)
- alphai = -1.172D0/(1.0D0 + 0.462D0*x)
- a1 = (alphan+alphat)*(1.0D0-y)**(alphan+alphat-1.0D0)
- al1 = x*(0.754D0+2.21D0*z+z*z+x*(0.348D0+1.243D0*z+z*z))/d
-
- ! q-profile
-
- q = q0 + (q95-q0)*(c1*y + c2*y*y + c3*y**3)/(c1+c2+c3)
-
- pratio = (betat - betae) / betae
-
- bsinteg = (q/q95)*(al1*(a1 + pratio*(a1+alphai*a2) ) + al2*a2 )
-
- end function bsinteg
-
- end function bootstrap_fraction_nevins
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- function bootstrap_fraction_wilson(alphaj,alphap,alphat,betpth, &
- q0,qpsi,rmajor,rminor)
-
- !! Bootstrap current fraction from Wilson et al scaling
- !! author: P J Knight, CCFE, Culham Science Centre
- !! alphaj : input real : current profile index
- !! alphap : input real : pressure profile index
- !! alphat : input real : temperature profile index
- !! beta : input real : total beta
- !! betpth : input real : thermal component of poloidal beta
- !! q0 : input real : safety factor on axis
- !! qpsi : input real : edge safety factor
- !! rmajor : input real : major radius (m)
- !! rminor : input real : minor radius (m)
- !! This function calculates the bootstrap current fraction
- !! using the numerically fitted algorithm written by Howard Wilson.
- !! AEA FUS 172: Physics Assessment for the European Reactor Study
- !! H. R. Wilson, Nuclear Fusion 32 (1992) 257
- !
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- use error_handling, only: fdiags, report_error
- use maths_library, only: linesolv
- implicit none
-
- real(dp) :: bootstrap_fraction_wilson
-
- ! Arguments
-
- real(dp), intent(in) :: alphaj,alphap,alphat,betpth, &
- q0,qpsi,rmajor,rminor
-
- ! Local variables
-
- integer :: i
- real(dp), dimension(12) :: a, b
- real(dp) :: aj,alfpnw,alftnw,eps1,r1,r2, &
- saj,seps1,sss,termj,termp,termt,term1,term2,z
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- ! alphap, alphat and alphaj are indices relevant to profiles of
- ! the form
- ! p = p0.(1-(r/a)**2)**alphap, etc.
- !
- ! Convert these indices to those relevant to profiles of the form
- ! p = p0.psi**alfpnw, etc.
-
- term1 = log(0.5D0)
- term2 = log(q0/qpsi)
-
- termp = 1.0D0-0.5D0**(1.0D0/alphap)
- termt = 1.0D0-0.5D0**(1.0D0/alphat)
- termj = 1.0D0-0.5D0**(1.0D0/alphaj)
-
- alfpnw = term1/log( log( (q0+(qpsi-q0)*termp)/qpsi )/term2)
- alftnw = term1/log( log( (q0+(qpsi-q0)*termt)/qpsi )/term2)
- aj = term1/log( log( (q0+(qpsi-q0)*termj)/qpsi )/term2)
-
- ! Crude check for NaN errors or other illegal values...
-
- if ((aj /= aj).or.(alfpnw /= alfpnw).or.(alftnw /= alftnw).or.(aj <= 0.0D0)) then
- fdiags(1) = aj ; fdiags(2) = alfpnw ; fdiags(3) = alftnw ; fdiags(4) = aj
- call report_error(76)
- end if
-
- ! Ratio of ionic charge to electron charge
-
- z = 1.0D0
-
- ! Inverse aspect ratio: r2 = maximum plasma radius, r1 = minimum
-
- r2 = rmajor+rminor
- r1 = rmajor-rminor
- eps1 = (r2-r1)/(r2+r1)
-
- ! Coefficients fitted using least squares techniques
-
- saj = sqrt(aj)
-
- a(1) = 1.41D0*(1.0D0-0.28D0*saj)*(1.0D0+0.12D0/z)
- a(2) = 0.36D0*(1.0D0-0.59D0*saj)*(1.0D0+0.8D0/z)
- a(3) = -0.27D0*(1.0D0-0.47D0*saj)*(1.0D0+3.0D0/z)
- a(4) = 0.0053D0*(1.0D0+5.0D0/z)
- a(5) = -0.93D0*(1.0D0-0.34D0*saj)*(1.0D0+0.15D0/z)
- a(6) = -0.26D0*(1.0D0-0.57D0*saj)*(1.0D0-0.27D0*z)
- a(7) = 0.064D0*(1.0D0-0.6D0*aj+0.15D0*aj*aj)*(1.0D0+7.6D0/z)
- a(8) = -0.0011D0*(1.0D0+9.0D0/z)
- a(9) = -0.33D0*(1.0D0-aj+0.33D0*aj*aj)
- a(10) = -0.26D0*(1.0D0-0.87D0/saj-0.16D0*aj)
- a(11) = -0.14D0*(1.0D0-1.14D0/saj-0.45D0*saj)
- a(12) = -0.0069D0
-
- seps1 = sqrt(eps1)
-
- b(1) = 1.0D0
- b(2) = alfpnw
- b(3) = alftnw
- b(4) = alfpnw*alftnw
- b(5) = seps1
- b(6) = alfpnw*seps1
- b(7) = alftnw*seps1
- b(8) = alfpnw*alftnw*seps1
- b(9) = eps1
- b(10) = alfpnw*eps1
- b(11) = alftnw*eps1
- b(12) = alfpnw*alftnw*eps1
-
- sss = 0.0D0
- do i = 1,12
- sss = sss + a(i)*b(i)
- end do
-
- ! Empirical bootstrap current fraction
-
- bootstrap_fraction_wilson = seps1 * betpth * sss
-
- end function bootstrap_fraction_wilson
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- function bootstrap_fraction_sauter()
-
- !! Bootstrap current fraction from Sauter et al scaling
- !! author: P J Knight, CCFE, Culham Science Centre
- !! None
- !! This function calculates the bootstrap current fraction
- !! using the Sauter, Angioni and Lin-Liu scaling.
- !!
The code was supplied by Emiliano Fable, IPP Garching - !! (private communication). - !! O. Sauter, C. Angioni and Y. R. Lin-Liu, - !! Physics of Plasmas 6 (1999) 2834 - !! O. Sauter, C. Angioni and Y. R. Lin-Liu, (ERRATA) - !! Physics of Plasmas 9 (2002) 5140 - ! - ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - use physics_variables, only: dnitot, rminor, tesep, ti, triang, q0, afuel, & - zeff, rhopedn, bt, plascur, xarea, fhe3, teped, dene, te, rmajor, q, & - nesep, te0, neped, tbeta, ne0, alphan, rhopedt, alphat - use profiles_module, only: tprofile, nprofile - use constants, only: pi - implicit none - - real(dp) :: bootstrap_fraction_sauter - - ! Arguments - - ! Local variables - - integer, parameter :: nr = 200 - integer :: ir - real(dp) :: da,drho,iboot,jboot,roa - real(dp) :: dlogne_drho,dlogte_drho,dlogti_drho - real(dp), dimension(nr) :: amain,mu,ne,ni,rho,sqeps,tempe,tempi,zef,zmain - - ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - ! Populate profile arrays - - do ir = 1,nr - roa = dble(ir)/nr - rho(ir) = sqrt(xarea/pi) * roa ! local circularised minor radius (m) - sqeps(ir) = sqrt(roa * rminor/rmajor) - - ne(ir) = 1.0D-19 * nprofile(roa,rhopedn,ne0,neped,nesep,alphan) - ni(ir) = dnitot/dene * ne(ir) - tempe(ir) = tprofile(roa,rhopedt,te0,teped,tesep,alphat,tbeta) - tempi(ir) = ti/te * tempe(ir) - - zef(ir) = zeff ! Flat Zeff profile assumed - - ! mu = 1/safety factor - ! Parabolic q profile assumed - - mu(ir) = 1.0D0 / (q0 + (q-q0)*roa**2) - amain(ir) = afuel ! fuel ion mass - zmain(ir) = 1.0D0 + fhe3 ! sum(Zi.ni)/sum(ni) over fuel ions i - end do - - ! Ensure that density and temperature values are not zero at edge - - if (ne(nr) == 0.0D0) then - ne(nr) = 1.0D-4*ne(nr-1) - ni(nr) = 1.0D-4*ni(nr-1) - end if - - if (tempe(nr) == 0.0D0) then - tempe(nr) = 1.0D-4*tempe(nr-1) - tempi(nr) = 1.0D-4*tempi(nr-1) - end if - - ! Calculate total bootstrap current (MA) by summing along profiles - - iboot = 0.0D0 - do ir = 1,nr - - if (ir == nr) then - jboot = 0.0D0 - da = 0.0D0 - else - drho = rho(ir+1) - rho(ir) - da = 2.0D0*pi*rho(ir)*drho ! area of annulus - - dlogte_drho = (log(tempe(ir+1)) - log(tempe(ir))) / drho - dlogti_drho = (log(tempi(ir+1)) - log(tempi(ir))) / drho - dlogne_drho = (log(ne(ir+1)) - log(ne(ir))) / drho - - ! The factor of 0.5 below arises because in ASTRA the logarithms - ! are coded as (e.g.): (Te(j+1)-Te(j))/(Te(j+1)+Te(j)), which - ! actually corresponds to grad(log(Te))/2. So the factors dcsa etc. - ! are a factor two larger than one might otherwise expect. - - jboot = 0.5D0 * ( dcsa(ir,nr) * dlogne_drho & - + hcsa(ir,nr) * dlogte_drho & - + xcsa(ir,nr) * dlogti_drho ) - jboot = -bt/(0.2D0*pi*rmajor) * rho(ir)*mu(ir) * jboot ! MA/m2 - end if - - iboot = iboot + da*jboot ! MA - - end do - - bootstrap_fraction_sauter = 1.0D6 * iboot/plascur - - contains - - ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - function beta_poloidal_local(j,nr) - - !! Local beta poloidal calculation - !! author: P J Knight, CCFE, Culham Science Centre - !! j : input integer : radial element index in range 1 to nr - !! nr : input integer : maximum value of j - !! This function calculates the local beta poloidal. - !!
The code was supplied by Emiliano Fable, IPP Garching - !! (private communication). - !!
beta poloidal = 4*pi*ne*Te/Bpo**2 - !! Pereverzev, 25th April 1989 (?) - ! - ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - implicit none - - real(dp) :: beta_poloidal_local - - ! Arguments - - integer, intent(in) :: j, nr - - ! Local variables - - ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - if (j /= nr) then - beta_poloidal_local = 1.6D-4*pi * (ne(j+1)+ne(j)) * (tempe(j+1)+tempe(j)) - else - beta_poloidal_local = 6.4D-4*pi * ne(j)*tempe(j) - end if - - beta_poloidal_local = beta_poloidal_local * & - ( rmajor/(bt*rho(j)*abs(mu(j)+1.0D-4)) )**2 - - end function beta_poloidal_local - - ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - function beta_poloidal_local_total(j,nr) - - !! Local beta poloidal calculation, including ion pressure - !! author: P J Knight, CCFE, Culham Science Centre - !! j : input integer : radial element index in range 1 to nr - !! nr : input integer : maximum value of j - !! This function calculates the local total beta poloidal. - !!
The code was supplied by Emiliano Fable, IPP Garching - !! (private communication). - !!
beta poloidal = 4*pi*(ne*Te+ni*Ti)/Bpo**2 - !! where ni is the sum of all ion densities (thermal) - !! Pereverzev, 25th April 1989 (?) - !! E Fable, private communication, 15th May 2014 - ! - ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - implicit none - - real(dp) :: beta_poloidal_local_total - - ! Arguments - - integer, intent(in) :: j, nr - - ! Local variables - - ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - if (j /= nr) then - beta_poloidal_local_total = 1.6D-4*pi * ( & - ( (ne(j+1)+ne(j)) * (tempe(j+1)+tempe(j)) ) + & - ( (ni(j+1)+ni(j)) * (tempi(j+1)+tempi(j)) ) ) - else - beta_poloidal_local_total = 6.4D-4*pi * (ne(j)*tempe(j) + ni(j)*tempi(j)) - end if - - beta_poloidal_local_total = beta_poloidal_local_total * & - ( rmajor/(bt*rho(j)*abs(mu(j)+1.0D-4)) )**2 - - end function beta_poloidal_local_total - - ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - function nues(j) - - !! Relative frequency of electron collisions - !! author: P J Knight, CCFE, Culham Science Centre - !! j : input integer : radial element index in range 1 to nr - !! This function calculates the relative frequency of electron - !! collisions: NU* = Nuei*q*Rt/eps**1.5/Vte - !! The electron-ion collision frequency NUEI=NUEE*1.4*ZEF is - !! used. - !!
The code was supplied by Emiliano Fable, IPP Garching - !! (private communication). - !! Yushmanov, 30th April 1987 (?) - ! - ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - implicit none - - real(dp) :: nues - - ! Arguments - - integer, intent(in) :: j - - ! Local variables - - ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - nues = nuee(j) * 1.4D0*zef(j)*rmajor / & - abs(mu(j)*(sqeps(j)**3)*sqrt(tempe(j))*1.875D7) - - end function nues - - ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - function nuee(j) - - !! Frequency of electron-electron collisions - !! author: P J Knight, CCFE, Culham Science Centre - !! j : input integer : radial element index in range 1 to nr - !! This function calculates the frequency of electron-electron - !! collisions (Hz): NUEE = 4*SQRT(pi)/3*Ne*e**4*lambd/ - !! SQRT(Me)/Te**1.5 - !!
The code was supplied by Emiliano Fable, IPP Garching - !! (private communication). - !! Yushmanov, 25th April 1987 (?), - !! updated by Pereverzev, 9th November 1994 (?) - ! - ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - implicit none - - real(dp) :: nuee - - ! Arguments - - integer, intent(in) :: j - - ! Local variables - - ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - nuee = 670.0D0 * coulg(j) * ne(j) / ( tempe(j)*sqrt(tempe(j)) ) - - end function nuee - - ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - function coulg(j) - - !! Coulomb logarithm - !! author: P J Knight, CCFE, Culham Science Centre - !! j : input integer : radial element index in range 1 to nr - !! This function calculates the Coulomb logarithm, valid - !! for e-e collisions (T_e > 0.01 keV), and for - !! e-i collisions (T_e > 0.01*Zeff^2) (Alexander, 9/5/1994). - !!
The code was supplied by Emiliano Fable, IPP Garching - !! (private communication). - !! C. A. Ordonez and M. I. Molina, Phys. Plasmas 1 (1994) 2515 - !! Rev. Mod. Phys., V.48, Part 1 (1976) 275 - ! - ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - implicit none - - real(dp) :: coulg - - ! Arguments - - integer, intent(in) :: j - - ! Local variables - - ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - coulg = 15.9D0 - 0.5D0*log(ne(j)) + log(tempe(j)) - - end function coulg - - ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - function nuis(j) - - !! Relative frequency of ion collisions - !! author: P J Knight, CCFE, Culham Science Centre - !! j : input integer : radial element index in range 1 to nr - !! This function calculates the relative frequency of ion - !! collisions: NU* = Nui*q*Rt/eps**1.5/Vti - !! The full ion collision frequency NUI is used. - !!
The code was supplied by Emiliano Fable, IPP Garching - !! (private communication). - !! Yushmanov, 30th April 1987 (?) - ! - ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - implicit none - - real(dp) :: nuis - - ! Arguments - - integer, intent(in) :: j - - ! Local variables - - ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - nuis = 3.2D-6 * nui(j)*rmajor / ( abs(mu(j)+1.0D-4) * & - sqeps(j)**3 * sqrt(tempi(j)/amain(j)) ) - - end function nuis - - ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - function nui(j) - - !! Full frequency of ion collisions - !! author: P J Knight, CCFE, Culham Science Centre - !! j : input integer : radial element index in range 1 to nr - !! This function calculates the full frequency of ion - !! collisions (Hz). - !!
The code was supplied by Emiliano Fable, IPP Garching - !! (private communication). - !! None - ! - ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - real(dp) :: nui - - ! Arguments - - integer, intent(in) :: j - - ! Local variables - - ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - ! Coulomb logarithm = 15 is used - - nui = zmain(j)**4 * ni(j) * 322.0D0 / ( tempi(j)*sqrt(tempi(j)*amain(j)) ) - - end function nui - - ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - function dcsa(j,nr) - - !! Grad(ln(ne)) coefficient in the Sauter bootstrap scaling - !! author: P J Knight, CCFE, Culham Science Centre - !! j : input integer : radial element index in range 1 to nr - !! nr : input integer : maximum value of j - !! This function calculates the coefficient scaling grad(ln(ne)) - !! in the Sauter bootstrap current scaling. - !! Code by Angioni, 29th May 2002. - !!
The code was supplied by Emiliano Fable, IPP Garching - !! (private communication). - !! O. Sauter, C. Angioni and Y. R. Lin-Liu, - !! Physics of Plasmas 6 (1999) 2834 - !! O. Sauter, C. Angioni and Y. R. Lin-Liu, (ERRATA) - !! Physics of Plasmas 9 (2002) 5140 - ! - ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - ! DCSA $\equiv \mathcal{L}_{31}$, Eq.14a, Sauter et al, 1999 - - implicit none - - real(dp) :: dcsa - - ! Arguments - - integer, intent(in) :: j,nr - - ! Local variables - - real(dp) :: zz,zft,zdf - - ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - if (j == 1) then - dcsa = 0.0D0 - else - zz = zef(j) - zft = tpf(j) - zdf = 1.0D0 + (1.0D0 - 0.1D0*zft)*sqrt(nues(j)) - zdf = zdf + 0.5D0*(1.0D0-zft)*nues(j)/zz - zft = zft/zdf ! $f^{31}_{teff}(\nu_{e*})$, Eq.14b - dcsa = (1.0D0 + 1.4D0/(zz+1.0D0))*zft - 1.9D0/(zz+1.0D0)*zft*zft - dcsa = dcsa + (0.3D0*zft*zft + 0.2D0*zft*zft*zft)*zft / (zz+1.0D0) - - ! Corrections suggested by Fable, 15/05/2015 - !dcsa = dcsa*beta_poloidal_local(j,nr) * (1.0D0+tempi(j)/(zz*tempe(j))) - dcsa = dcsa*beta_poloidal_local_total(j,nr) - end if - - end function dcsa - - ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - function hcsa(j,nr) - - !! Grad(ln(Te)) coefficient in the Sauter bootstrap scaling - !! author: P J Knight, CCFE, Culham Science Centre - !! j : input integer : radial element index in range 1 to nr - !! nr : input integer : maximum value of j - !! This function calculates the coefficient scaling grad(ln(Te)) - !! in the Sauter bootstrap current scaling. - !! Code by Angioni, 29th May 2002. - !!
The code was supplied by Emiliano Fable, IPP Garching - !! (private communication). - !! O. Sauter, C. Angioni and Y. R. Lin-Liu, - !! Physics of Plasmas 6 (1999) 2834 - !! O. Sauter, C. Angioni and Y. R. Lin-Liu, (ERRATA) - !! Physics of Plasmas 9 (2002) 5140 - ! - ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - ! HCSA $\equiv ?$, Sauter et al, 1999 - - implicit none - - real(dp) :: hcsa - - ! Arguments - - integer, intent(in) :: j,nr - - ! Local variables - - real(dp) :: zz,zft,zdf,zfte,zfte2,zfte3,zfte4 - real(dp) :: zfti,zfti2,zfti3,zfti4,hcee,hcei - - ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - if (j == 1) then - hcsa = 0.0D0 - else - zz = zef(j) - zft = tpf(j) - zdf = 1.0D0 + 0.26D0*(1.0D0-zft)*sqrt(nues(j)) - zdf = zdf + 0.18D0*(1.0D0-0.37D0*zft)*nues(j)/sqrt(zz) - zfte = zft/zdf ! $f^{32\_ee}_{teff}(\nu_{e*})$, Eq.15d - zfte2 = zfte*zfte - zfte3 = zfte*zfte2 - zfte4 = zfte2*zfte2 - - zdf = 1.0D0 + (1.0D0 + 0.6D0*zft)*sqrt(nues(j)) - zdf = zdf + 0.85D0*(1.0D0 - 0.37D0*zft)*nues(j)*(1.0D0+zz) - zfti = zft/zdf ! $f^{32\_ei}_{teff}(\nu_{e*})$, Eq.15e - zfti2 = zfti*zfti - zfti3 = zfti*zfti2 - zfti4 = zfti2*zfti2 - - hcee = (0.05D0 + 0.62D0*zz) / zz / (1.0D0 + 0.44D0*zz) * (zfte-zfte4) - hcee = hcee + (zfte2 - zfte4 - 1.2D0*(zfte3-zfte4)) / (1.0D0 + 0.22D0*zz) - hcee = hcee + 1.2D0/(1.0D0 + 0.5D0*zz)*zfte4 ! $F_{32\_ee}(X)$, Eq.15b - - hcei = -(0.56D0 + 1.93D0*zz) / zz / (1.0D0 + 0.44*zz) * (zfti-zfti4) - hcei = hcei + 4.95D0/(1.0D0 + 2.48D0*zz) * & - (zfti2 - zfti4 - 0.55D0*(zfti3-zfti4)) - hcei = hcei - 1.2D0/(1.0D0 + 0.5D0*zz)*zfti4 ! $F_{32\_ei}(Y)$, Eq.15c - - ! Corrections suggested by Fable, 15/05/2015 - !hcsa = beta_poloidal_local(j,nr)*(hcee + hcei) + dcsa(j,nr) & - ! / (1.0D0 + tempi(j)/(zz*tempe(j))) - hcsa = beta_poloidal_local(j,nr)*(hcee + hcei) + dcsa(j,nr) & - * beta_poloidal_local(j,nr)/beta_poloidal_local_total(j,nr) - end if - - end function hcsa - - ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - function xcsa(j,nr) - - !! Grad(ln(Ti)) coefficient in the Sauter bootstrap scaling - !! author: P J Knight, CCFE, Culham Science Centre - !! j : input integer : radial element index in range 1 to nr - !! nr : input integer : maximum value of j - !! This function calculates the coefficient scaling grad(ln(Ti)) - !! in the Sauter bootstrap current scaling. - !! Code by Angioni, 29th May 2002. - !!
The code was supplied by Emiliano Fable, IPP Garching - !! (private communication). - !! O. Sauter, C. Angioni and Y. R. Lin-Liu, - !! Physics of Plasmas 6 (1999) 2834 - !! O. Sauter, C. Angioni and Y. R. Lin-Liu, (ERRATA) - !! Physics of Plasmas 9 (2002) 5140 - ! - ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - implicit none - - real(dp) :: xcsa - - ! Arguments - - integer, intent(in) :: j,nr - - ! Local variables - - real(dp) :: zz,zft,zdf,a0,alp,a1,zfte - - ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - if (j == 1) then - xcsa = 0.0D0 - else - zz = zef(j) - zft = tpf(j) - zdf = 1.0D0 + (1.0D0 - 0.1D0*zft)*sqrt(nues(j)) - zdf = zdf + 0.5D0*(1.0D0 - 0.5D0*zft)*nues(j)/zz - zfte = zft/zdf ! $f^{34}_{teff}(\nu_{e*})$, Eq.16b - - xcsa = (1.0D0 + 1.4D0/(zz+1.0D0))*zfte - 1.9D0/(zz+1.0D0)*zfte*zfte - xcsa = xcsa + (0.3D0*zfte*zfte + 0.2D0*zfte*zfte*zfte)*zfte & - / (zz+1.0D0) ! Eq.16a - - a0 = -1.17D0*(1.0D0-zft) - a0 = a0 / (1.0D0 - 0.22D0*zft - 0.19D0*zft*zft) ! $\alpha_0$, Eq.17a - - alp = (a0 + 0.25D0*(1.0D0 - zft*zft)*sqrt(nuis(j))) / & - (1.0D0 + 0.5*sqrt(nuis(j))) - a1 = nuis(j)*nuis(j) * zft**6 - alp = (alp + 0.315D0*a1) / (1.0D0 + 0.15D0*a1) ! $\alpha(\nu_{i*})$, Eq.17b - - ! Corrections suggested by Fable, 15/05/2015 - !xcsa = beta_poloidal_local(j,nr) * (xcsa*alp)*tempi(j)/zz/tempe(j) - !xcsa = xcsa + dcsa(j,nr) / (1.0D0 + zz*tempe(j)/tempi(j)) - - xcsa = (beta_poloidal_local_total(j,nr)-beta_poloidal_local(j,nr)) & - * (xcsa*alp) - xcsa = xcsa + dcsa(j,nr) * & - (1.0D0 - beta_poloidal_local(j,nr)/beta_poloidal_local_total(j,nr)) - end if - - end function xcsa - - ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - function tpf(j) - - !! Trapped particle fraction - !! author: P J Knight, CCFE, Culham Science Centre - !! j : input integer : radial element index in range 1 to nr - !! This function calculates the trapped particle fraction at - !! a given radius. - !!
A number of different fits are provided, but the one - !! to be used is hardwired prior to run-time. - !!
The code was supplied by Emiliano Fable, IPP Garching
- !! (private communication).
- !! O. Sauter et al, Plasma Phys. Contr. Fusion 44 (2002) 1999
- !! O. Sauter, 2013:
- !! http://infoscience.epfl.ch/record/187521/files/lrp_012013.pdf
- !
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- implicit none
-
- real(dp) :: tpf
-
- ! Arguments
-
- integer, intent(in) :: j
-
- ! Local variables
-
- integer, parameter :: ASTRA=1, SAUTER2002=2, SAUTER2013=3
-
- real(dp) :: eps,epseff,g,s,zz
-
- integer, parameter :: fit = ASTRA
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- s = sqeps(j)
- eps = s*s
-
- select case (fit)
-
- case (ASTRA)
-
- ! ASTRA method, from Emiliano Fable, private communication
- ! (Excluding h term which dominates for inverse aspect ratios < 0.5,
- ! and tends to take the trapped particle fraction to 1)
-
- zz = 1.0D0 - eps
-
- g = 1.0D0 - zz*sqrt(zz) / (1.0D0 + 1.46D0*s)
-
- ! Advised by Emiliano to ignore ASTRA's h below
- !
- !h = 0.209D0 * (sqrt(tempi(j)*amain(j))/zmain(j)*mu(j)*rmajor*bt)**0.3333D0
- !tpf = min(1.0D0, max(g, h))
-
- tpf = g
-
- case (SAUTER2002)
-
- ! Equation 4 of Sauter 2002
- ! Similar to, but not quite identical to g above
-
- tpf = 1.0D0 - (1.0D0-eps)**2 / (1.0D0 + 1.46D0*s) / sqrt(1.0D0 - eps*eps)
-
- case (SAUTER2013)
-
- ! Includes correction for triangularity
-
- epseff = 0.67D0*(1.0D0 - 1.4D0*triang*abs(triang)) * eps
-
- tpf = 1.0D0 - sqrt( (1.0D0-eps)/(1.0D0+eps) ) * &
- (1.0D0 - epseff) / (1.0D0 + 2.0D0*sqrt(epseff))
-
- end select
-
- end function tpf
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- !subroutine fast_alpha_bs()
-
- ! BSALP (local per index J) is in MA/m^2
-
- ! Required... before we can use this routine:
- ! fast alpha pressure profile
- ! poloidal flux profile vs local minor radius (and grad(psi))
- ! Shafranov shift vs local minor radius
-
- ! all lengths in meters,
- ! temperatures in keV where j is the radial index,
- ! IPOL is R*Bphi / (R0*Bphi0) (i.e. the normalized poloidal current integral)
- ! PFAST is the alpha pressure
- ! TE is the electron temperature
- ! SHIF is the Shafranov shift (defined with respect to the geom. major radius)
- ! AMETR is the minor radius
- ! RTOR = R0
- ! ZEF = Z effective
- ! FP = PSI (magnetic flux, poloidal) defined such that
- ! B_pol = grad(PSI) / (2*PI*R)
-
- ! ZBIRTH = 1.
-
- ! !MeV already included in PFAST ,convert PFAST from keV*1e19 to J
- ! ZDPDPSI = 3./2.*1.60218*1.e3* &
- ! (PFAST(J)-PFAST(J-1))/((FP(J)-FP(J-1))/GP2)
- ! ZSB=(0.027*ZEF(J-1)*(TE(J-1)/20.)**(3./2.))**(1./3.)
- ! ZSB1=(0.027*ZEF(J)*(TE(J)/20.)**(3./2.))**(1./3.)
- ! ZSC=(5./3.)**(1./3.)*ZSB
- ! ZSC1=(5./3.)**(1./3.)*ZSB1
- ! ZDSC3DPSI = 3./2.*1.60218*1.e3*PFAST(J)* &
- ! (ZSC1**3.-ZSC**3.)/((FP(J)-FP(J-1))/GP2)
- ! ZEPS=AMETR(J)/RTOR
- ! ZFP=1.-1.46*(1.+0.67/ZEF(J))*ZEPS**0.5+ 0.46*(1.+2.1/ZEF(J))*ZEPS
-
- ! ZDR0DR=(SHIF(J)-SHIF(J-1))/(AMETR(J)-AMETR(J-1))
-
- ! ZY=(1.-ZDR0DR/ZEPS*(1.-(1.-ZEPS**2.)**0.5)) &
- ! /(1.+ZEPS*ZDR0DR/2.)/(1.-ZEPS**2.)**.5
-
- ! ZA11=-ZSB**(3./2.)*(0.12+2.24*ZSB**(3./2.)-0.9*ZSB**3.) &
- ! /(0.7+18.4*ZSB**(3./2.)+ &
- ! 23.5*ZSB**3.+101.*ZSB**(9./2.))*ZY
-
- ! ZA12=-2./3.*(0.5+0.8*ZSC**(3./2.)+0.4*ZSC**3.) &
- ! /(1.+2.3*ZSC**(3./2.)+4.*ZSC**3.)
-
- ! ZA21=(7.e-4+0.02*ZSB**(3./2.)+0.4*ZSB**3.)/ &
- ! (0.01-0.61*ZSB**(3./2.)+ &
- ! 24.8*ZSB**3.-53.4*ZSB**(9./2.)+118.*ZSB**6.)*ZY
-
- ! ZA22=2./3.*(0.1+3.25*ZSC**(3./2.)-1.1*ZSC**3.)/ &
- ! (1.e-3+0.6*ZSC**(3./2.)+ &
- ! 8.6*ZSC**3.+3.1*ZSC**(9./2.)+15.1*ZSC**6.)
-
- ! ZB1=(0.155+3.9*ZSB**(3./2.)-3.1*ZSB**3.+0.3*ZSB**6.) &
- ! /(0.1+3.*ZSB**(3./2.)-2.1*ZSB**3.)*ZY
-
- ! ZB2=(1.3-0.5*ZSB**(3./2.)+5.9*ZSB**3.)/ &
- ! (1.-0.34*ZSB**(3./2.)+4.9*ZSB**3.)*ZY
-
- ! ZA1 = -ZA11+(2.*ZA11+(2.*ZB1-3.)*ZA12)*ZEPS**.5 &
- ! -(ZA11+2.*(ZB1-1.)*ZA12)*ZEPS
-
- ! ZA2 = -ZA21+(2.*ZA21+(2.*ZB2-3.)*ZA22)*ZEPS**.5 &
- ! -(ZA21+2.*(ZB2-1.)*ZA22)*ZEPS
-
- ! !bootstrap current by alphas
- ! BSALP=-ZEPS**.5*(1.-2./ZEF(J)*ZFP)*IPOL(J)* &
- ! RTOR*ZBIRTH*(ZA1*ZDPDPSI+ZA2*ZDSC3DPSI)
- ! BSALP=BSALP/1.e6
-
- !end subroutine fast_alpha_bs
-
- end function bootstrap_fraction_sauter
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- subroutine diamagnetic_fraction_hender(beta,diacf)
-
- !! author: S.I. Muldrew, CCFE, Culham Science Centre
- !! Diamagnetic contribution at tight aspect ratio.
- !! Tim Hender fit
- !
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- implicit none
-
- ! Arguments
-
- real(dp), intent(in) :: beta
- real(dp), intent(out) :: diacf
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- diacf = beta / 2.8D0
-
-
- end subroutine diamagnetic_fraction_hender
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- subroutine diamagnetic_fraction_scene(beta,q95,q0,diacf)
-
- !! author: S.I. Muldrew, CCFE, Culham Science Centre
- !! Diamagnetic fraction based on SCENE fit by Tim Hender
- !! See Issue #992
- !
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- implicit none
-
- ! Arguments
-
- real(dp), intent(in) :: beta, q95, q0
- real(dp), intent(out) :: diacf
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- diacf = beta * (0.1D0*q95/q0+0.44D0) * 4.14D-1
-
- end subroutine diamagnetic_fraction_scene
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- subroutine ps_fraction_scene(beta,pscf)
-
- !! author: S.I. Muldrew, CCFE, Culham Science Centre
- !! Pfirsch-Schlüter fraction based on SCENE fit by Tim Hender
- !! See Issue #992
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- implicit none
-
- ! Arguments
-
- real(dp), intent(in) :: beta
- real(dp), intent(out) :: pscf
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- pscf = -9.0D-2 * beta
-
- end subroutine ps_fraction_scene
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- subroutine culcur(alphaj,alphap,bt,eps,icurr,iprofile,kappa,kappa95, &
- p0,pperim,q0,qpsi,rli,rmajor,rminor,sf,triang,triang95,bp,qstar,plascur)
-
- !! Routine to calculate the plasma current
- !! author: P J Knight, CCFE, Culham Science Centre
- !! alphaj : input/output real : current profile index
- !! alphap : input real : pressure profile index
- !! bt : input real : toroidal field on axis (T)
- !! eps : input real : inverse aspect ratio
- !! icurr : input integer : current scaling model to use
- !! 1 = Peng analytic fit
- !! 2 = Peng divertor scaling (TART)
- !! 3 = simple ITER scaling
- !! 4 = revised ITER scaling
- !! 5 = Todd empirical scaling I
- !! 6 = Todd empirical scaling II
- !! 7 = Connor-Hastie model
- !! iprofile : input integer : switch for current profile consistency
- !! 0 = use input alphaj, rli
- !! 1 = make these consistent with q, q0
- !! kappa : input real : plasma elongation
- !! kappa95 : input real : plasma elongation at 95% surface
- !! p0 : input real : central plasma pressure (Pa)
- !! pperim : input real : plasma perimeter length (m)
- !! q0 : input real : plasma safety factor on axis
- !! qpsi : input real : plasma edge safety factor (= q-bar for icurr=2)
- !! rli : input/output real : plasma normalised internal inductance
- !! rmajor : input real : major radius (m)
- !! rminor : input real : minor radius (m)
- !! sf : input real : shape factor for icurr=1 (=A/pi in documentation)
- !! triang : input real : plasma triangularity
- !! triang95 : input real : plasma triangularity at 95% surface
- !! bp : output real : poloidal field (T)
- !! qstar : output real : equivalent cylindrical safety factor (shaped)
- !! plascur : output real : plasma current (A)
- !! This routine performs the calculation of the
- !! plasma current, with a choice of formula for the edge
- !! safety factor. It will also make the current profile parameters
- !! consistent with the q-profile if required.
- !! AEA FUS 251: A User's Guide to the PROCESS Systems Code
- !! J D Galambos, STAR Code : Spherical Tokamak Analysis and Reactor Code,
- !! unpublished internal Oak Ridge document
- !! Y.-K. M. Peng, J. Galambos and P.C. Shipe, 1992,
- !! Fusion Technology, 21, 1729
- !! ITER Physics Design Guidelines: 1989 [IPDG89], N. A. Uckan et al,
- !! ITER Documentation Series No.10, IAEA/ITER/DS/10, IAEA, Vienna, 1990
- !! M. Kovari et al, 2014, "PROCESS": A systems code for fusion power plants -
- !! Part 1: Physics https://www.sciencedirect.com/science/article/pii/S0920379614005961
- !! H. Zohm et al, 2013, On the Physics Guidelines for a Tokamak DEMO
- !! https://iopscience.iop.org/article/10.1088/0029-5515/53/7/073019
- !! T. Hartmann, 2013, Development of a modular systems code to analyse the
- !! implications of physics assumptions on the design of a demonstration fusion power plant
- !! https://inis.iaea.org/search/search.aspx?orig_q=RN:45031642
- !! Sauter, Geometric formulas for systems codes..., FED 2016
- !
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- use error_handling, only: idiags, report_error
- use physics_variables, only: normalised_total_beta, beta
- use global_variables, only: run_tests
- use constants, only: pi, rmu0
- implicit none
-
- ! Arguments
-
- integer, intent(in) :: icurr, iprofile
- real(dp), intent(inout) :: alphaj, rli
- real(dp), intent(in) :: alphap, bt, eps, kappa, &
- kappa95, p0, pperim, q0, qpsi, rmajor, rminor, sf, triang, triang95
- real(dp), intent(out) :: bp, qstar, plascur
-
- ! Local variables
-
- real(dp) :: asp, curhat, fq, w07
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- ! Aspect ratio
-
- asp = 1.0D0/eps
-
- ! Calculate the function Fq that scales the edge q from the
- ! circular cross-section cylindrical case
-
- ! First check for negative triangularity using unsuitable current scaling
-
- if ((icurr.ne.8).and.(triang.lt.0.0)) then
- write(*,*) 'Triangularity is negative without icurr = 8.'
- write(*,*) 'Please check and try again.'
- write(*,*) 'PROCESS stopping'
- stop 1
- end if
-
- select case (icurr)
-
- case (1) ! Peng analytical fit
- fq = (1.22D0-0.68D0*eps)/((1.0D0-eps*eps)**2) * sf**2
-
- case (2) ! Peng scaling for double null divertor; TARTs [STAR Code]
- curhat = 1.0D6 * plasc(qpsi,asp,rminor,bt,kappa,triang)/bt
-
- case (3) ! Simple ITER scaling (simply the cylindrical case)
- fq = 1.0D0
-
- case (4) ! ITER formula (IPDG89)
- fq = 0.5D0 * (1.17D0-0.65D0*eps)/((1.0D0-eps*eps)**2) * &
- (1.0D0 + kappa95**2 * &
- (1.0D0 + 2.0D0*triang95**2 - 1.2D0*triang95**3) )
-
- case (5, 6) ! Todd empirical scalings
-
- fq = (1.0D0+2.0D0*eps*eps) * 0.5D0*(1.0D0+kappa95**2) * &
- (1.24D0-0.54D0*kappa95+0.3D0*(kappa95**2 + triang95**2) + &
- 0.125D0*triang95)
-
- if (icurr == 6) fq = fq * (1.0D0 + ( abs(kappa95-1.2D0) )**3)
-
- case (7) ! Connor-Hastie asymptotically-correct expression
-
- ! N.B. If iprofile=1, alphaj will be wrong during the first call (only)
-
- call conhas(alphaj,alphap,bt,triang95,eps,kappa95,p0,fq)
-
- case (8) ! Sauter scaling allowing negative triangularity [FED May 2016]
-
- ! Assumes zero squareness, note takes kappa, delta at separatrix not _95
-
- w07 = 1.0d0 ! zero squareness - can be modified later if required
-
- fq = (1.0d0 + 1.2d0*(kappa - 1.0d0) + 0.56d0*(kappa-1.0d0)**2) * &
- (1.0d0 + 0.09d0 * triang + 0.16d0 * triang**2) * &
- (1.0d0 + 0.45d0 * triang * eps)/(1.0d0 - 0.74d0 * eps) * &
- (1.0d0 + 0.55d0 * (w07 - 1.0d0))
-
- case (9) ! FIESTA ST fit
-
- fq = 0.538D0 * (1.0D0 + 2.440D0*eps**2.736D0) * kappa**2.154D0 * triang**0.060D0
-
- case default
- idiags(1) = icurr ; call report_error(77)
-
- end select
-
- ! Calculate the ratio of plasma current to toroidal field
-
- if (icurr /= 2) then
- curhat = 5.0D6 * rminor**2 / (rmajor*qpsi) * fq
- end if
- if (icurr == 8) then
- curhat = 4.1d6 * rminor**2 / (rmajor*qpsi) * fq
- end if
-
- ! Calculate the equivalent edge safety factor (= qcyl)
-
- qstar = 5.0D6 * rminor**2 / (rmajor*curhat) * 0.5D0 * &
- (1.0D0 + kappa95**2 * &
- (1.0D0 + 2.0D0*triang95**2 - 1.2D0*triang95**3) )
-
- ! Calculate plasma current
-
- plascur = curhat * bt
-
- normalised_total_beta = 1.0D8*beta*rminor*bt/plascur
-
- ! Calculate the poloidal field
-
- bp = bpol(icurr,plascur,qpsi,asp,bt,kappa,triang,pperim)
-
- ! Ensure current profile consistency, if required
- ! This is as described in Hartmann and Zohm only if icurr = 4 as well...
-
- if (iprofile == 1) then
- alphaj = qstar/q0 - 1.0D0
- rli = log(1.65D0 + 0.89D0*alphaj) ! Tokamaks 4th Edition, Wesson, page 116
- end if
-
- contains
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- function plasc(qbar,aspect,rminor,bt,kappa,delta)
-
- !! Function to calculate plasma current (Peng scaling)
- !! author: J Galambos, FEDC/ORNL
- !! author: P J Knight, CCFE, Culham Science Centre
- !! aspect : input real : plasma aspect ratio
- !! bt : input real : toroidal field on axis (T)
- !! delta : input real : plasma triangularity
- !! kappa : input real : plasma elongation
- !! qbar : input real : edge q-bar
- !! rminor : input real : plasma minor radius (m)
- !! This function calculates the plasma current in MA,
- !! using a scaling from Peng, Galambos and Shipe (1992).
- !! It is primarily used for Tight Aspect Ratio Tokamaks and is
- !! selected via icurr=2.
- !! J D Galambos, STAR Code : Spherical Tokamak Analysis and Reactor Code,
- !! unpublished internal Oak Ridge document
- !! Y.-K. M. Peng, J. Galambos and P.C. Shipe, 1992,
- !! Fusion Technology, 21, 1729
- !
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- implicit none
-
- real(dp) :: plasc
-
- ! Arguments
-
- real(dp), intent(in) :: aspect,bt,delta,kappa,qbar,rminor
-
- ! Local variables
-
- real(dp) :: c1,c2,d1,d2,eps,e1,e2,f1,f2,ff1,ff2,g,h1,h2,y1,y2
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- eps = 1.0D0/aspect
-
- c1 = kappa**2/(1.0D0+delta) + delta
- c2 = kappa**2/(1.0D0-delta) - delta
-
- d1 = (kappa/(1.0D0+delta))**2 + 1.0D0
- d2 = (kappa/(1.0D0-delta))**2 + 1.0D0
-
- if (aspect < c1) then
- y1 = sqrt( (c1*eps - 1.0D0)/(1.0D0+eps) ) * (1.0D0 + delta)/kappa
- else
- y1 = sqrt( (1.0D0 - c1*eps)/(1.0D0+eps) ) * (1.0D0 + delta)/kappa
- end if
- y2 = sqrt( (c2*eps+1.0D0)/(1.0D0-eps) ) * (1.0D0-delta)/kappa
-
- e1 = 2.0D0*kappa/(d1*(1.0D0+delta))
- e2 = 2.0D0*kappa/(d2*(1.0D0-delta))
-
- h2 = (1.0D0 + (c2-1.0D0)*eps/2.0D0) / &
- sqrt( (1.0D0-eps)*(c2*eps+1.0D0) )
- f2 = (d2*(1.0D0-delta)*eps) / ( (1.0D0-eps)*(c2*eps+1.0D0) )
- g = eps*kappa / (1.0D0 - eps*delta)
- ff2 = f2 * (g + 2.0D0*h2*atan(y2) )
-
- if (aspect < c1) then
- h1 = (1.0D0 + (1.0D0-c1)*eps/2.0D0) / &
- sqrt( (1.0D0+eps)*(c1*eps-1.0D0) )
- f1 = (d1*(1.0D0+delta)*eps) / ( (1.0D0+eps)*(c1*eps-1.0D0) )
- ff1 = f1*(g - h1*log( (1.0D0+y1)/(1.0D0-y1) ) )
- else
- h1 = (1.0D0 + (1.0D0-c1)*eps/2.0D0) / &
- sqrt( (1.0D0+eps)*(1.0D0-c1*eps) )
- f1 = -(d1*(1.0D0+delta)*eps) / ( (1.0D0+eps)*(c1*eps-1.0D0) )
- ff1 = f1*( -g + 2.0D0*h1*atan(y1) )
- end if
-
- plasc = rminor*bt/qbar * 5.0D0*kappa/(2.0D0*pi**2) * &
- ( asin(e1)/e1 + asin(e2)/e2 ) * (ff1 + ff2)
-
- end function plasc
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- subroutine conhas(alphaj,alphap,bt,delta95,eps,kappa95,p0,fq)
-
- !! Routine to calculate the F coefficient used for scaling the
- !! plasma current
- !! author: P J Knight, CCFE, Culham Science Centre
- !! alphaj : input real : current profile index
- !! alphap : input real : pressure profile index
- !! bt : input real : toroidal field on axis (T)
- !! delta95 : input real : plasma triangularity 95%
- !! eps : input real : inverse aspect ratio
- !! kappa95 : input real : plasma elongation 95%
- !! p0 : input real : central plasma pressure (Pa)
- !! fq : output real : scaling for edge q from circular
- !! cross-section cylindrical case
- !! This routine calculates the F coefficient used for scaling the
- !! plasma current, using the Connor-Hastie scaling given in
- !! AEA FUS 172.
- !! AEA FUS 172: Physics Assessment for the European Reactor Study
- !! AEA FUS 251: A User's Guide to the PROCESS Systems Code
- !
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- implicit none
-
- ! Arguments
-
- real(dp), intent(in) :: alphaj,alphap,bt,delta95,eps,kappa95,p0
- real(dp), intent(out) :: fq
-
- ! Local variables
-
- real(dp) :: beta0, deltap, deltar, eprime, er, kap1, &
- lambda, lamp1, li, nu, tprime, tr
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- ! Exponent in Connor-Hastie current profile - matching total
- ! current gives the following trivial relation
-
- lambda = alphaj
-
- ! Exponent in Connor-Hastie pressure profile
-
- nu = alphap
-
- ! Central plasma beta
-
- beta0 = 2.0D0 * rmu0 * p0 / (bt**2)
-
- ! Plasma internal inductance
-
- lamp1 = 1.0D0 + lambda
- li = lamp1/lambda * (lamp1/lambda * log(lamp1) - 1.0D0)
-
- ! T/r in AEA FUS 172
-
- kap1 = kappa95 + 1.0D0
- tr = kappa95 * delta95 / kap1**2
-
- ! E/r in AEA FUS 172
-
- er = (kappa95-1.0D0)/kap1
-
- ! T primed in AEA FUS 172
-
- tprime = 2.0D0 * tr * lamp1/(1.0D0 + 0.5D0*lambda)
-
- ! E primed in AEA FUS 172
-
- eprime = er * lamp1/(1.0D0 + lambda/3.0D0)
-
- ! Delta primed in AEA FUS 172
-
- deltap = 0.5D0*kap1 * eps * 0.5D0*li + &
- beta0/(0.5D0*kap1*eps) * lamp1**2 / (1.0D0+nu)
-
- ! Delta/R0 in AEA FUS 172
-
- deltar = beta0/6.0D0 * (1.0D0 + 5.0D0*lambda/6.0D0 + 0.25D0*lambda**2) &
- + (0.5D0*kap1*eps)**2 * 0.125D0*(1.0D0-(lambda**2)/3.0D0)
-
- ! F coefficient
-
- fq = (0.5D0*kap1)**2 * &
- ( 1.0D0 + eps**2 * (0.5D0*kap1)**2 + 0.5D0*deltap**2 + &
- 2.0D0*deltar + 0.5D0*(eprime**2 + er**2) + &
- 0.5D0*(tprime**2 + 4.0D0*tr**2) )
-
- end subroutine conhas
-
- end subroutine culcur
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- function bpol(icurr,ip,qbar,aspect,bt,kappa,delta,perim)
-
- !! Function to calculate poloidal field
- !! author: J Galambos, FEDC/ORNL
- !! author: P J Knight, CCFE, Culham Science Centre
- !! icurr : input integer : current scaling model to use
- !! ip : input real : plasma current (A)
- !! qbar : input real : edge q-bar
- !! aspect : input real : plasma aspect ratio
- !! bt : input real : toroidal field on axis (T)
- !! kappa : input real : plasma elongation
- !! delta : input real : plasma triangularity
- !! perim : input real : plasma perimeter (m)
- !! This function calculates the poloidal field in Tesla,
- !! using a simple calculation using Stoke's Law for conventional
- !! tokamaks, or for TARTs, a scaling from Peng, Galambos and
- !! Shipe (1992).
- !! J D Galambos, STAR Code : Spherical Tokamak Analysis and Reactor Code,
- !! unpublished internal Oak Ridge document
- !! Y.-K. M. Peng, J. Galambos and P.C. Shipe, 1992,
- !! Fusion Technology, 21, 1729
- !
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- use constants, only: pi, rmu0
- implicit none
-
- real(dp) :: bpol
-
- ! Arguments
-
- integer, intent(in) :: icurr
- real(dp), intent(in) :: aspect,bt,delta,ip,kappa,perim,qbar
-
- ! Local variables
-
- real(dp) :: c1,c2,d1,d2,eps,f1,f2,ff1,ff2,g,h1,h2,y1,y2
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- if (icurr /= 2) then
-
- ! Stoke's Law
-
- bpol = rmu0 * ip / perim
-
- else ! Original coding, only suitable for TARTs [STAR Code]
-
- eps = 1.0D0/aspect
-
- c1 = kappa**2/(1.0D0+delta) + delta
- c2 = kappa**2/(1.0D0-delta) - delta
-
- d1 = (kappa/(1.0D0+delta))**2 + 1.0D0
- d2 = (kappa/(1.0D0-delta))**2 + 1.0D0
-
- if (aspect < c1) then
- y1 = sqrt( (c1*eps - 1.0D0)/(1.0D0+eps) ) * (1.0D0 + delta)/kappa
- else
- y1 = sqrt( (1.0D0 - c1*eps)/(1.0D0+eps) ) * (1.0D0 + delta)/kappa
- end if
- y2 = sqrt( (c2*eps+1.0D0)/(1.0D0-eps) ) * (1.0D0-delta)/kappa
-
- h2 = (1.0D0 + (c2-1.0D0)*eps/2.0D0) / &
- sqrt( (1.0D0-eps)*(c2*eps+1.0D0) )
- f2 = (d2*(1.0D0-delta)*eps) / ( (1.0D0-eps)*(c2*eps+1.0D0) )
- g = eps*kappa / (1.0D0 - eps*delta)
- ff2 = f2 * (g + 2.0D0*h2*atan(y2) )
-
- if (aspect < c1) then
- h1 = (1.0D0 + (1.0D0-c1)*eps/2.0D0) / &
- sqrt( (1.0D0+eps)*(c1*eps-1.0D0) )
- f1 = (d1*(1.0D0+delta)*eps) / ( (1.0D0+eps)*(c1*eps-1.0D0) )
- ff1 = f1*(g - h1*log( (1.0D0+y1)/(1.0D0-y1) ) )
- else
- h1 = (1.0D0 + (1.0D0-c1)*eps/2.0D0) / &
- sqrt( (1.0D0+eps)*(1.0D0-c1*eps) )
- f1 = -(d1*(1.0D0+delta)*eps) / ( (1.0D0+eps)*(c1*eps-1.0D0) )
- ff1 = f1*( -g + 2.0D0*h1*atan(y1) )
- end if
-
- bpol = bt * (ff1 + ff2) / (2.0D0 * pi * qbar)
-
- end if
-
- end function bpol
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- subroutine culblm(bt,dnbeta,plascur,rminor,betalim)
-
- !! Beta scaling limit
- !! author: P J Knight, CCFE, Culham Science Centre
- !! bt : input real : toroidal B-field on plasma axis (T)
- !! dnbeta : input real : Troyon-like g coefficient
- !! plascur : input real : plasma current (A)
- !! rminor : input real : plasma minor axis (m)
- !! betalim : output real : beta limit as defined below
- !! This subroutine calculates the beta limit, using
- !! the algorithm documented in AEA FUS 172.
- !! The limit applies to beta defined with respect to the total B-field.
- !! Switch iculbl determines which components of beta to include.
- !!
- !! If iculbl = 0, then the limit is applied to the total beta
- !! If iculbl = 1, then the limit is applied to the thermal beta only
- !! If iculbl = 2, then the limit is applied to the thermal +
- !! neutral beam beta components
- !! If iculbl = 3, then the limit is applied to the toroidal beta
- !!
- !! The default value for the g coefficient is dnbeta = 3.5
- !! AEA FUS 172: Physics Assessment for the European Reactor Study
- !! AEA FUS 251: A User's Guide to the PROCESS Systems Code
- !
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- !! switch for beta limit scaling (`constraint equation 24`)
-
- implicit none
-
- ! Arguments
-
- real(dp), intent(in) :: bt, dnbeta, plascur, rminor
- real(dp), intent(out) :: betalim
-
- ! Local variables
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- betalim = 0.01D0 * dnbeta * (plascur/1.0D6) / (rminor*bt)
-
- end subroutine culblm
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- subroutine plasma_composition
-
- !! Calculates various plasma component fractional makeups
- !! author: P J Knight, CCFE, Culham Science Centre
- !! None
- !! This subroutine determines the various plasma component
- !! fractional makeups. It is the replacement for the original
- !! It is the replacement for the original routine betcom,
- !! and is used in conjunction with the new impurity radiation model
- !! None
- !
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- use current_drive_variables, only: ftritbm
- use error_handling, only: fdiags, report_error
- use impurity_radiation_module, only: nimp, impurity_arr_frac, element2index, &
- zav_of_te, impurity_arr_Z, impurity_arr_amass
- use physics_variables, only: alphat, ignite, falpe, afuel, ftrit, deni, &
- aion, dnitot, protium, zeffai, rncne, rnone, falpi, ralpne, dlamee, &
- rnbeam, zeff, dnz, pcoef, alpharate, rnfene, abeam, dlamie, te, &
- protonrate, fdeut, alphan, dnbeam, fhe3, dnalp, dene, dnprot
- use maths_library, only: secant_solve
- implicit none
-
- ! Arguments
-
- ! Local variables
-
- real(dp) :: znimp, pc, znfuel
- integer :: imp
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- ! Ion density components
- ! ======================
-
- ! Alpha ash portion
-
- dnalp = dene * ralpne
-
- ! Protons
- ! This calculation will be wrong on the first call as the particle
- ! production rates are evaluated later in the calling sequence
- ! Issue #557 Allow protium impurity to be specified: 'protium'
- ! This will override the calculated value which is a minimum.
-
- if (alpharate < 1.0D-6) then ! not calculated yet...
- dnprot = max(protium*dene, dnalp * (fhe3 + 1.0D-3)) ! rough estimate
- else
- dnprot = max(protium*dene, dnalp * protonrate/alpharate)
- end if
-
- ! Beam hot ion component
- ! If ignited, prevent beam fusion effects
-
- if (ignite == 0) then
- dnbeam = dene * rnbeam
- else
- dnbeam = 0.0D0
- end if
-
- ! Sum of Zi.ni for all impurity ions (those with charge > helium)
-
- znimp = 0.0D0
- do imp = 1,nimp
- if (impurity_arr_Z(imp) > 2) then
- ! znimp = znimp + impurity_arr(imp)%Z*(impurity_arr_frac(imp) * dene)
- znimp = znimp + Zav_of_te(imp,te)*(impurity_arr_frac(imp) * dene)
- end if
- end do
-
- ! Fuel portion - conserve charge neutrality
- ! znfuel is the sum of Zi.ni for the three fuel ions
-
- znfuel = dene - 2.0D0*dnalp - dnprot - dnbeam - znimp
-
- ! Fuel ion density, deni
- ! For D-T-He3 mix, deni = nD + nT + nHe3, while znfuel = nD + nT + 2*nHe3
- ! So deni = znfuel - nHe3 = znfuel - fhe3*deni
-
- deni = znfuel/(1.0D0+fhe3)
-
- ! Ensure that deni is never negative or zero
-
- if (deni < 0.0D0) then
- fdiags(1) = deni ; call report_error(78)
- deni = max(deni,1.0D0)
- end if
-
- ! Set hydrogen and helium impurity fractions for
- ! radiation calculations
-
- impurity_arr_frac(element2index('H_')) = &
- (dnprot + (fdeut+ftrit)*deni + dnbeam)/dene
-
- impurity_arr_frac(element2index('He')) = fhe3*deni/dene + ralpne
-
- ! Total impurity density
-
- dnz = 0.0D0
- do imp = 1,nimp
- if (impurity_arr_Z(imp) > 2) then
- dnz = dnz + impurity_arr_frac(imp)*dene
- end if
- end do
-
- ! Total ion density
-
- dnitot = deni + dnalp + dnprot + dnbeam + dnz
-
- ! Set some (obsolescent) impurity fraction variables
- ! for the benefit of other routines
-
- rncne = impurity_arr_frac(element2index('C_'))
- rnone = impurity_arr_frac(element2index('O_'))
- ! Issue #261 Remove zfear. Use the sum of Fe and Ar concentrations
- ! if (zfear == 0) then
- ! rnfene = impurity_arr(element2index('Fe'))%frac
- ! else
- ! rnfene = impurity_arr(element2index('Ar'))%frac
- ! end if
- rnfene = impurity_arr_frac(element2index('Fe')) + impurity_arr_frac(element2index('Ar'))
-
- ! Effective charge
- ! Calculation should be sum(ni.Zi^2) / sum(ni.Zi),
- ! but ne = sum(ni.Zi) through quasineutrality
-
- zeff = 0.0D0
- do imp = 1,nimp
- !zeff = zeff + impurity_arr_frac(imp) * (impurity_arr(imp)%Z)**2
- zeff = zeff + impurity_arr_frac(imp) * Zav_of_te(imp,te)**2
- end do
-
- ! Define coulomb logarithm
- ! (collisions: ion-electron, electron-electron)
-
- dlamee = 31.0D0 - (log(dene)/2.0D0) + log(te*1000.0D0)
- dlamie = 31.3D0 - (log(dene)/2.0D0) + log(te*1000.0D0)
-
- ! Fraction of alpha energy to ions and electrons
- ! From Max Fenstermacher
- ! (used with electron and ion power balance equations only)
- ! No consideration of pchargepv here...
-
- ! pcoef now calculated in plasma_profiles, after the very first
- ! call of plasma_composition; use old parabolic profile estimate
- ! in this case
-
- if (first_call == 1) then
- pc = (1.0D0 + alphan)*(1.0D0 + alphat)/(1.0D0+alphan+alphat)
- first_call = 0
- else
- pc = pcoef
- end if
-
- falpe = 0.88155D0 * exp(-te*pc/67.4036D0)
- falpi = 1.0D0 - falpe
-
- ! Average atomic masses
-
- afuel = 2.0D0*fdeut + 3.0D0*ftrit + 3.0D0*fhe3
- abeam = 2.0D0*(1.0D0-ftritbm) + 3.0D0*ftritbm
-
- ! Density weighted mass
-
- aion = afuel*deni + 4.0D0*dnalp + dnprot + abeam*dnbeam
- do imp = 1,nimp
- if (impurity_arr_Z(imp) > 2) then
- aion = aion + dene*impurity_arr_frac(imp)*impurity_arr_amass(imp)
- end if
- end do
- aion = aion/dnitot
-
- ! Mass weighted plasma effective charge
-
- zeffai = ( fdeut*deni/2.0D0 + ftrit*deni/3.0D0 + 4.0D0*fhe3*deni/3.0D0 + &
- dnalp + dnprot + (1.0D0-ftritbm)*dnbeam/2.0D0 + ftritbm*dnbeam/3.0D0 &
- ) / dene
- do imp = 1,nimp
- if (impurity_arr_Z(imp) > 2) then
- zeffai = zeffai + impurity_arr_frac(imp) &
- ! * (impurity_arr(imp)%Z)**2 / impurity_arr_amass(imp)
- * Zav_of_te(imp,te)**2 / impurity_arr_amass(imp)
- end if
- end do
-
- end subroutine plasma_composition
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- subroutine culdlm(bt,idensl,pdivt,plascur,prn1,qcyl,q95, &
- rmajor,rminor,sarea,zeff,dlimit,dnelimt)
-
- !! Density limit calculation
- !! author: P J Knight, CCFE, Culham Science Centre
- !! bt : input real : toroidal field on axis (T)
- !! idensl : input/output integer : switch denoting which formula to enforce
- !! pdivt : input real : power flowing to the edge plasma via
- !! charged particles (MW)
- !! plascur : input real : plasma current (A)
- !! prn1 : input real : edge density / average plasma density
- !! qcyl : input real : equivalent cylindrical safety factor (qstar)
- !! q95 : input real : safety factor at 95% surface
- !! rmajor : input real : plasma major radius (m)
- !! rminor : input real : plasma minor radius (m)
- !! sarea : input real : plasma surface area (m**2)
- !! zeff : input real : plasma effective charge
- !! dlimit(7): output real array : average plasma density limit using
- !! seven different models (m**-3)
- !! dnelimt : output real : enforced average plasma density limit (m**-3)
- !! This routine calculates several different formulae for the
- !! density limit, and enforces the one chosen by the user.
- !! AEA FUS 172: Physics Assessment for the European Reactor Study
- !! AEA FUS 251: A User's Guide to the PROCESS Systems Code
- !
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- use error_handling, only: fdiags, idiags, report_error
- use constants, only: pi
- implicit none
-
- ! Arguments
-
- integer, intent(inout) :: idensl
- real(dp), intent(in) :: bt, pdivt, plascur, prn1, q95, &
- qcyl, rmajor, rminor, sarea, zeff
- real(dp), intent(out) :: dnelimt
- real(dp), dimension(7), intent(out) :: dlimit
-
- ! Local variables
-
- real(dp) :: denom, dlim, qperp
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- ! Check for illegal values of IDENSL
-
- if ((idensl < 1).or.(idensl > 7)) then
- idiags(1) = idensl ; call report_error(79)
- end if
-
- dlimit(:) = 0.0D0
-
- ! Power per unit area crossing the plasma edge
- ! (excludes radiation and neutrons)
-
- qperp = pdivt/sarea
-
- ! Old ASDEX density limit formula
- ! This applies to the density at the plasma edge, so must be scaled
- ! to give the density limit applying to the average plasma density.
-
- dlim = 1.54D20 * qperp**0.43D0 * bt**0.31D0 /(q95*rmajor)**0.45D0
- dlimit(1) = dlim/prn1
-
- ! Borrass density limit model for ITER (I)
- ! This applies to the density at the plasma edge, so must be scaled
- ! to give the density limit applying to the average plasma density.
- ! Borrass et al, ITER-TN-PH-9-6 (1989)
-
- dlim = 1.8D20 * qperp**0.53D0 * bt**0.31D0 /(q95*rmajor)**0.22D0
- dlimit(2) = dlim/prn1
-
- ! Borrass density limit model for ITER (II)
- ! This applies to the density at the plasma edge, so must be scaled
- ! to give the density limit applying to the average plasma density.
- ! This formula is (almost) identical to that in the original routine
- ! denlim (now deleted).
-
- dlim = 0.5D20 * qperp**0.57D0 * bt**0.31D0 /(q95*rmajor)**0.09D0
- dlimit(3) = dlim/prn1
-
- ! JET edge radiation density limit model
- ! This applies to the density at the plasma edge, so must be scaled
- ! to give the density limit applying to the average plasma density.
- ! qcyl=qstar here, but literature is not clear.
-
- denom = (zeff-1.0D0)*( 1.0D0-4.0D0/(3.0D0*qcyl) )
- if (denom <= 0.0D0) then
- if (idensl == 4) then
- fdiags(1) = denom ; fdiags(2) = qcyl
- call report_error(80)
- idensl = 5
- end if
- dlimit(4) = 0.0D0
- else
- dlim = 1.0D20 * sqrt(pdivt/denom)
- dlimit(4) = dlim/prn1
- end if
-
- ! JET simplified density limit model
- ! This applies to the density at the plasma edge, so must be scaled
- ! to give the density limit applying to the average plasma density.
-
- dlim = 0.237D20 * bt * sqrt(pdivt)/rmajor
- dlimit(5) = dlim/prn1
-
- ! Hugill-Murakami M.q limit
- ! qcyl=qstar here, which is okay according to the literature
-
- dlimit(6) = 3.0D20 * bt / (rmajor*qcyl)
-
- ! Greenwald limit
-
- dlimit(7) = 1.0D14 * plascur/(pi*rminor*rminor)
-
- ! Enforce the chosen density limit
-
- dnelimt = dlimit(idensl)
-
- end subroutine culdlm
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- subroutine pcond(afuel,palpmw,aspect,bt,dnitot,dene,dnla,eps,hfact, &
- iinvqd,isc,ignite,kappa,kappa95,kappaa,pchargemw,pinjmw,&
- plascur,pcoreradpv,rmajor,rminor,te,ten,tin,q,qstar,vol, &
- xarea,zeff,ptrepv,ptripv,tauee,tauei,taueff,powerht)
-
- !! Routine to calculate the confinement times and
- !! the transport power loss terms.
- !! author: P J Knight, CCFE, Culham Science Centre
- !! afuel : input real : average mass of fuel (amu)
- !! palpmw : input real : alpha particle power (MW)
- !! aspect : input real : aspect ratio
- !! bt : input real : toroidal field on axis (T)
- !! dene : input real : volume averaged electron density (/m3)
- !! dnitot : input real : total ion density (/m3)
- !! dnla : input real : line-averaged electron density (/m3)
- !! eps : input real : inverse aspect ratio
- !! hfact : input real : H factor on energy confinement scalings
- !! iinvqd : input integer : switch for inverse quadrature
- !! isc : input integer : switch for energy confinement scaling to use
- !! ignite : input integer : switch for ignited calculation
- !! kappa : input real : plasma elongation
- !! kappa95 : input real : plasma elongation at 95% surface
- !! kappaa : output real : plasma elongation calculated using area ratio
- !! pchargemw : input real : non-alpha charged particle fusion power (MW)
- !! pinjmw : input real : auxiliary power to ions and electrons (MW)
- !! plascur : input real : plasma current (A)
- !! pcoreradpv: input real : total core radiation power (MW/m3)
- !! q : input real : edge safety factor (tokamaks), or
- !! rotational transform iotabar (stellarators)
- !! qstar : input real : equivalent cylindrical edge safety factor
- !! rmajor : input real : plasma major radius (m)
- !! rminor : input real : plasma minor radius (m)
- !! te : input real : average electron temperature (keV)
- !! ten : input real : density weighted average electron temp. (keV)
- !! tin : input real : density weighted average ion temperature (keV)
- !! vol : input real : plasma volume (m3)
- !! xarea : input real : plasma cross-sectional area (m2)
- !! zeff : input real : plasma effective charge
- !! ptrepv : output real : electron transport power (MW/m3)
- !! ptripv : output real : ion transport power (MW/m3)
- !! tauee : output real : electron energy confinement time (s)
- !! taueff : output real : global energy confinement time (s)
- !! tauei : output real : ion energy confinement time (s)
- !! powerht : output real : heating power (MW) assumed in calculation
- !! This subroutine calculates the energy confinement time
- !! using one of a large number of scaling laws, and the
- !! transport power loss terms.
- !! AEA FUS 251: A User's Guide to the PROCESS Systems Code
- !! N. A. Uckan and ITER Physics Group,
- !! "ITER Physics Design Guidelines: 1989",
- !! ITER Documentation Series, No. 10, IAEA/ITER/DS/10 (1990)
- !! ITER Documentation Series, No. 10, IAEA/ITER/DS/10 (1990)
- !! A. Murari et al 2015 Nucl. Fusion, 55, 073009
- !! C.C. Petty 2008 Phys. Plasmas, 15, 080501
- !! P.T. Lang et al. 2012 IAEA conference proceeding EX/P4-01
- !! ITER physics basis Chapter 2, 1999 Nuclear Fusion 39 2175
- !! Nuclear Fusion corrections, 2008 Nuclear Fusion 48 099801
- !! Menard 2019, Phil. Trans. R. Soc. A 377:20170440
- !! Kaye et al. 2006, Nucl. Fusion 46 848
- !
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- use error_handling, only: idiags, report_error
- use physics_variables, only: iradloss, tauee_in, pradpv, kappaa_ipb, &
- pohmmw, falpha
- use startup_variables, only: ptaue, gtaue, ftaue, rtaue, qtaue
- use constants, only: pi
- implicit none
-
- ! Arguments
- integer, intent(in) :: iinvqd, isc, ignite
- real(dp), intent(in) :: afuel, palpmw, aspect, bt, dene, &
- dnitot, dnla, eps, hfact, kappa, kappa95, pchargemw, pinjmw, &
- plascur, pcoreradpv, q, qstar, rmajor, rminor, te, &
- ten, tin, vol, xarea, zeff
- real(dp), intent(out) :: kappaa, powerht, ptrepv, ptripv, &
- tauee, taueff, tauei
-
- ! Local variables
- real(dp) :: chii,ck2,denfac,dnla19,dnla20,eps2,gjaeri,iotabar, &
- n20,pcur,qhat,ratio,rll,str2,str5,taueena,tauit1,tauit2, &
- term1,term2, h, qratio, nratio, nGW, taunstx,taupetty
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- ! Neoclassical ion transport loss
- ! Calculate ion energy confinement time
- !
- ! N.B. This calculation is superseded later in the routine
-
- eps2 = eps/2.0D0
- str5 = (2.0D0/(1.0D0+(kappa**2)))
- ck2 = (0.66D0+(1.88D0*(sqrt(eps2)))-(1.54D0*eps2))* &
- (1.0D0+(1.5D0*(eps2**2)))
- chii = (6.5D-22)*ck2*zeff*(aspect**1.5D0)*dene*(q**2)*str5/ &
- ((sqrt(tin))*(bt**2))
- str2 = (2.0D0*(kappa**2)/(1.0D0+(kappa**2)))
- tauei = 0.375D0*rminor**2/chii*str2
-
- ! Calculate heating power (MW)
- powerht = falpha*palpmw + pchargemw + pohmmw
-
- ! If the device is not ignited, add the injected auxiliary power
- if (ignite == 0) powerht = powerht + pinjmw
-
- ! Include the radiation as a loss term if requested
- if (iradloss == 0) then
- powerht = powerht - pradpv*vol
- else if (iradloss == 1) then
- powerht = powerht - pcoreradpv*vol ! shouldn't this be vol_core instead of vol?
- else
- continue ! do not adjust powerht for radiation
- end if
-
- ! Ensure heating power is positive (shouldn't be necessary)
- powerht = max(powerht,1.0D-3)
-
- ! Line averaged electron density in scaled units
- dnla20 = dnla * 1.0D-20
- dnla19 = dnla * 1.0D-19
-
- ! Volume averaged electron density in units of 10**20 m**-3
- n20 = dene / 1.0D20
-
- ! Plasma current in MA
- pcur = plascur / 1.0D6
-
- ! Separatrix kappa defined with X-section for general use
- kappaa = xarea/(pi*rminor*rminor)
-
- ! Separatrix kappa defined with plasma volume for IPB scalings
- kappaa_IPB = vol / ( 2.0D0 * pi*pi * rminor*rminor * rmajor )
-
- ! Calculate Neo-Alcator confinement time (used in several scalings)
- taueena = 0.07D0 * n20 * rminor * rmajor*rmajor * qstar
-
- ! For reference (see startup.f90):
- ! gtaue = offset term in tauee scaling
- ! ptaue = exponent for density term in tauee scaling
- ! qtaue = exponent for temperature term in tauee scaling
- ! rtaue = exponent for power term in tauee scaling
-
- ! Electron energy confinement times
-
- select case (isc)
-
- case (1) ! Neo-Alcator scaling (ohmic)
- !tauee = taueena
- tauee = hfact * taueena
- gtaue = 0.0D0
- ptaue = 1.0D0
- qtaue = 0.0D0
- rtaue = 0.0D0
-
- case (2) ! Mirnov scaling (H-mode)
- tauee = hfact * 0.2D0 * rminor * sqrt(kappa95) * pcur
- gtaue = 0.0D0
- ptaue = 0.0D0
- qtaue = 0.0D0
- rtaue = 0.0D0
-
- case (3) ! Merezhkin-Muhkovatov scaling (L-mode)
- tauee = hfact * 3.5D-3 * rmajor**2.75D0 * rminor**0.25D0 * &
- kappa95**0.125D0 * qstar * dnla20 * sqrt(afuel) / &
- sqrt(ten/10.0D0)
- gtaue = 0.0D0
- ptaue = 1.0D0
- qtaue = -0.5D0
- rtaue = 0.0D0
-
- case (4) ! Shimomura scaling (H-mode)
- tauee = hfact * 0.045D0 * rmajor * rminor * bt * sqrt(kappa95) &
- * sqrt(afuel)
- gtaue = 0.0D0
- ptaue = 0.0D0
- qtaue = 0.0D0
- rtaue = 0.0D0
-
- case (5) ! Kaye-Goldston scaling (L-mode)
- tauee = hfact * 0.055D0 * kappa95**0.28D0 * pcur**1.24D0 * &
- n20**0.26D0 * rmajor**1.65D0 * sqrt(afuel/1.5D0) / &
- ( bt**0.09D0 * rminor**0.49D0 * powerht**0.58D0 )
- gtaue = 0.0D0
- ptaue = 0.26D0
- qtaue = 0.0D0
- rtaue = -0.58D0
- if (iinvqd /= 0) tauee = 1.0D0 / &
- sqrt(1.0D0/taueena**2 + 1.0D0/tauee**2)
-
- case (6) ! ITER Power scaling - ITER 89-P (L-mode)
- tauee = hfact * 0.048D0 * pcur**0.85D0 * rmajor**1.2D0 * &
- rminor**0.3D0 * sqrt(kappa) * dnla20**0.1D0 * bt**0.2D0 * &
- sqrt(afuel) / sqrt(powerht)
- gtaue = 0.0D0
- ptaue = 0.1D0
- qtaue = 0.0D0
- rtaue = -0.5D0
-
- case (7) ! ITER Offset linear scaling - ITER 89-O (L-mode)
-
- term1 = 0.04D0 * pcur**0.5D0 * rmajor**0.3D0 * &
- rminor**0.8D0 * kappa**0.6D0 * afuel**0.5D0
- term2 = 0.064D0 * pcur**0.8D0 * rmajor**1.6D0 * &
- rminor**0.6D0 * kappa**0.5D0 * dnla20**0.6D0 * &
- bt**0.35D0 * afuel**0.2D0 / powerht
- tauee = hfact * (term1 + term2)
- gtaue = hfact*term1
- ptaue = 0.6D0
- qtaue = 0.0D0
- rtaue = -1.0D0
-
- case (8) ! Rebut-Lallia offset linear scaling (L-mode)
- rll = (rminor**2 * rmajor * kappa95)**0.333D0
- tauee = hfact * 1.65D0 * sqrt(afuel/2.0D0) * &
- ( 1.2D-2 * pcur * rll**1.5D0 / sqrt(zeff) + &
- 0.146D0 * dnla20**0.75D0 * sqrt(pcur) * sqrt(bt) * &
- rll**2.75D0 * zeff**0.25D0 /powerht )
- gtaue = hfact * 1.65D0 * sqrt(afuel/2.0D0) * &
- (1.2D-2 * pcur * rll**1.5D0 / sqrt(zeff))
- ptaue = 0.75D0
- qtaue = 0.0D0
- rtaue = -1.0D0
-
- case (9) ! Goldston scaling (L-mode)
- tauee = hfact * 0.037D0 * pcur * rmajor**1.75D0 * &
- rminor**(-0.37D0) * sqrt(kappa95) * sqrt(afuel/1.5D0) / &
- sqrt(powerht)
- gtaue = 0.0D0
- ptaue = 0.0D0
- qtaue = 0.0D0
- rtaue = -0.5D0
- if (iinvqd /= 0) tauee = 1.0D0 / &
- sqrt(1.0D0/taueena**2 + 1.0D0/tauee**2)
-
- case (10) ! T10 scaling
- denfac = dnla20 * rmajor * qstar / (1.3D0*bt)
- denfac = min(1.0D0,denfac)
- tauee = hfact * 0.095D0 * rmajor * rminor * bt * &
- sqrt(kappa95) * denfac / powerht**0.4D0 * &
- ( zeff**2 * pcur**4 / &
- (rmajor * rminor * qstar**3 * kappa95**1.5D0) )**0.08D0
- gtaue = 0.0D0
- ptaue = 1.0D0
- qtaue = 0.0D0
- rtaue = -0.4D0
-
- case (11) ! JAERI scaling
- gjaeri = zeff**0.4D0 * ((15.0D0-zeff)/20.0D0)**0.6D0 * &
- (3.0D0 * qstar * (qstar+5.0D0) / ((qstar+2.0D0) * &
- (qstar+7.0D0)))**0.6D0
- tauee = hfact * (0.085D0 * kappa95 * rminor**2 * sqrt(afuel) + &
- 0.069D0 * n20**0.6D0 * pcur * bt**0.2D0 * rminor**0.4D0 * &
- rmajor**1.6D0 * sqrt(afuel) * gjaeri * kappa95**0.2D0 / &
- powerht)
- gtaue = hfact * 0.085D0 * kappa95 * rminor**2 * sqrt(afuel)
- ptaue = 0.6D0
- qtaue = 0.0D0
- rtaue = -1.0D0
-
- case (12) ! Kaye-Big scaling
- tauee = hfact * 0.105D0 * sqrt(rmajor) * rminor**0.8D0 * &
- bt**0.3D0 * kappa95**0.25D0 * pcur**0.85D0 * &
- n20**0.1D0 * afuel**0.5D0 / powerht**0.5D0
- gtaue = 0.0D0
- ptaue = 0.1D0
- qtaue = 0.0D0
- rtaue = -0.5D0
-
- case (13) ! ITER H-mode scaling - ITER H90-P
- tauee = hfact * 0.064D0 * pcur**0.87D0 * rmajor**1.82D0 * &
- rminor**(-0.12D0) * kappa**0.35D0 * dnla20**0.09D0 * &
- bt**0.15D0 * sqrt(afuel) / sqrt(powerht)
- gtaue = 0.0D0
- ptaue = 0.09D0
- qtaue = 0.0D0
- rtaue = -0.5D0
-
- case (14) ! Minimum of ITER 89-P (isc=6) and ITER 89-O (isc=7)
- tauit1 = hfact * 0.048D0 * pcur**0.85D0 * rmajor**1.2D0 * &
- rminor**0.3D0 * sqrt(kappa) * dnla20**0.1D0 * bt**0.2D0 * &
- sqrt(afuel) / sqrt(powerht)
- term1 = 0.04D0 * pcur**0.5D0 * rmajor**0.3D0 * &
- rminor**0.8D0 * kappa**0.6D0 * afuel**0.5D0
- term2 = 0.064D0 * pcur**0.8D0 * rmajor**1.6D0 * &
- rminor**0.6D0 * kappa**0.5D0 * dnla20**0.6D0 * &
- bt**0.35D0 * afuel**0.2D0 / powerht
- tauit2 = hfact * (term1 + term2)
- tauee = min(tauit1,tauit2)
-
- if (tauit1 < tauit2) then
- gtaue = 0.0D0
- ptaue = 0.1D0
- qtaue = 0.0D0
- rtaue = -0.5D0
- else
- gtaue = hfact*term1
- ptaue = 0.6D0
- qtaue = 0.0D0
- rtaue = -1.0D0
- end if
-
- case (15) ! Riedel scaling (L-mode)
- tauee = hfact * 0.044D0 * pcur**0.93D0 * rmajor**1.37D0 * &
- rminor**(-0.049D0) * kappa95**0.588D0 * dnla20**0.078D0 * &
- bt**0.152D0 / powerht**0.537D0
- gtaue = 0.0D0
- ptaue = 0.078D0
- qtaue = 0.0D0
- rtaue = -0.537D0
-
- case (16) ! Christiansen et al scaling (L-mode)
- tauee = hfact * 0.24D0 * pcur**0.79D0 * rmajor**0.56D0 * &
- rminor**1.46D0 * kappa95**0.73D0 * dnla20**0.41D0 * &
- bt**0.29D0 / (powerht**0.79D0 * afuel**0.02D0)
- gtaue = 0.0D0
- ptaue = 0.41D0
- qtaue = 0.0D0
- rtaue = -0.79D0
-
- case (17) ! Lackner-Gottardi scaling (L-mode)
- qhat = (1.0D0+kappa95**2) * rminor**2 * bt /(0.4D0 * pcur * rmajor)
- tauee = hfact * 0.12D0 * pcur**0.8D0 * rmajor**1.8D0 * &
- rminor**0.4D0 * kappa95 * (1.0D0+kappa95)**(-0.8D0) * &
- dnla20**0.6D0 * qhat**0.4D0 / powerht**0.6D0
- gtaue = 0.0D0
- ptaue = 0.6D0
- qtaue = 0.0D0
- rtaue = -0.6D0
-
- case (18) ! Neo-Kaye scaling (L-mode)
- tauee = hfact * 0.063D0 * pcur**1.12D0 * rmajor**1.3D0 * &
- rminor**(-0.04D0) * kappa95**0.28D0 * dnla20**0.14D0 * &
- bt**0.04D0 * sqrt(afuel) / powerht**0.59D0
- gtaue = 0.0D0
- ptaue = 0.14D0
- qtaue = 0.0D0
- rtaue = -0.59D0
-
- case (19) ! Riedel scaling (H-mode)
- tauee = hfact * 0.1D0 * sqrt(afuel) * pcur**0.884D0 * &
- rmajor**1.24D0 * rminor**(-0.23D0) * kappa95**0.317D0 * &
- bt**0.207D0 * dnla20**0.105D0 / powerht**0.486D0
- gtaue = 0.0D0
- ptaue = 0.105D0
- qtaue = 0.0D0
- rtaue = -0.486D0
-
- case (20) ! Amended version of ITER H90-P law
- ! Nuclear Fusion 32 (1992) 318
- tauee = hfact * 0.082D0 * pcur**1.02D0 * &
- bt**0.15D0 * sqrt(afuel) * rmajor**1.60D0 / &
- (powerht**0.47D0 * kappa**0.19D0)
- gtaue = 0.0D0
- ptaue = 0.0D0
- qtaue = 0.0D0
- rtaue = -0.47D0
-
- case (21) ! Large Helical Device scaling (stellarators)
- ! S.Sudo, Y.Takeiri, H.Zushi et al., Nuclear Fusion 30 (1990) 11
- tauee = hfact * 0.17D0 * rmajor**0.75D0 * rminor**2 * &
- dnla20**0.69D0 * bt**0.84D0 * powerht**(-0.58D0)
- gtaue = 0.0D0
- ptaue = 0.69D0
- qtaue = 0.0D0
- rtaue = 0.58D0
-
- case (22) ! Gyro-reduced Bohm scaling
- ! R.J.Goldston, H.Biglari, G.W.Hammett et al., Bull.Am.Phys.Society,
- ! volume 34, 1964 (1989)
- tauee = hfact * 0.25D0 * bt**0.8D0 * dnla20**0.6D0 * &
- powerht**(-0.6D0) * rminor**2.4D0 * rmajor**0.6D0
- gtaue = 0.0D0
- ptaue = 0.6D0
- qtaue = 0.0D0
- rtaue = -0.6D0
-
- case (23) ! Lackner-Gottardi stellarator scaling
- ! K.Lackner and N.A.O.Gottardi, Nuclear Fusion, 30, p.767 (1990)
- iotabar = q ! dummy argument q is actual argument iotabar for stellarators
- tauee = hfact * 0.17D0 * rmajor * rminor**2 * dnla20**0.6D0 * &
- bt**0.8D0 * powerht**(-0.6D0) * iotabar**0.4D0
- gtaue = 0.0D0
- ptaue = 0.6D0
- qtaue = 0.0D0
- rtaue = -0.6D0
-
- case (24) ! ITER-93H scaling (ELM-free; multiply by 0.85 for ELMy version)
- ! S.Kaye and the ITER Joint Central Team and Home Teams, in Plasma
- ! Physics and Controlled Nuclear Fusion Research (Proc. 15th
- ! Int. Conf., Seville, 1994) IAEA-CN-60/E-P-3
- tauee = hfact * 0.053D0 * pcur**1.06D0 * bt**0.32D0 * &
- powerht**(-0.67D0) * afuel**0.41D0 * rmajor**1.79D0 * &
- dnla20**0.17D0 * aspect**0.11D0 * kappa**0.66D0
- gtaue = 0.0D0
- ptaue = 0.17D0
- qtaue = 0.0D0
- rtaue = -0.67D0
-
- case (25) ! Issue #508 Remove RFP option.
-
- ! Next two are ITER-97 H-mode scalings
- ! J. G. Cordey et al., EPS Berchtesgaden, 1997
-
- case (26) ! ELM-free: ITERH-97P
- tauee = hfact * 0.031D0 * pcur**0.95D0 * bt**0.25D0 * &
- powerht**(-0.67D0) * dnla19**0.35D0 * &
- rmajor**1.92D0 * aspect**(-0.08D0) * kappa**0.63D0 * &
- afuel**0.42D0
- gtaue = 0.0D0
- ptaue = 0.35D0
- qtaue = 0.0D0
- rtaue = -0.67D0
-
- case (27) ! ELMy: ITERH-97P(y)
- tauee = hfact * 0.029D0 * pcur**0.90D0 * bt**0.20D0 * &
- powerht**(-0.66D0) * dnla19**0.40D0 * &
- rmajor**2.03D0 * aspect**(-0.19D0) * kappa**0.92D0 * &
- afuel**0.2D0
- gtaue = 0.0D0
- ptaue = 0.4D0
- qtaue = 0.0D0
- rtaue = -0.66D0
-
- case (28) ! ITER-96P (= ITER-97L) L-mode scaling
- ! S.M.Kaye and the ITER Confinement Database Working Group,
- ! Nuclear Fusion 37 (1997) 1303
- ! N.B. tau_th formula used
- tauee = hfact * 0.023D0 * pcur**0.96D0 * bt**0.03D0 * &
- kappa95**0.64D0 * rmajor**1.83D0 * aspect**0.06D0 * &
- dnla19**0.40D0 * afuel**0.20D0 * powerht**(-0.73D0)
- gtaue = 0.0D0
- ptaue = 0.4D0
- qtaue = 0.0D0
- rtaue = -0.73D0
-
- case (29) ! Valovic modified ELMy-H mode scaling
- tauee = hfact * 0.067D0 * pcur**0.9D0 * bt**0.17D0 * &
- dnla19**0.45D0 * afuel**0.05D0 * rmajor**1.316D0 * &
- rminor**0.79D0 * kappa**0.56D0 * powerht**(-0.68D0)
- gtaue = 0.0D0
- ptaue = 0.45D0
- qtaue = 0.0D0
- rtaue = -0.68D0
-
- case (30) ! Kaye PPPL Workshop April 1998 L-mode scaling
- tauee = hfact * 0.021D0 * pcur**0.81D0 * bt**0.14D0 * &
- kappa**0.7D0 * rmajor**2.01D0 * aspect**(-0.18D0) * &
- dnla19**0.47D0 * afuel**0.25D0 * powerht**(-0.73D0)
- gtaue = 0.0D0
- ptaue = 0.47D0
- qtaue = 0.0D0
- rtaue = -0.73D0
-
- case (31) ! ITERH-PB98P(y), ELMy H-mode scaling
- tauee = hfact * 0.0615D0 * pcur**0.9D0 * bt**0.1D0 * &
- dnla19**0.4D0 * powerht**(-0.66D0) * rmajor**2 * &
- kappaa**0.75D0 * aspect**(-0.66D0) * afuel**0.2D0
- gtaue = 0.0D0
- ptaue = 0.4D0
- qtaue = 0.0D0
- rtaue = -0.66D0
-
- case (32) ! IPB98(y), ELMy H-mode scaling
- ! Data selection : full ITERH.DB3
- ! Nuclear Fusion 39 (1999) 2175, Table 5
- tauee = hfact * 0.0365D0 * pcur**0.97D0 * bt**0.08D0 * &
- dnla19**0.41D0 * powerht**(-0.63D0) * rmajor**1.93D0 * &
- kappa**0.67D0 * aspect**(-0.23D0) * afuel**0.2D0
- gtaue = 0.0D0
- ptaue = 0.41D0
- qtaue = 0.0D0
- rtaue = -0.63D0
-
- case (33) ! IPB98(y,1), ELMy H-mode scaling
- ! Data selection : full ITERH.DB3
- ! Nuclear Fusion 39 (1999) 2175, Table 5
- tauee = hfact * 0.0503D0 * pcur**0.91D0 * bt**0.15D0 * &
- dnla19**0.44D0 * powerht**(-0.65D0) * rmajor**2.05D0 * &
- kappaa_IPB**0.72D0 * aspect**(-0.57D0) * afuel**0.13D0
- gtaue = 0.0D0
- ptaue = 0.44D0
- qtaue = 0.0D0
- rtaue = -0.65D0
-
- case (34) ! IPB98(y,2), ELMy H-mode scaling
- ! Data selection : ITERH.DB3, NBI only
- ! Nuclear Fusion 39 (1999) 2175, Table 5
- tauee = hfact * 0.0562D0 * pcur**0.93D0 * bt**0.15D0 * &
- dnla19**0.41D0 * powerht**(-0.69D0) * rmajor**1.97D0 * &
- kappaa_IPB**0.78D0 * aspect**(-0.58D0) * afuel**0.19D0
- gtaue = 0.0D0
- ptaue = 0.41D0
- qtaue = 0.0D0
- rtaue = -0.69D0
-
- case (35) ! IPB98(y,3), ELMy H-mode scaling
- ! Data selection : ITERH.DB3, NBI only, no C-Mod
- ! Nuclear Fusion 39 (1999) 2175, Table 5
- tauee = hfact * 0.0564D0 * pcur**0.88D0 * bt**0.07D0 * &
- dnla19**0.40D0 * powerht**(-0.69D0) * rmajor**2.15D0 * &
- kappaa_IPB**0.78D0 * aspect**(-0.64D0) * afuel**0.20D0
- gtaue = 0.0D0
- ptaue = 0.4D0
- qtaue = 0.0D0
- rtaue = -0.69D0
-
- case (36) ! IPB98(y,4), ELMy H-mode scaling
- ! Data selection : ITERH.DB3, NBI only, ITER like devices
- ! Nuclear Fusion 39 (1999) 2175, Table 5
- tauee = hfact * 0.0587D0 * pcur**0.85D0 * bt**0.29D0 * &
- dnla19**0.39D0 * powerht**(-0.70D0) * rmajor**2.08D0 * &
- kappaa_IPB**0.76D0 * aspect**(-0.69D0) * afuel**0.17D0
- gtaue = 0.0D0
- ptaue = 0.39D0
- qtaue = 0.0D0
- rtaue = -0.70D0
-
- case (37) ! ISS95 stellarator scaling
- ! U. Stroth et al., Nuclear Fusion, 36, p.1063 (1996)
- ! Assumes kappa = 1.0, triang = 0.0
- iotabar = q ! dummy argument q is actual argument iotabar for stellarators
- tauee = hfact * 0.079D0 * rminor**2.21D0 * rmajor**0.65D0 * dnla19**0.51D0 * &
- bt**0.83D0 * powerht**(-0.59D0) * iotabar**0.4D0
- gtaue = 0.0D0
- ptaue = 0.51D0
- qtaue = 0.0D0
- rtaue = -0.59D0
-
- case (38) ! ISS04 stellarator scaling
- ! H. Yamada et al., Nuclear Fusion, 45, p.1684 (2005)
- ! Assumes kappa = 1.0, triang = 0.0
- iotabar = q ! dummy argument q is actual argument iotabar for stellarators
- tauee = hfact * 0.134D0 * rminor**2.28D0 * rmajor**0.64D0 * dnla19**0.54D0 * &
- bt**0.84D0 * powerht**(-0.61D0) * iotabar**0.41D0
- gtaue = 0.0D0
- ptaue = 0.54D0
- qtaue = 0.0D0
- rtaue = -0.61D0
-
- case (39) ! DS03 beta-independent H-mode scaling
- ! T. C. Luce, C. C. Petty and J. G. Cordey,
- ! Plasma Phys. Control. Fusion 50 (2008) 043001, eqn.4.13, p.67
- tauee = hfact * 0.028D0 * pcur**0.83D0 * bt**0.07D0 * &
- dnla19**0.49D0 * powerht**(-0.55D0) * rmajor**2.11D0 * &
- kappa95**0.75D0 * aspect**(-0.3D0) * afuel**0.14D0
- gtaue = 0.0D0
- ptaue = 0.49D0
- qtaue = 0.0D0
- rtaue = -0.55D0
-
- case (40) ! "Non-power law" (NPL) Murari energy confinement scaling
- ! Based on the ITPA database of H-mode discharges
- ! A new approach to the formulation and validation of scaling expressions for plasma confinement in tokamaks
- ! A. Murari et al 2015 Nucl. Fusion 55 073009, doi:10.1088/0029-5515/55/7/073009
- ! Table 4. (Issue #311)
- ! Note that aspect ratio and M (afuel) do not appear, and B (bt) only
- ! appears in the "saturation factor" h.
- h = dnla19**0.448D0 / (1.0D0 + exp(-9.403D0*(bt/dnla19)**1.365D0))
- tauee = hfact * 0.0367D0 * pcur**1.006D0 * rmajor**1.731D0 * kappaa**1.450D0 * &
- powerht**(-0.735D0) * h
-
- gtaue = 0.0D0
- ptaue = 0.448D0
- qtaue = 0.0D0
- rtaue = -0.735D0
-
- case (41) ! Beta independent dimensionless confinement scaling
- ! C.C. Petty 2008 Phys. Plasmas 15, 080501, equation 36
- ! Note that there is no dependence on the average fuel mass 'afuel'
- tauee = hfact * 0.052D0 * pcur**0.75D0 * bt**0.3D0 * &
- dnla19**0.32D0 * powerht**(-0.47D0) * rmajor**2.09D0 * &
- kappaa**0.88D0 * aspect**(-0.84D0)
-
- gtaue = 0.0D0
- ptaue = 0.32D0
- qtaue = 0.0D0
- rtaue = -0.47D0
-
- case (42) ! High density relevant confinement scaling
- ! P.T. Lang et al. 2012, IAEA conference proceeding EX/P4-01
- ! q should be q95: incorrect if icurr = 2 (ST current scaling)
- qratio = q/qstar
- ! Greenwald density in m^-3
- nGW = 1.0D14 * plascur/(pi*rminor*rminor)
- nratio = dnla/nGW
- tauee = hfact * 6.94D-7 * plascur**1.3678D0 * bt**0.12D0 * &
- dnla**0.032236D0 * (powerht*1.0D6)**(-0.74D0) * rmajor**1.2345D0 * &
- kappaa_IPB**0.37D0 * aspect**2.48205D0 * afuel**0.2D0 * &
- qratio**0.77D0 * aspect**(-0.9D0*log(aspect)) * &
- nratio**(-0.22D0*log(nratio))
-
- gtaue = 0.0D0
- ptaue = 0.032236D0 -0.22D0*log(nratio)
- qtaue = 0.0D0
- rtaue = -0.74D0
-
- case (43) ! Hubbard et al. 2017 I-mode confinement time scaling - nominal
- tauee = hfact * 0.014D0 * (plascur/1.0D6)**0.68D0 * bt**0.77D0 * dnla20**0.02D0 &
- * powerht**(-0.29D0)
- gtaue = 0.0D0
- ptaue = 0.02D0
- qtaue = 0.0D0
- rtaue = -0.29D0
-
- case (44) ! Hubbard et al. 2017 I-mode confinement time scaling - lower
- tauee = hfact * 0.014D0 * (plascur/1.0D6)**0.60D0 * bt**0.70D0 * dnla20**(-0.03D0) &
- * powerht**(-0.33D0)
- gtaue = 0.0D0
- ptaue = -0.03D0
- qtaue = 0.0D0
- rtaue = -0.33D0
-
- case (45) ! Hubbard et al. 2017 I-mode confinement time scaling - upper
- tauee = hfact * 0.014D0 * (plascur/1.0D6)**0.76D0 * bt**0.84D0 * dnla20**0.07 &
- * powerht**(-0.25D0)
- gtaue = 0.0D0
- ptaue = 0.07D0
- qtaue = 0.0D0
- rtaue = -0.25D0
-
- case (46) ! NSTX, ELMy H-mode scaling
- ! NSTX scaling with IPB98(y,2) for other variables
- ! Menard 2019, Phil. Trans. R. Soc. A 377:20170440
- ! Kaye et al. 2006, Nucl. Fusion 46 848
- tauee = hfact * 0.095D0 * pcur**0.57D0 * bt**1.08D0 * &
- dnla19**0.44D0 * powerht**(-0.73D0) * rmajor**1.97D0 * &
- kappaa_IPB**0.78D0 * aspect**(-0.58D0) * afuel**0.19D0
- gtaue = 0.0D0
- ptaue = 0.44D0
- qtaue = 0.0D0
- rtaue = -0.73D0
-
- case (47) ! NSTX-Petty08 Hybrid
- ! Linear interpolation between NSTX and Petty08 in eps
- ! Menard 2019, Phil. Trans. R. Soc. A 377:20170440
- if ((1.0D0/aspect).le.0.4D0) then
- ! Petty08, i.e. case (41)
- tauee = hfact * 0.052D0 * pcur**0.75D0 * bt**0.3D0 * &
- dnla19**0.32D0 * powerht**(-0.47D0) * rmajor**2.09D0 * &
- kappaa**0.88D0 * aspect**(-0.84D0)
-
- gtaue = 0.0D0
- ptaue = 0.32D0
- qtaue = 0.0D0
- rtaue = -0.47D0
-
- else if ((1.0D0/aspect).ge.0.6D0) then
- ! NSTX, i.e.case (46)
- tauee = hfact * 0.095D0 * pcur**0.57D0 * bt**1.08D0 * &
- dnla19**0.44D0 * powerht**(-0.73D0) * rmajor**1.97D0 * &
- kappaa_IPB**0.78D0 * aspect**(-0.58D0) * afuel**0.19D0
-
- gtaue = 0.0D0
- ptaue = 0.44D0
- qtaue = 0.0D0
- rtaue = -0.73D0
-
- else
- taupetty = 0.052D0 * pcur**0.75D0 * bt**0.3D0 * &
- dnla19**0.32D0 * powerht**(-0.47D0) * rmajor**2.09D0 * &
- kappaa**0.88D0 * aspect**(-0.84D0)
- taunstx= 0.095D0 * pcur**0.57D0 * bt**1.08D0 * &
- dnla19**0.44D0 * powerht**(-0.73D0) * rmajor**1.97D0 * &
- kappaa_IPB**0.78D0 * aspect**(-0.58D0) * afuel**0.19D0
-
- tauee = hfact*((((1.0D0/aspect)-0.4D0)/(0.6D0-0.4D0))*taunstx + &
- ((0.6D0-(1.0D0/aspect))/(0.6D0-0.4D0))*taupetty)
-
- gtaue = 0.0D0
- ptaue = ((((1.0D0/aspect)-0.4D0)/(0.6D0-0.4D0))*0.32D0 + &
- ((0.6D0-(1.0D0/aspect))/(0.6D0-0.4D0))*0.44D0)
- qtaue = 0.0D0
- rtaue = ((((1.0D0/aspect)-0.4D0)/(0.6D0-0.4D0))*(-0.47D0) + &
- ((0.6D0-(1.0D0/aspect))/(0.6D0-0.4D0))*(-0.73D0))
- end if
-
- case (48) ! NSTX gyro-Bohm (Buxton)
- ! P F Buxton et al. 2019 Plasma Phys. Control. Fusion 61 035006
- tauee = hfact * 0.21D0 * pcur**0.54D0 * bt**0.91D0 * &
- powerht**(-0.38D0) * rmajor**2.14D0 * dnla20**(-0.05D0)
-
- gtaue = 0.0D0
- ptaue = -0.05D0
- qtaue = 0.0D0
- rtaue = -0.38D0
-
- case (49) ! tauee is an input
- tauee = hfact * tauee_in
-
- gtaue = 0.0D0
- ptaue = 0.0D0
- qtaue = 0.0D0
- rtaue = 0.0D0
-
- case default
- idiags(1) = isc ; call report_error(81)
-
- end select
-
- ! Ion energy confinement time
- ! N.B. Overwrites earlier calculation above
-
- tauei = tauee
-
- ! Calculation of the transport power loss terms
- ! Transport losses in Watts/m3 are 3/2 * n.e.T / tau , with T in eV
- ! (here, tin and ten are in keV, and ptrepv and ptripv are in MW/m3)
-
- ptripv = 2.403D-22 * dnitot*tin/tauei
- ptrepv = 2.403D-22 * dene*ten/tauee
-
- ratio = dnitot/dene * tin/ten
-
- ! Global energy confinement time
-
- taueff = ((ratio + 1.0D0)/(ratio/tauei + 1.0D0/tauee))
-
- ! This is used only in subroutine startup, which is currently (r400)
- ! not used.
- ftaue = (tauee-gtaue) / &
- (n20**ptaue * (te/10.0D0)**qtaue * powerht**rtaue)
-
- end subroutine pcond
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- subroutine vscalc(csawth,eps,facoh,gamma,kappa,rmajor,rplas, &
- plascur,theat,tburn,phiint,rli,rlp,vsbrn,vsind,vsres,vsstt)
-
- !! Volt-second requirements
- !! author: P J Knight, CCFE, Culham Science Centre
- !! csawth : input real : coefficient for sawteeth effects
- !! eps : input real : inverse aspect ratio
- !! facoh : input real : fraction of plasma current produced inductively
- !! gamma : input real : Ejima coeff for resistive start-up V-s component
- !! kappa : input real : plasma elongation
- !! plascur: input real : plasma current (A)
- !! rli : input real : plasma normalised inductivity
- !! rmajor : input real : plasma major radius (m)
- !! rplas : input real : plasma resistance (ohm)
- !! theat : input real : heating time (s)
- !! tburn : input real : burn time (s)
- !! phiint : output real : internal plasma volt-seconds (Wb)
- !! rlp : output real : plasma inductance (H)
- !! vsbrn : output real : volt-seconds needed during flat-top (heat+burn) (Wb)
- !! vsind : output real : internal and external plasma inductance V-s (Wb)
- !! vsres : output real : resistive losses in start-up volt-seconds (Wb)
- !! vsstt : output real : total volt-seconds needed (Wb)
- !! This subroutine calculates the volt-second requirements and some
- !! other related items.
- !! AEA FUS 251: A User's Guide to the PROCESS Systems Code
- !
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- use constants, only: rmu0
- implicit none
-
- ! Arguments
-
- real(dp), intent(in) :: csawth, eps, facoh, gamma, kappa, &
- plascur, rli, rmajor, rplas, tburn, theat
- real(dp), intent(out) :: phiint, rlp, vsbrn, vsind, vsres, vsstt
-
- ! Local variables
-
- real(dp) :: aeps,beps,rlpext,rlpint,vburn
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- ! Internal inductance
-
- rlpint = rmu0 * rmajor * rli/2.0D0
- phiint = rlpint*plascur
-
- ! Start-up resistive component
- ! Uses ITER formula without the 10 V-s add-on
-
- vsres = gamma * rmu0*plascur*rmajor
-
- ! Hirshman, Neilson: Physics of Fluids, 29 (1986) p790
- ! fit for external inductance
-
- aeps = (1.0D0 + 1.81D0*sqrt(eps)+2.05D0*eps)*log(8.0D0/eps) &
- - (2.0D0 + 9.25D0*sqrt(eps)-1.21D0*eps)
- beps = 0.73D0 * sqrt(eps) *(1.0D0 + 2.0D0*eps**4-6.0D0*eps**5 &
- + 3.7D0*eps**6)
- rlpext = rmajor*rmu0 * aeps*(1.0D0-eps)/(1.0D0-eps+beps*kappa)
-
- rlp = rlpext + rlpint
-
- ! Inductive V-s component
-
- vsind = rlp * plascur
- vsstt = vsres + vsind
-
- ! Loop voltage during flat-top
- ! Include enhancement factor in flattop V-s requirement
- ! to account for MHD sawtooth effects.
-
- vburn = plascur * rplas * facoh * csawth
-
- ! N.B. tburn on first iteration will not be correct
- ! if the pulsed reactor option is used, but the value
- ! will be correct on subsequent calls.
-
- vsbrn = vburn*(theat + tburn)
- vsstt = vsstt + vsbrn
-
- end subroutine vscalc
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- subroutine phyaux(aspect,dene,deni,fusionrate,alpharate,plascur,sbar,dnalp, &
- taueff,vol,burnup,dntau,figmer,fusrat,qfuel,rndfuel,taup)
-
- !! Auxiliary physics quantities
- !! author: P J Knight, CCFE, Culham Science Centre
- !! aspect : input real : plasma aspect ratio
- !! dene : input real : electron density (/m3)
- !! deni : input real : fuel ion density (/m3)
- !! dnalp : input real : alpha ash density (/m3)
- !! fusionrate : input real : fusion reaction rate (/m3/s)
- !! alpharate : input real : alpha particle production rate (/m3/s)
- !! plascur: input real : plasma current (A)
- !! sbar : input real : exponent for aspect ratio (normally 1)
- !! taueff : input real : global energy confinement time (s)
- !! vol : input real : plasma volume (m3)
- !! burnup : output real : fractional plasma burnup
- !! dntau : output real : plasma average n-tau (s/m3)
- !! figmer : output real : physics figure of merit
- !! fusrat : output real : number of fusion reactions per second
- !! qfuel : output real : fuelling rate for D-T (nucleus-pairs/sec)
- !! rndfuel: output real : fuel burnup rate (reactions/s)
- !! taup : output real : (alpha) particle confinement time (s)
- !! This subroutine calculates extra physics related items
- !! needed by other parts of the code
- !! AEA FUS 251: A User's Guide to the PROCESS Systems Code
- !
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- use physics_variables, only: tauratio,burnup_in
- implicit none
-
- ! Arguments
-
- real(dp), intent(in) :: aspect, dene, deni, dnalp, &
- fusionrate, alpharate, plascur, sbar, taueff, vol
- real(dp), intent(out) :: burnup, dntau, figmer, fusrat, &
- qfuel, rndfuel, taup
-
- ! Local variables
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- figmer = 1.0D-6 * plascur * aspect**sbar
-
- dntau = taueff*dene
-
- ! Fusion reactions per second
-
- fusrat = fusionrate*vol
-
- ! Alpha particle confinement time (s)
- ! Number of alphas / alpha production rate
-
- if (alpharate /= 0.0D0) then
- taup = dnalp / alpharate
- else ! only likely if DD is only active fusion reaction
- taup = 0.0D0
- end if
-
- ! Fractional burnup
-
- ! (Consider detailed model in: G. L. Jackson, V. S. Chan, R. D. Stambaugh,
- ! Fusion Science and Technology, vol.64, no.1, July 2013, pp.8-12)
-
- ! The ratio of ash to fuel particle confinement times is given by
- ! tauratio
- ! Possible logic...
- ! burnup = fuel ion-pairs burned/m3 / initial fuel ion-pairs/m3;
- ! fuel ion-pairs burned/m3 = alpha particles/m3 (for both D-T and D-He3 reactions)
- ! initial fuel ion-pairs/m3 = burnt fuel ion-pairs/m3 + unburnt fuel-ion pairs/m3
- ! Remember that unburnt fuel-ion pairs/m3 = 0.5 * unburnt fuel-ions/m3
- if (burnup_in <= 1.0D-9) then
- burnup = dnalp / (dnalp + 0.5D0*deni) / tauratio
- else
- burnup = burnup_in
- end if
- ! Fuel burnup rate (reactions/second) (previously Amps)
-
- rndfuel = fusrat
-
- ! Required fuelling rate (fuel ion pairs/second) (previously Amps)
-
- qfuel = rndfuel/burnup
-
- end subroutine phyaux
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- subroutine rether(alphan,alphat,dene,dlamie,te,ti,zeffai,piepv)
-
- !! Routine to find the equilibration power between the
- !! ions and electrons
- !! author: P J Knight, CCFE, Culham Science Centre
- !! alphan : input real : density profile index
- !! alphat : input real : temperature profile index
- !! dene : input real : electron density (/m3)
- !! dlamie : input real : ion-electron coulomb logarithm
- !! te : input real : electron temperature (keV)
- !! ti : input real : ion temperature (keV)
- !! zeffai : input real : mass weighted plasma effective charge
- !! piepv : output real : ion/electron equilibration power (MW/m3)
- !! This routine calculates the equilibration power between the
- !! ions and electrons.
- !! Unknown origin
- !
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- implicit none
-
- ! Arguments
-
- real(dp), intent(in) :: alphan, alphat, dene, dlamie, &
- te, ti, zeffai
- real(dp), intent(out) :: piepv
-
- ! Local variables
-
- real(dp) :: conie, profie
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- profie = (1.0D0+alphan)**2 / &
- ( (2.0D0*alphan - 0.5D0*alphat + 1.0D0) * sqrt(1.0D0+alphat) )
-
- conie = 2.42165D-41 * dlamie * dene**2 * zeffai * profie
-
- piepv = conie*(ti-te)/(te**1.5D0)
-
- end subroutine rether
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- subroutine pohm(facoh,kappa95,plascur,rmajor,rminor,ten,vol, &
- zeff,pohmpv,pohmmw,rpfac,rplas)
-
- !! Ohmic power calculation
- !! author: P J Knight, CCFE, Culham Science Centre
- !! facoh : input real : fraction of plasma current produced inductively
- !! kappa95: input real : plasma elongation at 95% flux
- !! plascur: input real : plasma current (A)
- !! rmajor : input real : plasma major radius (m)
- !! rminor : input real : plasma minor radius (m)
- !! ten : input real : density weighted average electron temperature (keV)
- !! vol : input real : plasma volume (m3)
- !! zeff : input real : plasma effective charge
- !! pohmpv : output real : ohmic heating power per unit volume (MW/m3)
- !! pohmmw : output real : ohmic heating power (MW)
- !! rpfac : output real : neoclassical resistivity enhancement factor
- !! rplas : output real : plasma resistance (ohm)
- !! This routine finds the ohmic heating power per unit volume.
- !! The expression is a good fit for alphan = 0.5, alphat = 1.0,
- !! alphaj = 1.5, aspect = 2.5 -- 4.
- !! AEA FUS 251: A User's Guide to the PROCESS Systems Code
- !! ITER Physics Design Guidelines: 1989 [IPDG89], N. A. Uckan et al,
- !! ITER Documentation Series No.10, IAEA/ITER/DS/10, IAEA, Vienna, 1990
- !
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- use error_handling, only: fdiags, report_error
- use physics_variables, only: aspect, plasma_res_factor
- implicit none
-
- ! Arguments
-
- real(dp), intent(in) :: facoh, kappa95, plascur, rmajor, &
- rminor, ten, vol, zeff
- real(dp), intent(out) :: pohmpv, pohmmw, rpfac, rplas
-
- ! Local variables
-
- real(dp) :: t10
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- ! Density weighted electron temperature in 10 keV units
-
- t10 = ten/10.0D0
-
- ! Plasma resistance, from loop voltage calculation in IPDG89
-
- rplas = plasma_res_factor * 2.15D-9 * zeff*rmajor / (kappa95*rminor**2 * t10**1.5D0)
-
- ! Neo-classical resistivity enhancement factor
- ! Taken from N. A. Uckan et al, Fusion Technology 13 (1988) p.411.
- ! The expression is valid for aspect ratios in the range 2.5--4.
-
- rpfac = 4.3D0 - 0.6D0*rmajor/rminor
- rplas = rplas * rpfac
-
- ! Check to see if plasma resistance is negative
- ! (possible if aspect ratio is too high)
-
- if (rplas <= 0.0D0) then
- fdiags(1) = rplas ; fdiags(2) = aspect
- call report_error(83)
- end if
-
- ! Ohmic heating power per unit volume
- ! Corrected from: pohmpv = (facoh*plascur)**2 * ...
-
- pohmpv = facoh * plascur**2 * rplas * 1.0D-6/vol
-
- ! Total ohmic heating power
-
- pohmmw = pohmpv*vol
-
- end subroutine pohm
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- subroutine igmarcal(outfile)
-
- !! Routine to calculate ignition margin
- !! author: P J Knight, CCFE, Culham Science Centre
- !! outfile : input integer : Fortran output unit identifier
- !! This routine calculates the ignition margin at the final point
- !! with different scalings.
- !! AEA FUS 251: A User's Guide to the PROCESS Systems Code
- !
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- use current_drive_variables, only: pinjmw
- use physics_variables, only: vol, palpmw, zeff, pchargemw, hfac, xarea, &
- tin, tauscl, eps, kappaa, dnla, kappa95, ten, te, kappa, dnitot, dene, &
- iinvqd, rminor, bt, rmajor, ignite, aspect, qstar, q, afuel, plascur, &
- pcoreradpv
- use process_output, only: oheadr, oblnkl
- implicit none
-
- ! Arguments
-
- integer, intent(in) :: outfile
-
- ! Local variables
-
- integer :: iisc
- real(dp), parameter :: d1 = 1.0D0
- real(dp) :: powerhtz, ptrez, ptriz, &
- taueez, taueffz, taueiz
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- call oheadr(outfile,'Energy confinement times, and required H-factors :')
-
- write(outfile,10)
-10 format(t5,'scaling law', t30,'confinement time (s)', &
- t55,'H-factor for')
-
- write(outfile,20)
-20 format(t34,'for H = 1',t54,'power balance')
-
- call oblnkl(outfile)
-
- ! Calculate power balances for all scaling laws assuming H = 1
-
- do iisc = 32,47
- call pcond(afuel,palpmw,aspect,bt,dnitot,dene,dnla,eps,d1, &
- iinvqd,iisc,ignite,kappa,kappa95,kappaa,pchargemw,pinjmw, &
- plascur,pcoreradpv,rmajor,rminor,te,ten,tin,q,qstar,vol, &
- xarea,zeff,ptrez,ptriz,taueez,taueiz,taueffz,powerhtz)
- hfac(iisc) = fhfac(iisc)
-
- write(outfile,30) tauscl(iisc),taueez,hfac(iisc)
- end do
-30 format(t2,a24,t34,f7.3,t58,f7.3)
-
- end subroutine igmarcal
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- function fhfac(is)
-
- !! Function to find H-factor for power balance
- !! author: P J Knight, CCFE, Culham Science Centre
- !! is : input integer : confinement time scaling law of interest
- !! This function calculates the H-factor required for power balance,
- !! using the given energy confinement scaling law.
- !! AEA FUS 251: A User's Guide to the PROCESS Systems Code
- !
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- use maths_library, only: zeroin
- implicit none
-
- real(dp) :: fhfac
-
- ! Arguments
-
- integer, intent(in) :: is
-
- ! Local variables
-
- real(dp), parameter :: abserr = 0.003D0 ! numerical tolerance
- real(dp), parameter :: xlow = 0.01D0 ! minimum bound on H-factor
- real(dp), parameter :: xhigh = 100.0D0 ! maximum bound on H-factor
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- iscz = is
-
- ! Find value of H-factor for which function FHZ is zero
- ! (this occurs at power balance)
-
- fhfac = zeroin(xlow,xhigh,fhz,abserr)
-
- end function fhfac
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- function fhz(hhh)
-
- !! Function used to find power balance
- !! author: P J Knight, CCFE, Culham Science Centre
- !! hhh : input real : test value for confinement time H-factor
- !! This function is used to find power balance.
- !! FHZ is zero at power balance, which is achieved
- !! using routine ZEROIN to adjust the
- !! value of hhh, the confinement time H-factor.
- !! AEA FUS 251: A User's Guide to the PROCESS Systems Code
- !
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- use current_drive_variables, only: pinjmw
- use physics_variables, only: iradloss, vol, palpmw, pradpv, pchargemw, &
- zeff, pohmpv, pchargepv, xarea, tin, eps, kappaa, dnla, palppv, kappa95, &
- ten, te, kappa, falpha, dnitot, dene, iinvqd, rminor, bt, rmajor, &
- ignite, aspect, qstar, q, afuel, plascur, pcoreradpv
- implicit none
-
- real(dp) :: fhz
-
- ! Arguments
-
- real(dp), intent(in) :: hhh
-
- ! Local variables
-
- real(dp) :: powerhtz,ptrez,ptriz,taueezz,taueiz,taueffz
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- call pcond(afuel,palpmw,aspect,bt,dnitot,dene,dnla,eps,hhh, &
- iinvqd,iscz,ignite,kappa,kappa95,kappaa,pchargemw,pinjmw, &
- plascur,pcoreradpv,rmajor,rminor,te,ten,tin,q,qstar,vol, &
- xarea,zeff,ptrez,ptriz,taueezz,taueiz,taueffz,powerhtz)
-
- ! MDK All the scaling laws now contain hfact, so this code no longer required.
- !if (iscz < 3) then ! only laws 1 and 2 are affected???
- ! ptrez = ptrez/hhh
- ! ptriz = ptriz/hhh
- !end if
-
- ! At power balance, fhz is zero.
-
- fhz = ptrez + ptriz - falpha*palppv - pchargepv - pohmpv
-
- ! Take into account whether injected power is included in tau_e
- ! calculation (i.e. whether device is ignited)
-
- if (ignite == 0) fhz = fhz - pinjmw/vol
-
- ! Include the radiation power if requested
-
- if (iradloss == 0) then
- fhz = fhz + pradpv
- else if (iradloss == 1) then
- fhz = fhz + pcoreradpv
- else
- continue
- end if
-
- end function fhz
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- subroutine outplas(outfile)
-
- !! Subroutine to output the plasma physics information
- !! author: P J Knight, CCFE, Culham Science Centre
- !! outfile : input integer : Fortran output unit identifier
- !! This routine writes the plasma physics information
- !! to a file, in a tidy format.
- !! AEA FUS 251: A User's Guide to the PROCESS Systems Code
- !
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- use constraint_variables, only: maxradwallload, peakradwallload, fbetatry, &
- taulimit, peakfactrad
- use current_drive_variables, only: bscf_nevins, bscfmax, cboot, &
- bscf_wilson, bscf_sauter, pinjmw, bscf_iter89, bootipf, pinjimw, pinjemw, &
- psipf, pscf_scene, diacf_hender, diacf_scene, diaipf
- use error_handling, only: fdiags, idiags, report_error
- use impurity_radiation_module, only: nimp, coreradiationfraction, &
- coreradius, fimp, impurity_arr_frac, impurity_arr_Label
- use physics_variables, only: ieped, ftar, dnelimt, fgwped, kappaa, deni, &
- betap, iculbl, rad_fraction_total, palpnb, ten, falpi, iradloss, pthrmw, &
- ralpne, taueff, dntau, dene, rad_fraction_sol, iprofile, rhopedn, &
- xarea, itart, epbetmax, neped, te0, ptrimw, dnbeta, powerht, psyncpv, &
- res_time, ignite, vol, bvert, tbeta, photon_wall, burnup, kappaa_ipb, &
- hfact, ilhthresh, alphan, fkzohm, alpha_crit, pohmmw, pouterzoneradmw, qlim, &
- qfuel, triang95, rplas, zeff, pdhe3, plascur, pdt, pdd, pbrempv, &
- ipedestal, dlamie, vsres, falpe, rli, ptremw, alphat, rminor, isc, &
- teped, fdeut, gamma, dnprot, ftrit, aion, btot, vsbrn, betanb, protium, &
- pchargemw, wallmw, vsstt, aspect, ti, q0, pinnerzoneradmw, &
- normalised_total_beta, pdivmax, dnbeam, kappa95, nesep_crit, fhe3, &
- triang, pneutmw, tauee, betalim, rlp, te, dlimit, ne0, qstar, dnalp, &
- taup, sarea, ti0, plhthresh, bp, dnitot, pradmw, pradsolmw, csawth, rndfuel, q95, &
- rhopedt, tauratio, pperim, tesep, vsind, ibss, alphaj, dnz, q, ssync, &
- psolradmw, tauei, ishape, plinepv, palpmw, palpfwmw, icurr, pdivt, &
- gammaft, powfmw
- use physics_variables, only: betaft, tauscl, fgwsep, rmajor, falpha, &
- nesep, facoh, kappa, dlimit, beta, dlimit, eps, pthrmw, dnla, bt, &
- pthrmw, pthrmw, pthrmw, idivrt, ips, idia
- use process_output, only: int_to_string2, ovarre, ovarrf, oheadr, &
- oblnkl, ovarin, ocmmnt, osubhd, ovarst
- use numerics, only: active_constraints, boundu, icc, &
- boundl, ioptimz
- use reinke_variables, only: fzactual, impvardiv, fzmin
- use constants, only: rmu0, mproton, mfile, echarge, pi, epsilon0
- use stellarator_variables, only: iotabar, istell
- implicit none
-
- ! Arguments
-
- integer, intent(in) :: outfile
-
- ! Local variables
-
- real(dp) :: betath, tot_power_plasma, normalised_toroidal_beta
- ! pinj
- integer :: imp
- character(len=30) :: tauelaw
- character(len=30) :: str1,str2
- real(dp) :: fgwped_out ! neped/dlimit(7)
- real(dp) :: fgwsep_out ! nesep/dlimit(7)
-
- ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- ! Dimensionless plasma parameters. See reference below.
- nu_star = 1/rmu0 * (15.d0*echarge**4 * dlamie) / (4.d0*pi**1.5d0 * epsilon0**2) * &
- vol**2 * rmajor**2 * bt * sqrt(eps) * dnla**3 * kappa / &
- (total_plasma_internal_energy**2 * plascur)
-
- rho_star = sqrt(2.d0* mproton * aion * total_plasma_internal_energy / (3.d0 * vol * dnla) ) / &
- (echarge * bt * eps * rmajor)
-
- beta_mcdonald = 4.d0/3.d0 *rmu0 * total_plasma_internal_energy / (vol * bt**2)
-
- call oheadr(outfile,'Plasma')
-
- if (istell == 0) then
- select case (idivrt)
- case (0)
- call ocmmnt(outfile,'Plasma configuration = limiter')
- case (1)
- call ocmmnt(outfile,'Plasma configuration = single null divertor')
- case (2)
- call ocmmnt(outfile,'Plasma configuration = double null divertor')
- case default
- idiags(1) = idivrt ; call report_error(85)
- end select
- else
- call ocmmnt(outfile,'Plasma configuration = stellarator')
- end if
-
- if (istell == 0) then
- if (itart == 0) then
- itart_r = itart
- call ovarrf(outfile,'Tokamak aspect ratio = Conventional, itart = 0','(itart)',itart_r)
- else if (itart == 1) then
- itart_r = itart
- call ovarrf(outfile,'Tokamak aspect ratio = Spherical, itart = 1','(itart)',itart_r)
- end if
- end if
-
- call osubhd(outfile,'Plasma Geometry :')
- call ovarrf(outfile,'Major radius (m)','(rmajor)',rmajor)
- call ovarrf(outfile,'Minor radius (m)','(rminor)',rminor, 'OP ')
- call ovarrf(outfile,'Aspect ratio','(aspect)',aspect)
-
- if (istell == 0) then
-
- select case (ishape)
- case (0,6,8)
- call ovarrf(outfile,'Elongation, X-point (input value used)', '(kappa)',kappa, 'IP ')
- case (1)
- call ovarrf(outfile,'Elongation, X-point (TART scaling)', '(kappa)',kappa, 'OP ')
- case (2,3)
- call ovarrf(outfile,'Elongation, X-point (Zohm scaling)', '(kappa)',kappa, 'OP ')
- call ovarrf(outfile,'Zohm scaling adjustment factor', '(fkzohm)',fkzohm)
- case (4,5,7)
- call ovarrf(outfile,'Elongation, X-point (calculated from kappa95)', '(kappa)',kappa, 'OP ')
- case (9)
- call ovarrf(outfile,'Elongation, X-point (calculated from aspect ratio and li(3))', &
- '(kappa)',kappa, 'OP ')
- case (10)
- call ovarrf(outfile,'Elongation, X-point (calculated from aspect ratio and stability margin)', &
- '(kappa)',kappa, 'OP ')
- case (11)
- call ovarrf(outfile,'Elongation, X-point (calculated from aspect ratio via Menard 2016)', &
- '(kappa)',kappa, 'OP ')
- case default
- idiags(1) = ishape ; call report_error(86)
- end select
-
- select case (ishape)
- case (4,5,7)
- call ovarrf(outfile,'Elongation, 95% surface (input value used)', &
- '(kappa95)',kappa95, 'IP ')
- case default
- call ovarrf(outfile,'Elongation, 95% surface (calculated from kappa)', &
- '(kappa95)',kappa95, 'OP ')
- end select
-
- call ovarrf(outfile,'Elongation, area ratio calc.','(kappaa)',kappaa, 'OP ')
-
- select case (ishape)
- case (0,2,6,8,9,10,11)
- call ovarrf(outfile,'Triangularity, X-point (input value used)', &
- '(triang)',triang, 'IP ')
- case (1)
- call ovarrf(outfile,'Triangularity, X-point (TART scaling)', &
- '(triang)',triang, 'OP ')
- case (3,4,5,7)
- call ovarrf(outfile,'Triangularity, X-point (calculated from triang95)', &
- '(triang)',triang, 'OP ')
- end select
-
- select case (ishape)
- case (3,4,5,7)
- call ovarrf(outfile,'Triangularity, 95% surface (input value used)', &
- '(triang95)',triang95, 'IP ')
- case default
- call ovarrf(outfile,'Triangularity, 95% surface (calculated from triang)', &
- '(triang95)',triang95, 'OP ')
- end select
-
- call ovarrf(outfile,'Plasma poloidal perimeter (m)','(pperim)',pperim, 'OP ')
- end if
-
- call ovarrf(outfile,'Plasma cross-sectional area (m2)','(xarea)',xarea, 'OP ')
- call ovarre(outfile,'Plasma surface area (m2)','(sarea)',sarea, 'OP ')
- call ovarre(outfile,'Plasma volume (m3)','(vol)',vol, 'OP ')
-
- call osubhd(outfile,'Current and Field :')
-
-
- if (istell == 0) then
- if (iprofile == 0) then
- call ocmmnt(outfile, &
- 'Consistency between q0,q,alphaj,rli,dnbeta is not enforced')
- else
- call ocmmnt(outfile, &
- 'Consistency between q0,q,alphaj,rli,dnbeta is enforced')
- end if
- call oblnkl(outfile)
- call ovarin(outfile,'Plasma current scaling law used','(icurr)',icurr)
-
-
- call ovarrf(outfile,'Plasma current (MA)','(plascur/1D6)',plascur/1.0D6, 'OP ')
- !call ovarrf(outfile,'Plasma current (A)','(plascur)',plascur, 'OP ')
- if (iprofile == 1) then
- call ovarrf(outfile,'Current density profile factor','(alphaj)',alphaj, 'OP ')
- else
- call ovarrf(outfile,'Current density profile factor','(alphaj)',alphaj)
- end if
-
- call ovarrf(outfile,'Plasma internal inductance, li','(rli)',rli, 'OP ')
- call ovarrf(outfile,'Vertical field at plasma (T)','(bvert)',bvert, 'OP ')
- end if
-
- call ovarrf(outfile,'Vacuum toroidal field at R (T)','(bt)',bt)
- call ovarrf(outfile,'Average poloidal field (T)','(bp)',bp, 'OP ')
-
- call ovarrf(outfile,'Total field (sqrt(bp^2 + bt^2)) (T)','(btot)',btot, 'OP ')
-
-
- if (istell == 0) then
- call ovarrf(outfile,'Safety factor on axis','(q0)',q0)
-
- if (icurr == 2) then
- call ovarrf(outfile,'Mean edge safety factor','(q)',q)
- end if
-
- call ovarrf(outfile,'Safety factor at 95% flux surface','(q95)',q95)
-
- call ovarrf(outfile,'Cylindrical safety factor (qcyl)','(qstar)',qstar, 'OP ')
-
- if (ishape == 1) then
- call ovarrf(outfile,'Lower limit for edge safety factor q', '(qlim)',qlim, 'OP ')
- end if
- else
- call ovarrf(outfile,'Rotational transform','(iotabar)',iotabar)
- end if
-
- call osubhd(outfile,'Beta Information :')
-
- betath = beta-betaft-betanb
- gammaft = (betaft + betanb)/betath
-
- call ovarre(outfile,'Total plasma beta','(beta)',beta)
- call ovarre(outfile,'Total poloidal beta','(betap)',betap, 'OP ')
- call ovarre(outfile,'Total toroidal beta',' ',beta*(btot/bt)**2, 'OP ')
- call ovarre(outfile,'Fast alpha beta','(betaft)',betaft, 'OP ')
- call ovarre(outfile,'Beam ion beta','(betanb)',betanb, 'OP ')
- call ovarre(outfile,'(Fast alpha + beam beta)/(thermal beta)','(gammaft)',gammaft, 'OP ')
-
- call ovarre(outfile,'Thermal beta',' ',betath, 'OP ')
- call ovarre(outfile,'Thermal poloidal beta',' ',betath*(btot/bp)**2, 'OP ')
- call ovarre(outfile,'Thermal toroidal beta (= beta-exp)',' ', betath*(btot/bt)**2, 'OP ')
-
- call ovarrf(outfile,'2nd stability beta : beta_p / (R/a)', '(eps*betap)',eps*betap, 'OP ')
- call ovarrf(outfile,'2nd stability beta upper limit','(epbetmax)', epbetmax)
-
-
- if (istell == 0) then
- if (iprofile == 1) then
- call ovarrf(outfile,'Beta g coefficient','(dnbeta)',dnbeta, 'OP ')
- else
- call ovarrf(outfile,'Beta g coefficient','(dnbeta)',dnbeta)
- end if
-
- call ovarrf(outfile,'Normalised thermal beta',' ',1.0D8*betath*rminor*bt/plascur, 'OP ')
- !call ovarrf(outfile,'Normalised total beta',' ',1.0D8*beta*rminor*bt/plascur, 'OP ')
- call ovarrf(outfile,'Normalised total beta',' ',normalised_total_beta, 'OP ')
- !call ovarrf(outfile,'Normalised toroidal beta',' ',normalised_total_beta*(btot/bt)**2, 'OP ')
- normalised_toroidal_beta=normalised_total_beta*(btot/bt)**2
- call ovarrf(outfile,'Normalised toroidal beta','(normalised_toroidal_beta)',normalised_toroidal_beta, 'OP ')
- end if
-
-
- if (iculbl == 0) then
- call ovarrf(outfile,'Limit on total beta','(betalim)',betalim, 'OP ')
- else if (iculbl == 1) then
- call ovarrf(outfile,'Limit on thermal beta','(betalim)',betalim, 'OP ')
- else
- call ovarrf(outfile,'Limit on thermal + NB beta','(betalim)', betalim, 'OP ')
- end if
-
- call ovarre(outfile,'Plasma thermal energy (J)',' ', 1.5D0*betath*btot*btot/(2.0D0*rmu0)*vol, 'OP ')
-
- call ovarre(outfile,'Total plasma internal energy (J)','(total_plasma_internal_energy)', total_plasma_internal_energy, 'OP ')
-
- call osubhd(outfile,'Temperature and Density (volume averaged) :')
- call ovarrf(outfile,'Electron temperature (keV)','(te)',te)
- call ovarrf(outfile,'Electron temperature on axis (keV)','(te0)',te0, 'OP ')
- call ovarrf(outfile,'Ion temperature (keV)','(ti)',ti)
- call ovarrf(outfile,'Ion temperature on axis (keV)','(ti0)',ti0, 'OP ')
- call ovarrf(outfile,'Electron temp., density weighted (keV)','(ten)',ten, 'OP ')
- call ovarre(outfile,'Electron density (/m3)','(dene)',dene)
- call ovarre(outfile,'Electron density on axis (/m3)','(ne0)',ne0, 'OP ')
- call ovarre(outfile,'Line-averaged electron density (/m3)','(dnla)',dnla, 'OP ')
-
- if (istell == 0) then
- call ovarre(outfile,'Line-averaged electron density / Greenwald density', &
- '(dnla_gw)',dnla/dlimit(7), 'OP ')
- end if
-
-
- call ovarre(outfile,'Ion density (/m3)','(dnitot)',dnitot, 'OP ')
- call ovarre(outfile,'Fuel density (/m3)','(deni)',deni, 'OP ')
- call ovarre(outfile,'Total impurity density with Z > 2 (no He) (/m3)','(dnz)',dnz, 'OP ')
- call ovarre(outfile,'Helium ion density (thermalised ions only) (/m3)','(dnalp)',dnalp, 'OP ')
- call ovarre(outfile,'Proton density (/m3)','(dnprot)',dnprot, 'OP ')
- if(protium > 1.0d-10)then
- call ovarre(outfile,'Seeded protium density / electron density','(protium)',protium)
- end if
-
- call ovarre(outfile,'Hot beam density (/m3)','(dnbeam)',dnbeam, 'OP ')
- call ovarre(outfile,'Density limit from scaling (/m3)','(dnelimt)',dnelimt, 'OP ')
- if ((ioptimz > 0).and.(active_constraints(5))) then
- call ovarre(outfile,'Density limit (enforced) (/m3)','(boundu(9)*dnelimt)',boundu(9)*dnelimt, 'OP ')
- end if
- call ovarre(outfile,'Helium ion density (thermalised ions only) / electron density','(ralpne)',ralpne)
- call oblnkl(outfile)
-
-
- call ocmmnt(outfile,'Impurities')
- call oblnkl(outfile)
- call ocmmnt(outfile,'Plasma ion densities / electron density:')
- do imp = 1,nimp
- ! MDK Update fimp, as this will make the ITV output work correctly.
- fimp(imp) = impurity_arr_frac(imp)
- str1 = impurity_arr_Label(imp) // ' concentration'
- str2 = '(fimp('//int_to_string2(imp)//'))'
- ! MDK Add output flag for H which is calculated.
- if (imp==1) then
- !call ovarre(outfile,str1,str2,impurity_arr_frac(imp), 'OP ')
- call ovarre(outfile,str1,str2,fimp(imp), 'OP ')
- else
- call ovarre(outfile,str1,str2,fimp(imp))
- end if
- end do
-
- call ovarre(outfile,'Average mass of all ions (amu)','(aion)',aion, 'OP ')
- call oblnkl(outfile)
- call ovarrf(outfile,'Effective charge','(zeff)',zeff, 'OP ')
-
- ! Issue #487. No idea what zeffai is.
- ! I haven't removed it as it is used in subroutine rether,
- ! (routine to find the equilibration power between the ions and electrons)
- ! call ovarrf(outfile,'Mass weighted effective charge','(zeffai)',zeffai, 'OP ')
-
- call ovarrf(outfile,'Density profile factor','(alphan)',alphan)
- call ovarin(outfile,'Plasma profile model','(ipedestal)',ipedestal)
-
- if(ipedestal.ge.1)then
- if (ne0