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= 0d0)then - call ovarre(outfile,'Electron density pedestal height (/m3)','(neped)',neped, 'OP ') - else - call ovarre(outfile,'Electron density pedestal height (/m3)','(neped)',neped) - end if - - ! This code is ODD! Don't change it! No explanation why fgwped and fgwsep - ! must be assigned to their exisiting values! - fgwped_out = neped/dlimit(7) - fgwsep_out = nesep/dlimit(7) - if(fgwped >= 0d0) fgwped = neped/dlimit(7) - if(fgwsep >= 0d0) fgwsep = nesep/dlimit(7) - - call ovarre(outfile,'Electron density at pedestal / nGW','(fgwped_out)',fgwped_out) - call ovarrf(outfile,'Temperature pedestal r/a location','(rhopedt)',rhopedt) - ! Issue #413 Pedestal scaling - call ovarin(outfile,'Pedestal scaling switch','(ieped)',ieped) - if(ieped==1)then - call ocmmnt(outfile,'Saarelma 6-parameter pedestal temperature scaling is ON') - - if(eped_warning() /= '')then - call ocmmnt(outfile,'WARNING: Pedestal parameters are outside the range of applicability of the scaling:') - call ocmmnt(outfile,'triang: 0.4 - 0.6; kappa: 1.5 - 2.0; plascur: 10 - 20 MA, rmajor: 7 - 11 m;') - call ocmmnt(outfile,'rminor: 2 - 3.5 m; tesep: 0 - 0.5 keV; normalised_total_beta: 2 - 3; ') - write(*,*)'WARNING: Pedestal parameters are outside the range of applicability of the scaling:' - write(*,*)'triang: 0.4 - 0.6; kappa: 1.5 - 2.0; plascur: 10 - 20 MA, rmajor: 7 - 11 m;' - write(*,*)'rminor: 2 - 3.5 m; tesep: 0 - 0.5 keV; normalised_total_beta: 2 - 3' - write(*,*)trim(eped_warning()) - endif - endif - call ovarrf(outfile,'Electron temp. pedestal height (keV)','(teped)',teped) - if (any(icc == 78)) then - call ovarrf(outfile,'Electron temp. at separatrix (keV)','(tesep)',tesep, 'OP ') - else - call ovarrf(outfile,'Electron temp. at separatrix (keV)','(tesep)',tesep) - endif - call ovarre(outfile,'Electron density at separatrix (/m3)','(nesep)',nesep) - call ovarre(outfile,'Electron density at separatrix / nGW','(fgwsep_out)',fgwsep_out) - - endif - - ! Issue 558 - addition of constraint 76 to limit the value of nesep, in proportion with the ballooning parameter and Greenwald density - if(any(icc==76))then - call ovarre(outfile,'Critical ballooning parameter value','(alpha_crit)',alpha_crit) - call ovarre(outfile,'Critical electron density at separatrix (/m3)','(nesep_crit)',nesep_crit) - endif - - call ovarrf(outfile,'Temperature profile index','(alphat)',alphat) - call ovarrf(outfile,'Temperature profile index beta','(tbeta)',tbeta) - - if (istell == 0) then - call osubhd(outfile,'Density Limit using different models :') - call ovarre(outfile,'Old ASDEX model','(dlimit(1))',dlimit(1), 'OP ') - call ovarre(outfile,'Borrass ITER model I','(dlimit(2))',dlimit(2), 'OP ') - call ovarre(outfile,'Borrass ITER model II','(dlimit(3))',dlimit(3), 'OP ') - call ovarre(outfile,'JET edge radiation model','(dlimit(4))',dlimit(4), 'OP ') - call ovarre(outfile,'JET simplified model','(dlimit(5))',dlimit(5), 'OP ') - call ovarre(outfile,'Hugill-Murakami Mq model','(dlimit(6))',dlimit(6), 'OP ') - call ovarre(outfile,'Greenwald model','(dlimit(7))',dlimit(7), 'OP ') - end if - - call osubhd(outfile,'Fuel Constituents :') - call ovarrf(outfile,'Deuterium fuel fraction','(fdeut)',fdeut) - call ovarrf(outfile,'Tritium fuel fraction','(ftrit)',ftrit) - if (fhe3 > 1.0D-3) call ovarrf(outfile,'3-Helium fuel fraction','(fhe3)',fhe3) - - call osubhd(outfile,'Fusion Power :') - call ovarre(outfile,'Total fusion power (MW)','(powfmw)',powfmw, 'OP ') - call ovarre(outfile,' = D-T fusion power (MW)','(pdt)',pdt, 'OP ') - call ovarre(outfile,' + D-D fusion power (MW)','(pdd)',pdd, 'OP ') - call ovarre(outfile,' + D-He3 fusion power (MW)','(pdhe3)',pdhe3, 'OP ') - call ovarre(outfile,'Alpha power: total (MW)','(palpmw)',palpmw, 'OP ') - call ovarre(outfile,'Alpha power: beam-plasma (MW)','(palpnb)',palpnb, 'OP ') - call ovarre(outfile,'Neutron power (MW)','(pneutmw)',pneutmw, 'OP ') - call ovarre(outfile,'Charged particle power (excluding alphas) (MW)', '(pchargemw)',pchargemw, 'OP ') - tot_power_plasma=falpha*palpmw+pchargemw+pohmmw+pinjmw - call ovarre(outfile,'Total power deposited in plasma (MW)','(tot_power_plasma)',tot_power_plasma, 'OP ') - !call ovarre(outfile,'Total power deposited in plasma (MW)','()',falpha*palpmw+pchargemw+pohmmw+pinjmw, 'OP ') - - call osubhd(outfile,'Radiation Power (excluding SOL):') - call ovarre(outfile,'Bremsstrahlung radiation power (MW)','(pbrempv*vol)', pbrempv*vol, 'OP ') - call ovarre(outfile,'Line radiation power (MW)','(plinepv*vol)', plinepv*vol, 'OP ') - call ovarre(outfile,'Synchrotron radiation power (MW)','(psyncpv*vol)', psyncpv*vol, 'OP ') - call ovarrf(outfile,'Synchrotron wall reflectivity factor','(ssync)',ssync) - call ovarre(outfile,"Normalised minor radius defining 'core'", '(coreradius)',coreradius) - call ovarre(outfile,"Fraction of core radiation subtracted from P_L", & - '(coreradiationfraction)',coreradiationfraction) - call ovarre(outfile,'Radiation power from inner zone (MW)', '(pinnerzoneradmw)',pinnerzoneradmw, 'OP ') - call ovarre(outfile,'Radiation power from outer zone (MW)','(pouterzoneradmw)', pouterzoneradmw, 'OP ') - - if (istell/=0) then - call ovarre(outfile,'SOL radiation power as imposed by f_rad (MW)','(psolradmw)', psolradmw, 'OP ') - end if - - call ovarre(outfile,'Total radiation power from inside LCFS (MW)','(pradmw)',pradmw, 'OP ') - call ovarre(outfile,'LCFS radiation fraction = total radiation in LCFS / total power deposited in plasma', & - '(rad_fraction_LCFS)', rad_fraction_LCFS, 'OP ') - call ovarre(outfile,'Nominal mean radiation load on inside surface of reactor (MW/m2)', & - '(photon_wall)', photon_wall, 'OP ') - call ovarre(outfile,'Peaking factor for radiation wall load', & - '(peakfactrad)', peakfactrad, 'IP ') - call ovarre(outfile,'Maximum permitted radiation wall load (MW/m^2)', & - '(maxradwallload)', maxradwallload, 'IP ') - call ovarre(outfile,'Peak radiation wall load (MW/m^2)', & - '(peakradwallload)', peakradwallload, 'OP ') - call ovarre(outfile,'Fast alpha particle power incident on the first wall (MW)', & - '(palpfwmw)', palpfwmw, 'OP ') - call ovarre(outfile,'Nominal mean neutron load on inside surface of reactor (MW/m2)', & - '(wallmw)', wallmw, 'OP ') - - if (istell == 0) then - call oblnkl(outfile) - call ovarre(outfile,'Power incident on the divertor targets (MW)', & - '(ptarmw)',ptarmw, 'OP ') - call ovarre(outfile, 'Fraction of power to the lower divertor', & - '(ftar)', ftar, 'IP ') - call ovarre(outfile,'Outboard side heat flux decay length (m)', & - '(lambdaio)',lambdaio, 'OP ') - if (idivrt == 2) then - call ovarre(outfile,'Midplane seperation of the two magnetic closed flux surfaces (m)', & - '(drsep)',drsep, 'OP ') - end if - call ovarre(outfile,'Fraction of power on the inner targets', & - '(fio)',fio, 'OP ') - call ovarre(outfile,'Fraction of power incident on the lower inner target', & - '(fLI)',fLI, 'OP ') - call ovarre(outfile,'Fraction of power incident on the lower outer target', & - '(fLO)',fLO, 'OP ') - if (idivrt == 2 ) then - call ovarre(outfile,'Fraction of power incident on the upper inner target', & - '(fUI)',fUI, 'OP ') - call ovarre(outfile,'Fraction of power incident on the upper outer target', & - '(fUO)',fUO, 'OP ') - end if - call ovarre(outfile,'Power incident on the lower inner target (MW)', & - '(pLImw)',pLImw, 'OP ') - call ovarre(outfile,'Power incident on the lower outer target (MW)', & - '(pLOmw)',pLOmw, 'OP ') - if (idivrt == 2) then - call ovarre(outfile,'Power incident on the upper innner target (MW)', & - '(pUImw)',pUImw, 'OP ') - call ovarre(outfile,'Power incident on the upper outer target (MW)', & - '(pUOmw)',pUOmw, 'OP ') - end if - end if - - call oblnkl(outfile) - call ovarre(outfile,'Ohmic heating power (MW)','(pohmmw)',pohmmw, 'OP ') - call ovarrf(outfile,'Fraction of alpha power deposited in plasma','(falpha)',falpha, 'OP ') - call ovarrf(outfile,'Fraction of alpha power to electrons','(falpe)',falpe, 'OP ') - call ovarrf(outfile,'Fraction of alpha power to ions','(falpi)',falpi, 'OP ') - call ovarre(outfile,'Ion transport (MW)','(ptrimw)',ptrimw, 'OP ') - call ovarre(outfile,'Electron transport (MW)','(ptremw)',ptremw, 'OP ') - call ovarre(outfile,'Injection power to ions (MW)','(pinjimw)',pinjimw, 'OP ') - call ovarre(outfile,'Injection power to electrons (MW)','(pinjemw)',pinjemw, 'OP ') - if (ignite == 1) then - call ocmmnt(outfile,' (Injected power only used for start-up phase)') - end if - call ovarin(outfile,'Ignited plasma switch (0=not ignited, 1=ignited)', '(ignite)',ignite) - - call oblnkl(outfile) - call ovarre(outfile,'Power into divertor zone via charged particles (MW)','(pdivt)',pdivt, 'OP ') - - if (pdivt <= 0.001D0) then - fdiags(1) = pdivt ; call report_error(87) - call oblnkl(outfile) - call ocmmnt(outfile,' BEWARE: possible problem with high radiation power') - call ocmmnt(outfile,' Power into divertor zone is unrealistic;') - call ocmmnt(outfile,' divertor calculations will be nonsense!') - call ocmmnt(outfile,' Set constraint 17 (Radiation fraction upper limit).') - call oblnkl(outfile) - end if - - if (idivrt == 2) then - ! Double null divertor configuration - call ovarre(outfile,'Pdivt / R ratio (MW/m) (On peak divertor)','(pdivmax/rmajor)',pdivmax/rmajor, 'OP ') - call ovarre(outfile,'Pdivt Bt / qAR ratio (MWT/m) (On peak divertor)','(pdivmaxbt/qar)', ((pdivmax*bt)/(q95*aspect*rmajor)), 'OP ') - else - ! Single null divertor configuration - call ovarre(outfile,'Psep / R ratio (MW/m)','(pdivt/rmajor)',pdivt/rmajor, 'OP ') - call ovarre(outfile,'Psep Bt / qAR ratio (MWT/m)','(pdivtbt/qar)', ((pdivt*bt)/(q95*aspect*rmajor)), 'OP ') - end if - - if (istell == 0) then - call osubhd(outfile,'H-mode Power Threshold Scalings :') - - call ovarre(outfile,'ITER 1996 scaling: nominal (MW)','(pthrmw(1))', pthrmw(1), 'OP ') - call ovarre(outfile,'ITER 1996 scaling: upper bound (MW)','(pthrmw(2))', pthrmw(2), 'OP ') - call ovarre(outfile,'ITER 1996 scaling: lower bound (MW)','(pthrmw(3))', pthrmw(3), 'OP ') - call ovarre(outfile,'ITER 1997 scaling (1) (MW)','(pthrmw(4))',pthrmw(4), 'OP ') - call ovarre(outfile,'ITER 1997 scaling (2) (MW)','(pthrmw(5))',pthrmw(5), 'OP ') - call ovarre(outfile,'Martin 2008 scaling: nominal (MW)', '(pthrmw(6))',pthrmw(6), 'OP ') - call ovarre(outfile,'Martin 2008 scaling: 95% upper bound (MW)', '(pthrmw(7))',pthrmw(7), 'OP ') - call ovarre(outfile,'Martin 2008 scaling: 95% lower bound (MW)', '(pthrmw(8))',pthrmw(8), 'OP ') - call ovarre(outfile,'Snipes 2000 scaling: nominal (MW)', '(pthrmw(9))',pthrmw(9), 'OP ') - call ovarre(outfile,'Snipes 2000 scaling: upper bound (MW)', '(pthrmw(10))',pthrmw(10), 'OP ') - call ovarre(outfile,'Snipes 2000 scaling: lower bound (MW)', '(pthrmw(11))',pthrmw(11), 'OP ') - call ovarre(outfile,'Snipes 2000 scaling (closed divertor): nominal (MW)', '(pthrmw(12))',pthrmw(12), 'OP ') - call ovarre(outfile,'Snipes 2000 scaling (closed divertor): upper bound (MW)', '(pthrmw(13))',pthrmw(13), 'OP ') - call ovarre(outfile,'Snipes 2000 scaling (closed divertor): lower bound (MW)', '(pthrmw(14))',pthrmw(14), 'OP ') - call ovarre(outfile,'Hubbard 2012 L-I threshold - nominal (MW)', '(pthrmw(15))',pthrmw(15), 'OP ') - call ovarre(outfile,'Hubbard 2012 L-I threshold - lower bound (MW)', '(pthrmw(16))',pthrmw(16), 'OP ') - call ovarre(outfile,'Hubbard 2012 L-I threshold - upper bound (MW)', '(pthrmw(17))',pthrmw(17), 'OP ') - call ovarre(outfile,'Hubbard 2017 L-I threshold', '(pthrmw(18))',pthrmw(18), 'OP ') - call ovarre(outfile,'Martin 2008 aspect ratio corrected scaling: nominal (MW)', '(pthrmw(19))',pthrmw(19), 'OP ') - call ovarre(outfile,'Martin 2008 aspect ratio corrected scaling: 95% upper bound (MW)', '(pthrmw(20))',pthrmw(20), 'OP ') - call ovarre(outfile,'Martin 2008 aspect ratio corrected scaling: 95% lower bound (MW)', '(pthrmw(21))',pthrmw(21), 'OP ') - call oblnkl(outfile) - if ((ilhthresh.eq.9).or.(ilhthresh.eq.10).or.(ilhthresh.eq.11)) then - if ((bt < 0.78D0).or.(bt > 7.94D0)) then - call ocmmnt(outfile,'(bt outside Snipes 2000 fitted range)') - call report_error(201) - end if - if ((rminor < 0.15D0).or.(rminor > 1.15D0)) then - call ocmmnt(outfile,'(rminor outside Snipes 2000 fitted range)') - call report_error(202) - end if - if ((rmajor < 0.55D0).or.(rmajor > 3.37D0)) then - call ocmmnt(outfile,'(rmajor outside Snipes 2000 fitted range)') - call report_error(203) - end if - if ((dnla < 0.09D20).or.(dnla > 3.16D20)) then - call ocmmnt(outfile,'(dnla outside Snipes 2000 fitted range)') - call report_error(204) - end if - if ((kappa < 1.0D0).or.(kappa > 2.04D0)) then - call ocmmnt(outfile,'(kappa outside Snipes 2000 fitted range)') - call report_error(205) - end if - if ((triang < 0.07D0).or.(triang > 0.74D0)) then - call ocmmnt(outfile,'(triang outside Snipes 2000 fitted range)') - call report_error(206) - end if - call oblnkl(outfile) - end if - if ((ilhthresh.eq.12).or.(ilhthresh.eq.13).or.(ilhthresh.eq.14)) then - call ocmmnt(outfile,'(L-H threshold for closed divertor only. Limited data used in Snipes fit)') - call oblnkl(outfile) - call report_error(207) - end if - if ((ioptimz > 0).and.(active_constraints(15))) then - call ovarre(outfile,'L-H threshold power (enforced) (MW)', '(boundl(103)*plhthresh)',boundl(103)*plhthresh, 'OP ') - call ovarre(outfile,'L-H threshold power (MW)', '(plhthresh)',plhthresh, 'OP ') - else - call ovarre(outfile,'L-H threshold power (NOT enforced) (MW)', '(plhthresh)',plhthresh, 'OP ') - end if - end if - - call osubhd(outfile,'Confinement :') - - if (ignite == 1) then - call ocmmnt(outfile, & - 'Device is assumed to be ignited for the calculation of confinement time') - call oblnkl(outfile) - end if - - write(outfile,200) tauscl(isc) -200 format(' Confinement scaling law',T45,A24) - - if (index(tauscl(isc),'(') /= 0) then - tauelaw = '"'//trim(tauscl(isc)(1:index(tauscl(isc),'(',.true.)-1))//'"' - else - tauelaw = '"'//trim(tauscl(isc))//'"' - end if - call ovarst(mfile,'Confinement scaling law','(tauelaw)',trim(tauelaw)) - - call ovarrf(outfile,'Confinement H factor','(hfact)',hfact) - call ovarrf(outfile,'Global thermal energy confinement time (s)','(taueff)',taueff, 'OP ') - call ovarrf(outfile,'Ion energy confinement time (s)','(tauei)',tauei, 'OP ') - call ovarrf(outfile,'Electron energy confinement time (s)','(tauee)',tauee, 'OP ') - call ovarre(outfile,'n.tau = Volume-average electron density x Energy confinement time (s/m3)', & - '(dntau)', dntau, 'OP ') - call ocmmnt(outfile,'Triple product = Vol-average electron density x Vol-average& - & electron temperature x Energy confinement time:') - call ovarre(outfile,'Triple product (keV s/m3)','(dntau*te)',dntau*te, 'OP ') - call ovarre(outfile,'Transport loss power assumed in scaling law (MW)', '(powerht)',powerht, 'OP ') - call ovarin(outfile,'Switch for radiation loss term usage in power balance', '(iradloss)',iradloss) - if (iradloss == 0) then - call ovarre(outfile,'Radiation power subtracted from plasma power balance (MW)', '',pradmw, 'OP ') - call ocmmnt(outfile,' (Radiation correction is total radiation power)') - else if (iradloss == 1) then - call ovarre(outfile,'Radiation power subtracted from plasma power balance (MW)', '',pinnerzoneradmw, 'OP ') - call ocmmnt(outfile,' (Radiation correction is core radiation power)') - else - call ovarre(outfile,'Radiation power subtracted from plasma power balance (MW)', '',0.0D0) - call ocmmnt(outfile,' (No radiation correction applied)') - end if - call ovarrf(outfile,'Alpha particle confinement time (s)','(taup)',taup, 'OP ') - ! Note alpha confinement time is no longer equal to fuel particle confinement time. - call ovarrf(outfile,'Alpha particle/energy confinement time ratio','(taup/taueff)',taup/taueff, 'OP ') - call ovarrf(outfile,'Lower limit on taup/taueff','(taulimit)',taulimit) - call ovarrf(outfile,'Total energy confinement time including radiation loss (s)', & - '(total_energy_conf_time)', total_energy_conf_time, 'OP ') - call ocmmnt(outfile,' (= stored energy including fast particles / loss power including radiation') - - if (istell == 0) then - ! Issues 363 Output dimensionless plasma parameters MDK - call osubhd(outfile,'Dimensionless plasma parameters') - call ocmmnt(outfile,'For definitions see') - call ocmmnt(outfile,'Recent progress on the development and analysis of the ITPA global H-mode confinement database') - call ocmmnt(outfile,'D.C. McDonald et al, 2007 Nuclear Fusion v47, 147. (nu_star missing 1/mu0)') - call ovarre(outfile,'Normalized plasma pressure beta as defined by McDonald et al', '(beta_mcdonald)',beta_mcdonald,'OP ') - call ovarre(outfile,'Normalized ion Larmor radius', '(rho_star)', rho_star,'OP ') - call ovarre(outfile,'Normalized collisionality', '(nu_star)',nu_star,'OP ') - call ovarre(outfile,'Volume measure of elongation','(kappaa_IPB)',kappaa_IPB,'OP ') - - - call osubhd(outfile,'Plasma Volt-second Requirements :') - call ovarre(outfile,'Total volt-second requirement (Wb)','(vsstt)',vsstt, 'OP ') - call ovarre(outfile,'Inductive volt-seconds (Wb)','(vsind)',vsind, 'OP ') - call ovarrf(outfile,'Ejima coefficient','(gamma)',gamma) - call ovarre(outfile,'Start-up resistive (Wb)','(vsres)',vsres, 'OP ') - call ovarre(outfile,'Flat-top resistive (Wb)','(vsbrn)',vsbrn, 'OP ') - - call ovarrf(outfile,'bootstrap current fraction multiplier', '(cboot)',cboot) - call ovarrf(outfile,'Bootstrap fraction (ITER 1989)', '(bscf_iter89)',bscf_iter89, 'OP ') - - - call ovarrf(outfile,'Bootstrap fraction (Sauter et al)', '(bscf_sauter)',bscf_sauter, 'OP ') - - - call ovarrf(outfile,'Bootstrap fraction (Nevins et al)', '(bscf_nevins)',bscf_nevins, 'OP ') - call ovarrf(outfile,'Bootstrap fraction (Wilson)', '(bscf_wilson)',bscf_wilson, 'OP ') - call ovarrf(outfile,'Diamagnetic fraction (Hender)', '(diacf_hender)',diacf_hender, 'OP ') - call ovarrf(outfile,'Diamagnetic fraction (SCENE)', '(diacf_scene)',diacf_scene, 'OP ') - call ovarrf(outfile,'Pfirsch-Schlueter fraction (SCENE)', '(pscf_scene)',pscf_scene, 'OP ') - ! Error to catch if bootstap fraction limit has been enforced - if (err242==1)then - call report_error(242) - end if - ! Error to catch if self-driven current fraction limit has been enforced - if (err243==1)then - call report_error(243) - end if - - if (bscfmax < 0.0D0) then - call ocmmnt(outfile,' (User-specified bootstrap current fraction used)') - else if (ibss == 1) then - call ocmmnt(outfile,' (ITER 1989 bootstrap current fraction model used)') - else if (ibss == 2) then - call ocmmnt(outfile,' (Nevins et al bootstrap current fraction model used)') - else if (ibss == 3) then - call ocmmnt(outfile,' (Wilson bootstrap current fraction model used)') - else if (ibss == 4) then - call ocmmnt(outfile,' (Sauter et al bootstrap current fraction model used)') - end if - - if (idia == 0) then - call ocmmnt(outfile,' (Diamagnetic current fraction not calculated)') - ! Error to show if diamagnetic current is above 1% but not used - if (diacf_scene.gt.0.01D0) then - call report_error(244) - end if - else if (idia == 1) then - call ocmmnt(outfile,' (Hender diamagnetic current fraction scaling used)') - else if (idia == 2) then - call ocmmnt(outfile,' (SCENE diamagnetic current fraction scaling used)') - - if (ips == 0) then - call ocmmnt(outfile,' (Pfirsch-Schlüter current fraction not calculated)') - else if (ips == 1) then - call ocmmnt(outfile,' (SCENE Pfirsch-Schlüter current fraction scaling used)') - end if - - endif - - call ovarrf(outfile,'Bootstrap fraction (enforced)','(bootipf.)',bootipf, 'OP ') - call ovarrf(outfile,'Diamagnetic fraction (enforced)','(diaipf.)',diaipf, 'OP ') - call ovarrf(outfile,'Pfirsch-Schlueter fraction (enforced)','(psipf.)',psipf, 'OP ') - - call ovarre(outfile,'Loop voltage during burn (V)','(vburn)', plascur*rplas*facoh, 'OP ') - call ovarre(outfile,'Plasma resistance (ohm)','(rplas)',rplas, 'OP ') - - call ovarre(outfile,'Resistive diffusion time (s)','(res_time)',res_time, 'OP ') - call ovarre(outfile,'Plasma inductance (H)','(rlp)',rlp, 'OP ') - call ovarrf(outfile,'Coefficient for sawtooth effects on burn V-s requirement','(csawth)',csawth) - end if - - call osubhd(outfile,'Fuelling :') - call ovarre(outfile,'Ratio of He and pellet particle confinement times','(tauratio)',tauratio) - call ovarre(outfile,'Fuelling rate (nucleus-pairs/s)','(qfuel)',qfuel, 'OP ') - call ovarre(outfile,'Fuel burn-up rate (reactions/s)','(rndfuel)',rndfuel, 'OP ') - call ovarrf(outfile,'Burn-up fraction','(burnup)',burnup, 'OP ') - - - if (any(icc == 78)) then - call osubhd(outfile,'Reinke Criterion :') - call ovarin(outfile,'index of impurity to be iterated for divertor detachment', '(impvardiv)',impvardiv) - call ovarre(outfile,'Minimum Impurity fraction from Reinke','(fzmin)',fzmin, 'OP ') - call ovarre(outfile,'Actual Impurity fraction','(fzactual)',fzactual) - endif - end subroutine outplas - - ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - subroutine outtim(outfile) - - !! Routine to print out the times of the various stages - !! during a single plant cycle - !! author: P J Knight, CCFE, Culham Science Centre - !! outfile : input integer : Fortran output unit identifier - !! This routine writes out the times of the various stages - !! during a single plant cycle. - !! AEA FUS 251: A User's Guide to the PROCESS Systems Code - ! - ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - use process_output, only: ovarrf, ovarre, oheadr, oblnkl - use times_variables, only: tramp, theat, tcycle, tohs, tdwell, tqnch, tburn - implicit none - - ! Arguments - - integer, intent(in) :: outfile - - ! Local variables - - ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - call oheadr(outfile,'Times') - - call ovarrf(outfile,'Initial charge time for CS from zero current (s)','(tramp)', tramp) - call ovarrf(outfile,'Plasma current ramp-up time (s)','(tohs)',tohs) - call ovarrf(outfile,'Heating time (s)','(theat)',theat) - call ovarre(outfile,'Burn time (s)','(tburn)',tburn, 'OP ') - call ovarrf(outfile,'Reset time to zero current for CS (s)','(tqnch)',tqnch) - call ovarrf(outfile,'Time between pulses (s)','(tdwell)',tdwell) - call oblnkl(outfile) - !call ovarre(outfile,'Pulse time (s)','(tpulse)',tpulse, 'OP ') - !call ovarrf(outfile,'Down time (s)','(tdown)',tdown, 'OP ') - call ovarre(outfile,'Total plant cycle time (s)','(tcycle)',tcycle, 'OP ') - - end subroutine outtim - end module physics_module diff --git a/tests/regression/scenarios/large-tokamak/ref.MFILE.DAT b/tests/regression/scenarios/large-tokamak/ref.MFILE.DAT index d1899c6212..c7e9b746d6 100644 --- a/tests/regression/scenarios/large-tokamak/ref.MFILE.DAT +++ b/tests/regression/scenarios/large-tokamak/ref.MFILE.DAT @@ -2,15 +2,15 @@ # Power Reactor Optimisation Code # # PROCESS # # Power Reactor Optimisation Code # - PROCESS_version_number__________________________________________________ (procver)_____________________ "2.4.0 R" - Date_of_run_____________________________________________________________ (date)________________________ "15/08/2023" - Time_of_run_____________________________________________________________ (time)________________________ "11:53" + PROCESS_version_number__________________________________________________ (procver)_____________________ "3.0.1 R" + Date_of_run_____________________________________________________________ (date)________________________ "31/01/2024" + Time_of_run_____________________________________________________________ (time)________________________ "13:28" User____________________________________________________________________ (username)____________________ "timothyn" PROCESS_run_title_______________________________________________________ (runtitle)____________________ "Generic large tokamak - PROCESS_tag_number______________________________________________________ (tagno)_______________________ "" - PROCESS_git_branch_name_________________________________________________ (branch_name)_________________ "main" - PROCESS_last_commit_message_____________________________________________ (commsg)______________________ "Install PyVMCON from PyPI, not source ([hash]2851)" - Input_filename__________________________________________________________ (fileprefix)__________________ "/private/var/folders/2c/5k4t0wm94jxdmnqwdvn_h59r0000gq/T/pytest-of-timothynunn/pytest-108/test_scenario_large_tokamak_0/IN.DAT " + PROCESS_tag_number______________________________________________________ (tagno)_______________________ "v3.0.1-41-gc698cd140" + PROCESS_git_branch_name_________________________________________________ (branch_name)_________________ "convert-physics-to-python" + PROCESS_last_commit_message_____________________________________________ (commsg)______________________ "Convert Physics.f90 to Python" + Input_filename__________________________________________________________ (fileprefix)__________________ "/private/var/folders/2c/5k4t0wm94jxdmnqwdvn_h59r0000gq/T/pytest-of-timothynunn/pytest-45/test_scenario_large_tokamak_0/IN.DAT " # Numerics # VMCON_error_flag________________________________________________________ (ifail)_______________________ 1 # PROCESS found a feasible solution # @@ -347,12 +347,12 @@ Total_toroidal_beta_____________________________________________________ ______________________________ 3.5056E-02 OP Fast_alpha_beta_________________________________________________________ (betaft)______________________ 4.2465E-03 OP Beam_ion_beta___________________________________________________________ (betanb)______________________ 0.0000E+00 OP - (Fast_alpha_+_beam_beta)/(thermal_beta)_________________________________ (gammaft)_____________________ 1.4215E-01 OP + (Fast_alpha_+_beam_physics_variables.beta)/(thermal_physics_variables.be (gammaft)_____________________ 1.4215E-01 OP Thermal_beta____________________________________________________________ ______________________________ 2.9874E-02 OP Thermal_poloidal_beta___________________________________________________ ______________________________ 1.1199E+00 OP - Thermal_toroidal_beta_(=_beta-exp)______________________________________ ______________________________ 3.0693E-02 OP - 2nd_stability_beta_:_beta_p_/_(R/a)_____________________________________ (eps*betap)___________________ 4.2636E-01 - 2nd_stability_beta_upper_limit__________________________________________ (epbetmax)____________________ 1.3800E+00 + Thermal_toroidal_physics_variables.beta_(=_beta-exp)____________________ ______________________________ 3.0693E-02 OP + 2nd_stability_physics_variables.beta_:_beta_p_/_(R/a)___________________ (eps*betap)___________________ 4.2636E-01 + 2nd_stability_physics_variables.beta_upper_limit________________________ (epbetmax)____________________ 1.3800E+00 Beta_g_coefficient______________________________________________________ (dnbeta)______________________ 4.8794E+00 Normalised_thermal_beta_________________________________________________ ______________________________ 2.5111E+00 Normalised_total_beta___________________________________________________ ______________________________ 2.8680E+00 @@ -390,7 +390,7 @@ Fe_concentration________________________________________________________ (fimp(10))____________________ 0.0000E+00 Ni_concentration________________________________________________________ (fimp(11))____________________ 0.0000E+00 Kr_concentration________________________________________________________ (fimp(12))____________________ 0.0000E+00 - Xe_concentration________________________________________________________ (fimp(13))____________________ 5.6341E-04 + Xe_concentration________________________________________________________ (fimp(13))____________________ 5.6341E-04 ITV W__concentration________________________________________________________ (fimp(14))____________________ 5.0000E-06 Average_mass_of_all_ions_(amu)__________________________________________ (aion)________________________ 2.7265E+00 OP Effective_charge________________________________________________________ (zeff)________________________ 2.4987E+00 @@ -433,7 +433,6 @@ Fraction_of_core_radiation_subtracted_from_P_L__________________________ (coreradiationfraction)_______ 6.0000E-01 Radiation_power_from_inner_zone_(MW)____________________________________ (pinnerzoneradmw)_____________ 9.0174E+01 OP Radiation_power_from_outer_zone_(MW)____________________________________ (pouterzoneradmw)_____________ 1.3309E+02 OP - SOL_radiation_power_as_imposed_by_f_rad_(MW)____________________________ (psolradmw)___________________ 0.0000E+00 OP Total_radiation_power_from_inside_LCFS_(MW)_____________________________ (pradmw)______________________ 2.2326E+02 OP LCFS_radiation_fraction_=_total_radiation_in_LCFS_/_total_power_deposite (rad_fraction_LCFS)___________ 5.8698E-01 OP Nominal_mean_radiation_load_on_inside_surface_of_reactor_(MW/m2)________ (photon_wall)_________________ 1.7498E-01 OP @@ -485,7 +484,6 @@ Martin_2008_aspect_ratio_corrected_scaling:_95%_lower_bound_(MW)________ (pthrmw(21))__________________ 6.6515E+01 OP L-H_threshold_power_(enforced)_(MW)_____________________________________ (boundl(103)*plhthresh)_______ 9.6473E+01 OP L-H_threshold_power_(MW)________________________________________________ (plhthresh)___________________ 9.6473E+01 OP - Confinement_scaling_law_________________________________________________ (tauelaw)_____________________ "IPB98(y,2)" Confinement_H_factor____________________________________________________ (hfact)_______________________ 1.1947E+00 ITV Global_thermal_energy_confinement_time_(s)______________________________ (taueff)______________________ 3.2694E+00 Ion_energy_confinement_time_(s)_________________________________________ (tauei)_______________________ 3.2694E+00 @@ -511,7 +509,7 @@ bootstrap_current_fraction_multiplier___________________________________ (cboot)_______________________ 1.0000E+00 Bootstrap_fraction_(ITER_1989)__________________________________________ (bscf_iter89)_________________ 3.7036E-01 Bootstrap_fraction_(Sauter_et_al)_______________________________________ (bscf_sauter)_________________ 4.1885E-01 - Bootstrap_fraction_(Nevins_et_al)_______________________________________ (bscf_nevins)_________________ 3.4880E-01 + Bootstrap_fraction_(Nevins_et_al)_______________________________________ (bscf_nevins)_________________ 3.5014E-01 Bootstrap_fraction_(Wilson)_____________________________________________ (bscf_wilson)_________________ 4.3324E-01 Diamagnetic_fraction_(Hender)___________________________________________ (diacf_hender)________________ 1.2186E-02 Diamagnetic_fraction_(SCENE)____________________________________________ (diacf_scene)_________________ 1.1246E-02 @@ -531,6 +529,7 @@ # Energy confinement times, and required H-factors : # # Current Drive System # Current_drive_efficiency_model__________________________________________ (iefrf)_______________________ 10 + Secondary_current_drive_efficiency_model________________________________ (iefrffix)____________________ 0 Ratio_of_power_for_flat-top_to_start-up_(MW)____________________________ (startupratio)________________ 1.0000E+00 Auxiliary_power_used_for_plasma_heating_only_(MW)_______________________ (pheat)_______________________ 7.5000E+01 Power_injected_for_current_drive_(MW)___________________________________ (pcurrentdrivemw)_____________ 3.9779E-01 @@ -746,7 +745,7 @@ Max_allowed_tfcoil_variables.ripple_amplitude_at_plasma_outboard_midplan (ripmax)______________________ 6.0000E-01 Ripple_amplitude_at_plasma_outboard_midplane_(%)________________________ (ripple)______________________ 6.0000E-01 OP Actual_quench_time_(or_time_constant)_(s)_______________________________ (tdmptf)______________________ 1.7534E+01 ITV - Vacuum_Vassel_stress_on_quench_(Pa)_____________________________________ (vv_stress_quench)____________ 6.2719E+07 OP + Vacuum_Vessel_stress_on_quench_(Pa)_____________________________________ (vv_stress_quench)____________ 6.2719E+07 OP Maximum_allowed_voltage_during_quench_due_to_insulation_(kV)____________ (vdalw)_______________________ 9.9851E+00 ITV Actual_quench_voltage_(kV)______________________________________________ (vtfskv)______________________ 9.9703E+00 OP Maximum_allowed_temp_rise_during_a_quench_(K)___________________________ (tmaxpro)_____________________ 1.5000E+02 diff --git a/tests/regression/scenarios/large-tokamak/ref.OUT.DAT b/tests/regression/scenarios/large-tokamak/ref.OUT.DAT index 82f47aa124..f64da13c55 100644 --- a/tests/regression/scenarios/large-tokamak/ref.OUT.DAT +++ b/tests/regression/scenarios/large-tokamak/ref.OUT.DAT @@ -25,15 +25,15 @@ ************************************************************************************************************** Program : - Version : 2.4.0 Release Date :: 2022-05-18 - Tag No. : - Branch : main - Git log : Install PyVMCON from PyPI, not source ([hash]2851) - Date/time : 15 Aug 2023 11:53:24 +01:00(hh:mm) UTC + Version : 3.0.1 Release Date :: 2023-11-01 + Tag No. : v3.0.1-41-gc698cd140 + Branch : convert-physics-to-python + Git log : Convert Physics.f90 to Python + Date/time : 31 Jan 2024 13:28:34 +00:00(hh:mm) UTC User : timothynunn Computer : L0268-iMac Directory : /Users/timothynunn/process - Input : /private/var/folders/2c/5k4t0wm94jxdmnqwdvn_h59r0000gq/T/pytest-of-timothynunn/pytest-108/test_scenario_large_tokamak_0/IN.DAT + Input : /private/var/folders/2c/5k4t0wm94jxdmnqwdvn_h59r0000gq/T/pytest-of-timothynunn/pytest-45/test_scenario_large_tokamak_0/IN.DAT Run title : Generic large tokamak Run type : Reactor concept design: Pulsed tokamak model, (c) CCFE @@ -417,12 +417,12 @@ PROCESS has successfully optimised the iteration variables to minimise the figur Total toroidal beta 3.506E-02 OP Fast alpha beta (betaft) 4.247E-03 OP Beam ion beta (betanb) 0.000E+00 OP - (Fast alpha + beam beta)/(thermal beta) (gammaft) 1.421E-01 OP + (Fast alpha + beam physics_variables.beta)/(thermal physics_variables.be (gammaft) 1.421E-01 OP Thermal beta 2.987E-02 OP Thermal poloidal beta 1.120E+00 OP - Thermal toroidal beta (= beta-exp) 3.069E-02 OP - 2nd stability beta : beta_p / (R/a) (eps*betap) 0.426 OP - 2nd stability beta upper limit (epbetmax) 1.380 + Thermal toroidal physics_variables.beta (= beta-exp) 3.069E-02 OP + 2nd stability physics_variables.beta : beta_p / (R/a) (eps*betap) 0.426 OP + 2nd stability physics_variables.beta upper limit (epbetmax) 1.380 Beta g coefficient (dnbeta) 4.879 OP Normalised thermal beta 2.511 OP Normalised total beta 2.868 OP @@ -467,7 +467,7 @@ PROCESS has successfully optimised the iteration variables to minimise the figur Fe concentration (fimp(10)) 0.000E+00 Ni concentration (fimp(11)) 0.000E+00 Kr concentration (fimp(12)) 0.000E+00 - Xe concentration (fimp(13)) 5.634E-04 + Xe concentration (fimp(13)) 5.634E-04 ITV W_ concentration (fimp(14)) 5.000E-06 Average mass of all ions (amu) (aion) 2.727E+00 OP @@ -524,7 +524,6 @@ PROCESS has successfully optimised the iteration variables to minimise the figur Fraction of core radiation subtracted from P_L (coreradiationfraction) 6.000E-01 Radiation power from inner zone (MW) (pinnerzoneradmw) 9.017E+01 OP Radiation power from outer zone (MW) (pouterzoneradmw) 1.331E+02 OP - SOL radiation power as imposed by f_rad (MW) (psolradmw) 0.000E+00 OP Total radiation power from inside LCFS (MW) (pradmw) 2.233E+02 OP LCFS radiation fraction = total radiation in LCFS / total power deposite (rad_fraction_LCFS) 5.870E-01 OP Nominal mean radiation load on inside surface of reactor (MW/m2) (photon_wall) 1.750E-01 OP @@ -581,18 +580,19 @@ PROCESS has successfully optimised the iteration variables to minimise the figur Martin 2008 aspect ratio corrected scaling: 95% upper bound (MW) (pthrmw(20)) 1.264E+02 OP Martin 2008 aspect ratio corrected scaling: 95% lower bound (MW) (pthrmw(21)) 6.652E+01 OP + L-H threshold power (enforced) (MW) (boundl(103)*plhthresh) 9.647E+01 OP L-H threshold power (MW) (plhthresh) 9.647E+01 OP Confinement : - Confinement scaling law IPB98(y,2) (H) + Confinement scaling law: b'IPB98(y,2) (H)' Confinement H factor (hfact) 1.195 ITV Global thermal energy confinement time (s) (taueff) 3.269 OP Ion energy confinement time (s) (tauei) 3.269 OP Electron energy confinement time (s) (tauee) 3.269 OP n.tau = Volume-average electron density x Energy confinement time (s/m3) (dntau) 2.635E+20 OP - Triple product = Vol-average electron density x Vol-average electron temperature x Energy confinement time: + Triple product = Vol-average electron density x Vol-average & electron temperature x Energy confinement time: Triple product (keV s/m3) (dntau*te) 3.277E+21 OP Transport loss power assumed in scaling law (MW) (powerht) 2.902E+02 OP Switch for radiation loss term usage in power balance (iradloss) 1 @@ -624,13 +624,14 @@ PROCESS has successfully optimised the iteration variables to minimise the figur bootstrap current fraction multiplier (cboot) 1.000 Bootstrap fraction (ITER 1989) (bscf_iter89) 0.370 OP Bootstrap fraction (Sauter et al) (bscf_sauter) 0.419 OP - Bootstrap fraction (Nevins et al) (bscf_nevins) 0.349 OP + Bootstrap fraction (Nevins et al) (bscf_nevins) 0.350 OP Bootstrap fraction (Wilson) (bscf_wilson) 0.433 OP Diamagnetic fraction (Hender) (diacf_hender) 0.012 OP Diamagnetic fraction (SCENE) (diacf_scene) 0.011 OP Pfirsch-Schlueter fraction (SCENE) (pscf_scene) -0.003 OP (Sauter et al bootstrap current fraction model used) (Diamagnetic current fraction not calculated) + Pfirsch-Schluter current fraction not calculated Bootstrap fraction (enforced) (bootipf.) 0.419 OP Diamagnetic fraction (enforced) (diaipf.) 0.000 OP Pfirsch-Schlueter fraction (enforced) (psipf.) 0.000 OP @@ -649,30 +650,30 @@ PROCESS has successfully optimised the iteration variables to minimise the figur ***************************** Energy confinement times, and required H-factors : ***************************** - scaling law confinement time (s) H-factor for - for H = 1 power balance - - IPB98(y) (H) 3.418 0.956 - IPB98(y,1) (H) 3.398 0.962 - IPB98(y,2) (H) 2.737 1.195 - IPB98(y,3) (H) 2.809 1.164 - IPB98(y,4) (H) 2.818 1.160 - ISS95 (stell) 1.885 1.734 - ISS04 (stell) 3.293 0.992 - DS03 (H) 4.013 0.814 - Murari et al NPL (H) 2.033 1.608 - Petty 2008 (H) 4.870 0.672 - Lang et al. 2012 (H) 1.717 1.905 - Hubbard 2017 - nom (I) 0.065 50.097 - Hubbard 2017 - lower (I) 0.037 87.868 - Hubbard 2017 - upper (I) 0.114 28.562 - NSTX (Spherical) (H) 6.677 0.489 - NSTX-Petty08 Hybrid (H) 4.870 0.672 + scaling law confinement time (s) H-factor for + for H = 1 power balance + IPB98(y) (H) 3.418 0.956 + IPB98(y,1) (H) 3.398 0.962 + IPB98(y,2) (H) 2.737 1.195 + IPB98(y,3) (H) 2.809 1.164 + IPB98(y,4) (H) 2.818 1.160 + ISS95 (stell) 1.885 1.734 + ISS04 (stell) 3.293 0.992 + DS03 (H) 4.013 0.814 + Murari et al NPL (H) 2.033 1.608 + Petty 2008 (H) 4.870 0.672 + Lang et al. 2012 (H) 1.717 1.905 + Hubbard 2017 - nom (I) 0.065 50.097 + Hubbard 2017 - lower (I) 0.037 87.868 + Hubbard 2017 - upper (I) 0.114 28.562 + NSTX (Spherical) (H) 6.677 0.489 + NSTX-Petty08 Hybrid (H) 4.870 0.672 ******************************************** Current Drive System ******************************************** Electron Cyclotron Current Drive (user input gamma_CD) Current drive efficiency model (iefrf) 10 + Secondary current drive efficiency model (iefrffix) 0 Current is driven by both inductive and non-inductive means. @@ -818,14 +819,14 @@ PROCESS has successfully optimised the iteration variables to minimise the figur Materal stress of the point of maximum shear stress (Tresca criterion) for each layer Please use utilities/plot_stress_tf.py for radial plots plots summary Layers Steel case WP Outer case - Radial stress (MPa) 4.884866930978646e-14 -143.73232373861893 6.204164059945074 - Toroidal stress (MPa) -489.9238263941959 -377.9366629374062 -366.9418355528041 - Vertical stress (MPa) 258.86339026661796 258.86339026661796 144.31111821875967 - Von-Mises stress (MPa) 658.6797045316131 554.6894102888741 456.5367412709292 - Shear (Tresca) (MPa) 748.7872166608139 636.8000532040242 511.25295377156374 + Radial stress (MPa) 4.884866930978646e-14 -143.73232374130475 6.2041640597974785 + Toroidal stress (MPa) -489.9238264011406 -377.93666294106964 -366.9418355440757 + Vertical stress (MPa) 258.86339026316233 258.86339026316233 144.3111182168326 + Von-Mises stress (MPa) 658.6797045355 554.6894102894352 456.5367412611505 + Shear (Tresca) (MPa) 748.787216664303 636.800053204232 511.2529537609082 - Toroidal modulus (GPa) 205.0 48.96805566472091 205.0 - Vertical modulus (GPa) 205.0 126.43000655578726 367.7263100699767 + Toroidal modulus (GPa) 205.0 48.968055666373715 205.0 + Vertical modulus (GPa) 205.0 126.43000655926919 367.7263100699783 WP transverse modulus (GPa) (eyoung_wp_trans*1.0d-9) 4.452E+01 OP WP vertical modulus (GPa) (eyoung_wp_axial*1.0d-9) 1.161E+02 OP @@ -862,11 +863,11 @@ PROCESS has successfully optimised the iteration variables to minimise the figur by a straight segment and elliptical arcs between the following points: point x(m) y(m) - 0 3.625333336675998 4.5506 + 0 3.6253333366759968 4.5506 1 7.466666666666667 7.584333333333334 - 2 14.53614117428001 0.0 + 2 14.53614117423021 0.0 3 7.466666666666667 -8.818217164127494 - 4 3.625333336675998 -5.290930298476496 + 4 3.6253333366759968 -5.290930298476496 Global material area/fractions: @@ -964,7 +965,7 @@ PROCESS has successfully optimised the iteration variables to minimise the figur Quench information : Actual quench time (or time constant) (s) (tdmptf) 1.753E+01 ITV - Vacuum Vassel stress on quench (Pa) (vv_stress_quench) 6.272E+07 OP + Vacuum Vessel stress on quench (Pa) (vv_stress_quench) 6.272E+07 OP Maximum allowed voltage during quench due to insulation (kV) (vdalw) 9.985E+00 ITV Actual quench voltage (kV) (vtfskv) 9.970E+00 OP Maximum allowed temp rise during a quench (K) (tmaxpro) 1.500E+02 @@ -1160,7 +1161,7 @@ PROCESS has successfully optimised the iteration variables to minimise the figur 3 0.000e+00 0.000e+00 -7.154e+06 -7.154e+06 -7.154e+06 0.0e0 4 0.000e+00 0.000e+00 -4.852e+06 -4.852e+06 -4.852e+06 0.0e0 5 0.000e+00 0.000e+00 -4.852e+06 -4.852e+06 -4.852e+06 0.0e0 - 6 0.000e+00 0.000e+00 4.096e-09 4.096e-09 0.000e+00 0.0e0 + 6 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.0e0 Ratio of central solenoid current at beginning of Pulse / end of flat-to (fcohbop) 9.687E-01 ITV Ratio of central solenoid current at beginning of Flat-top / end of flat (fcohbof) -1.701E-01 OP @@ -1519,16 +1520,16 @@ PROCESS has successfully optimised the iteration variables to minimise the figur htpmw_blkt 0.00 0.00 Shield: - 1.3935888986974982 0.0 1.3935888986974982 + 1.3935888984449547 0.0 1.3935888984449547 0.0e0 0.0e0 0.0e0 0.0e0 0.0e0 0.0e0 - 0.0069679444934874915 0.0 0.0069679444934874915 + 0.006967944492224773 0.0 0.006967944492224773 Divertor: - 146.93029804056846 0.0 146.93029804056846 - 157.09558934002595 0.0 157.09558934002595 - 25.675194656516506 0.0 25.675194656516506 - 1.6485054101855547 0.0 1.6485054101855547 + 146.93029801393774 0.0 146.93029801393774 + 157.09558926414797 0.0 157.09558926414797 + 25.675194651036445 0.0 25.675194651036445 + 1.648505409645611 0.0 1.648505409645611 TF coil: ptfnuc 0.00 0.02 @@ -1542,7 +1543,7 @@ PROCESS has successfully optimised the iteration variables to minimise the figur pradhcd 0.00 0.00 0.0e0 0.0e0 0.0e0 - 1978.7927750049373 0.024103348232513956 1978.8168783531698 + 1978.792774591497 0.024103348230210837 1978.8168779397272 Total power leaving reactor (across vacuum vessel boundary) (MW) 1978.841 OP @@ -1636,39 +1637,39 @@ PROCESS has successfully optimised the iteration variables to minimise the figur tramp tohs theat tburn tqnch tdwell ----- ---- ----- ----- ----- ------ - Duration 500.0 166.16203759462505 10.0 7210.408167852351 166.16203759462505 1800.0 + Duration 500.0 166.16203759180593 10.0 7210.408167573202 166.16203759180593 1800.0 ------ ----- ---- ----- ----- ----- ------ Continous power usage [MWe]: System tramp tohs theat tburn tqnch tdwell ------ ----- ---- ----- ----- ----- ------ - Primary cooling 187.7984301903559 187.7984301903559 187.7984301903559 187.7984301903559 187.7984301903559 187.7984301903559 - Cryoplant 35.615768698828035 35.615768698828035 35.615768698828035 35.615768698828035 35.615768698828035 35.615768698828035 + Primary cooling 187.7984301553273 187.7984301553273 187.7984301553273 187.7984301553273 187.7984301553273 187.7984301553273 + Cryoplant 35.61576869500067 35.61576869500067 35.61576869500067 35.61576869500067 35.61576869500067 35.61576869500067 Vacuum 0.5 0.5 0.5 0.5 0.5 0.5 Tritium 15.0 15.0 15.0 15.0 15.0 15.0 - TF 9.854833388897118 9.854833388897118 9.854833388897118 9.854833388897118 9.854833388897118 9.854833388897118 - Facilities 55.405448398312224 55.405448398312224 55.405448398312224 55.405448398312224 55.405448398312224 55.405448398312224 + TF 9.854833386636704 9.854833386636704 9.854833386636704 9.854833386636704 9.854833386636704 9.854833386636704 + Facilities 55.405448398646456 55.405448398646456 55.405448398646456 55.405448398646456 55.405448398646456 55.405448398646456 ------ ----- ---- ----- ----- ----- ------ - Total 304.1744806763933 304.1744806763933 304.1744806763933 304.1744806763933 304.1744806763933 304.1744806763933 + Total 304.17448063561113 304.17448063561113 304.17448063561113 304.17448063561113 304.17448063561113 304.17448063561113 ------ ----- ---- ----- ----- ----- ------ Intermittent power usage [MWe]: System tramp tohs theat tburn tqnch tdwell ------ ----- ---- ----- ----- ----- ------ - H & CD 0.0 240.0 240.0 150.79557756173983 240.0 0.0 - PF 46.51235286843421 -57.496752030386375 0.0 2.015020863847534 -169.905845595978 0.0 + H & CD 0.0 240.0 240.0 150.7955774255487 240.0 0.0 + PF 46.51235285967593 -57.496752020712144 0.0 2.0150208625789845 -169.90584552472362 0.0 ------ ----- ---- ----- ----- ----- ------ - Total 46.51235286843421 182.50324796961362 240.0 152.81059842558736 70.09415440402199 0.0 + Total 46.51235285967593 182.50324797928786 240.0 152.81059828812766 70.09415447527638 0.0 ------ ----- ---- ----- ----- ----- ------ Power production [MWe]: tramp tohs theat tburn tqnch tdwell avg ----- ---- ----- ----- ----- ------ --- - Gross power 0.0 0.0 0.0 856.2087743663474 0.0 0.0 - Net power -350.6868335448275 -486.6777286460069 -544.1744806763933 399.2236952643667 -374.26863508041527 -304.1744806763933 + Gross power 0.0 0.0 0.0 856.2087741889977 0.0 0.0 + Net power -350.68683349528703 -486.677728614899 -544.1744806356112 399.2236952652589 -374.26863511088754 -304.17448063561113 ------ ----- ---- ----- ----- ----- ------ diff --git a/tests/unit/test_physics.py b/tests/unit/test_physics.py index 9020a02855..14ddcc2afb 100644 --- a/tests/unit/test_physics.py +++ b/tests/unit/test_physics.py @@ -1,26 +1,2729 @@ """Unit tests for physics.f90.""" -from process.fortran import physics_module as pm -from pytest import approx +from typing import Any, NamedTuple +from process.fortran import ( + physics_variables, + physics_module, + current_drive_variables, + impurity_radiation_module, + startup_variables, +) +import numpy +import pytest +from process.physics import Physics +from process.plasma_profiles import PlasmaProfile +from process.current_drive import CurrentDrive +from process.impurity_radiation import initialise_imprad -def test_diamagnetic_fraction_hender(): +@pytest.fixture +def physics(): + """Provides Physics object for testing. + + :returns: initialised Physics object + :rtype: process.physics.Physics + """ + return Physics(PlasmaProfile(), CurrentDrive()) + + +def test_diamagnetic_fraction_hender(physics): """Test diamagnetic_fraction_hender().""" beta = 0.14 - diacf = pm.diamagnetic_fraction_hender(beta) - assert diacf == approx(0.05, abs=0.0001) + diacf = physics.diamagnetic_fraction_hender(beta) + assert diacf == pytest.approx(0.05, abs=0.0001) -def test_diamagnetic_fraction_scene(): +def test_diamagnetic_fraction_scene(physics): """Test diamagnetic_fraction_scene.""" beta = 0.15 q95 = 3.0 q0 = 1.0 - diacf = pm.diamagnetic_fraction_scene(beta, q95, q0) - assert diacf == approx(0.0460, abs=0.0001) + diacf = physics.diamagnetic_fraction_scene(beta, q95, q0) + assert diacf == pytest.approx(0.0460, abs=0.0001) -def test_ps_fraction_scene(): +def test_ps_fraction_scene(physics): """Test ps_fraction_scene.""" beta = 0.15 - pscf = pm.ps_fraction_scene(beta) - assert pscf == approx(-0.0135, abs=0.0001) + pscf = physics.ps_fraction_scene(beta) + assert pscf == pytest.approx(-0.0135, abs=0.0001) + + +class BootstrapFractionIter89Param(NamedTuple): + aspect: Any = None + + beta: Any = None + + bt: Any = None + + cboot: Any = None + + plascur: Any = None + + q95: Any = None + + q0: Any = None + + rmajor: Any = None + + vol: Any = None + + expected_bootipf: Any = None + + +@pytest.mark.parametrize( + "bootstrapfractioniter89param", + ( + BootstrapFractionIter89Param( + aspect=3, + beta=0.030000000000000006, + bt=5.7802910787445487, + cboot=1, + plascur=18398455.678867526, + q95=3.5, + q0=1, + rmajor=8, + vol=1888.1711539956691, + expected_bootipf=0.30255906256775245, + ), + ), +) +def test_bootstrap_fraction_iter89(bootstrapfractioniter89param, physics): + """ + Automatically generated Regression Unit Test for bootstrap_fraction_iter89. + + This test was generated using data from tests/regression/scenarios/large-tokamak/IN.DAT. + + :param bootstrapfractioniter89param: the data used to mock and assert in this test. + :type bootstrapfractioniter89param: bootstrapfractioniter89param + + :param monkeypatch: pytest fixture used to mock module/class variables + :type monkeypatch: _pytest.monkeypatch.monkeypatch + """ + + bootipf = physics.bootstrap_fraction_iter89( + aspect=bootstrapfractioniter89param.aspect, + beta=bootstrapfractioniter89param.beta, + bt=bootstrapfractioniter89param.bt, + cboot=bootstrapfractioniter89param.cboot, + plascur=bootstrapfractioniter89param.plascur, + q95=bootstrapfractioniter89param.q95, + q0=bootstrapfractioniter89param.q0, + rmajor=bootstrapfractioniter89param.rmajor, + vol=bootstrapfractioniter89param.vol, + ) + + assert bootipf == pytest.approx(bootstrapfractioniter89param.expected_bootipf) + + +class BootstrapFractionNevinsParam(NamedTuple): + te0: Any = None + + ne0: Any = None + + alphan: Any = None + + betat: Any = None + + bt: Any = None + + dene: Any = None + + plascur: Any = None + + q0: Any = None + + q95: Any = None + + alphat: Any = None + + rmajor: Any = None + + rminor: Any = None + + ten: Any = None + + zeff: Any = None + + expected_fibs: Any = None + + +@pytest.mark.parametrize( + "bootstrapfractionnevinsparam", + ( + BootstrapFractionNevinsParam( + te0=24.402321098330372, + ne0=8.515060981068918e19, + alphan=1.0, + betat=0.03, + bt=5.7, + dene=18398455.678867526, + plascur=18398455.678867526, + q0=1, + q95=3.5, + alphat=1.45, + rmajor=8, + rminor=2.6666666666666665, + ten=12.626131115905864, + zeff=2.0909945616489103, + expected_fibs=889258771342.7881, + ), + ), +) +def test_bootstrap_fraction_nevins(bootstrapfractionnevinsparam, monkeypatch, physics): + """ + Automatically generated Regression Unit Test for bootstrap_fraction_nevins. + + This test was generated using data from tests/regression/scenarios/large-tokamak/IN.DAT. + + :param bootstrapfractionnevinsparam: the data used to mock and assert in this test. + :type bootstrapfractionnevinsparam: bootstrapfractionnevinsparam + + :param monkeypatch: pytest fixture used to mock module/class variables + :type monkeypatch: _pytest.monkeypatch.monkeypatch + """ + + monkeypatch.setattr(physics_variables, "te0", bootstrapfractionnevinsparam.te0) + + monkeypatch.setattr(physics_variables, "ne0", bootstrapfractionnevinsparam.ne0) + + fibs = physics.bootstrap_fraction_nevins( + alphan=bootstrapfractionnevinsparam.alphan, + alphat=bootstrapfractionnevinsparam.alphat, + betat=bootstrapfractionnevinsparam.betat, + bt=bootstrapfractionnevinsparam.bt, + dene=bootstrapfractionnevinsparam.dene, + plascur=bootstrapfractionnevinsparam.plascur, + q0=bootstrapfractionnevinsparam.q0, + q95=bootstrapfractionnevinsparam.q95, + rmajor=bootstrapfractionnevinsparam.rmajor, + rminor=bootstrapfractionnevinsparam.rminor, + ten=bootstrapfractionnevinsparam.ten, + zeff=bootstrapfractionnevinsparam.zeff, + ) + + assert fibs == pytest.approx(bootstrapfractionnevinsparam.expected_fibs) + + +class BootstrapFractionWilsonParam(NamedTuple): + alphaj: Any = None + + alphap: Any = None + + alphat: Any = None + + betpth: Any = None + + q0: Any = None + + qpsi: Any = None + + rmajor: Any = None + + rminor: Any = None + + expected_bfw: Any = None + + +@pytest.mark.parametrize( + "bootstrapfractionwilsonparam", + ( + BootstrapFractionWilsonParam( + alphaj=1.9008029008029004, + alphap=2.4500000000000002, + alphat=1.45, + betpth=1.0874279209664601, + q0=1, + qpsi=3.5, + rmajor=8, + rminor=2.6666666666666665, + expected_bfw=0.42321339288758714, + ), + BootstrapFractionWilsonParam( + alphaj=1.9008029008029004, + alphap=2.4500000000000002, + alphat=1.45, + betpth=0.99075943086768326, + q0=1, + qpsi=3.5, + rmajor=8, + rminor=2.6666666666666665, + expected_bfw=0.38559122143951252, + ), + ), +) +def test_bootstrap_fraction_wilson(bootstrapfractionwilsonparam, physics): + """ + Automatically generated Regression Unit Test for bootstrap_fraction_wilson. + + This test was generated using data from tests/regression/scenarios/large-tokamak/IN.DAT. + + :param bootstrapfractionwilsonparam: the data used to mock and assert in this test. + :type bootstrapfractionwilsonparam: bootstrapfractionwilsonparam + + :param monkeypatch: pytest fixture used to mock module/class variables + :type monkeypatch: _pytest.monkeypatch.monkeypatch + """ + + bfw = physics.bootstrap_fraction_wilson( + alphaj=bootstrapfractionwilsonparam.alphaj, + alphap=bootstrapfractionwilsonparam.alphap, + alphat=bootstrapfractionwilsonparam.alphat, + betpth=bootstrapfractionwilsonparam.betpth, + q0=bootstrapfractionwilsonparam.q0, + qpsi=bootstrapfractionwilsonparam.qpsi, + rmajor=bootstrapfractionwilsonparam.rmajor, + rminor=bootstrapfractionwilsonparam.rminor, + ) + + assert bfw == pytest.approx(bootstrapfractionwilsonparam.expected_bfw) + + +class BootstrapFractionSauterParam(NamedTuple): + dnitot: Any = None + + rminor: Any = None + + tesep: Any = None + + ti: Any = None + + triang: Any = None + + q0: Any = None + + afuel: Any = None + + zeff: Any = None + + rhopedn: Any = None + + bt: Any = None + + plascur: Any = None + + xarea: Any = None + + fhe3: Any = None + + teped: Any = None + + dene: Any = None + + te: Any = None + + rmajor: Any = None + + q: Any = None + + nesep: Any = None + + te0: Any = None + + neped: Any = None + + tbeta: Any = None + + ne0: Any = None + + alphan: Any = None + + rhopedt: Any = None + + alphat: Any = None + + expected_bfs: Any = None + + +@pytest.mark.parametrize( + "bootstrapfractionsauterparam", + ( + BootstrapFractionSauterParam( + dnitot=6.6125550702454276e19, + rminor=2.6666666666666665, + tesep=0.10000000000000001, + ti=12, + triang=0.5, + q0=1, + afuel=2.5, + zeff=2.0909945616489103, + rhopedn=0.94000000000000006, + bt=5.7000000000000002, + plascur=18398455.678867526, + xarea=38.39822223637151, + fhe3=0, + teped=5.5, + dene=7.5e19, + te=12, + rmajor=8, + q=3.5, + nesep=4.1177885154594193e19, + te0=24.402321098330372, + neped=7.000240476281013e19, + tbeta=2, + ne0=8.515060981068918e19, + alphan=1, + rhopedt=0.94000000000000006, + alphat=1.45, + expected_bfs=0.27635918746616817, + ), + ), +) +def test_bootstrap_fraction_sauter(bootstrapfractionsauterparam, monkeypatch, physics): + """ + Automatically generated Regression Unit Test for bootstrap_fraction_sauter. + + This test was generated using data from tests/regression/scenarios/large-tokamak/IN.DAT. + + :param bootstrapfractionsauterparam: the data used to mock and assert in this test. + :type bootstrapfractionsauterparam: bootstrapfractionsauterparam + + :param monkeypatch: pytest fixture used to mock module/class variables + :type monkeypatch: _pytest.monkeypatch.monkeypatch + """ + + monkeypatch.setattr( + physics_variables, "dnitot", bootstrapfractionsauterparam.dnitot + ) + + monkeypatch.setattr( + physics_variables, "rminor", bootstrapfractionsauterparam.rminor + ) + + monkeypatch.setattr(physics_variables, "tesep", bootstrapfractionsauterparam.tesep) + + monkeypatch.setattr(physics_variables, "ti", bootstrapfractionsauterparam.ti) + + monkeypatch.setattr( + physics_variables, "triang", bootstrapfractionsauterparam.triang + ) + + monkeypatch.setattr(physics_variables, "q0", bootstrapfractionsauterparam.q0) + + monkeypatch.setattr(physics_variables, "afuel", bootstrapfractionsauterparam.afuel) + + monkeypatch.setattr(physics_variables, "zeff", bootstrapfractionsauterparam.zeff) + + monkeypatch.setattr( + physics_variables, "rhopedn", bootstrapfractionsauterparam.rhopedn + ) + + monkeypatch.setattr(physics_variables, "bt", bootstrapfractionsauterparam.bt) + + monkeypatch.setattr( + physics_variables, "plascur", bootstrapfractionsauterparam.plascur + ) + + monkeypatch.setattr(physics_variables, "xarea", bootstrapfractionsauterparam.xarea) + + monkeypatch.setattr(physics_variables, "fhe3", bootstrapfractionsauterparam.fhe3) + + monkeypatch.setattr(physics_variables, "teped", bootstrapfractionsauterparam.teped) + + monkeypatch.setattr(physics_variables, "dene", bootstrapfractionsauterparam.dene) + + monkeypatch.setattr(physics_variables, "te", bootstrapfractionsauterparam.te) + + monkeypatch.setattr( + physics_variables, "rmajor", bootstrapfractionsauterparam.rmajor + ) + + monkeypatch.setattr(physics_variables, "q", bootstrapfractionsauterparam.q) + + monkeypatch.setattr(physics_variables, "nesep", bootstrapfractionsauterparam.nesep) + + monkeypatch.setattr(physics_variables, "te0", bootstrapfractionsauterparam.te0) + + monkeypatch.setattr(physics_variables, "neped", bootstrapfractionsauterparam.neped) + + monkeypatch.setattr(physics_variables, "tbeta", bootstrapfractionsauterparam.tbeta) + + monkeypatch.setattr(physics_variables, "ne0", bootstrapfractionsauterparam.ne0) + + monkeypatch.setattr( + physics_variables, "alphan", bootstrapfractionsauterparam.alphan + ) + + monkeypatch.setattr( + physics_variables, "rhopedt", bootstrapfractionsauterparam.rhopedt + ) + + monkeypatch.setattr( + physics_variables, "alphat", bootstrapfractionsauterparam.alphat + ) + + bfs = physics.bootstrap_fraction_sauter() + + assert bfs == pytest.approx(bootstrapfractionsauterparam.expected_bfs) + + +class CulcurParam(NamedTuple): + normalised_total_beta: Any = None + + beta: Any = None + + icurr: Any = None + + iprofile: Any = None + + alphaj: Any = None + + rli: Any = None + + alphap: Any = None + + bt: Any = None + + eps: Any = None + + kappa: Any = None + + kappa95: Any = None + + p0: Any = None + + pperim: Any = None + + q0: Any = None + + qpsi: Any = None + + rmajor: Any = None + + rminor: Any = None + + sf: Any = None + + triang: Any = None + + triang95: Any = None + + expected_normalised_total_beta: Any = None + + expected_alphaj: Any = None + + expected_rli: Any = None + + expected_bp: Any = None + + expected_qstar: Any = None + + expected_plascur: Any = None + + +@pytest.mark.parametrize( + "culcurparam", + ( + CulcurParam( + normalised_total_beta=0, + beta=0.030000000000000006, + icurr=4, + iprofile=1, + alphaj=1, + rli=0.90000000000000002, + alphap=0, + bt=5.7000000000000002, + eps=0.33333333333333331, + kappa=1.8500000000000001, + kappa95=1.6517857142857142, + p0=0, + pperim=24.081367139525412, + q0=1, + qpsi=3.5, + rmajor=8, + rminor=2.6666666666666665, + sf=1.4372507312498271, + triang=0.5, + triang95=0.33333333333333331, + expected_normalised_total_beta=2.4784688886891844, + expected_alphaj=1.9008029008029004, + expected_rli=1.2064840230894305, + expected_bp=0.96008591022564971, + expected_qstar=2.9008029008029004, + expected_plascur=18398455.678867526, + ), + CulcurParam( + normalised_total_beta=2.4784688886891844, + beta=0.030000000000000006, + icurr=4, + iprofile=1, + alphaj=1.9008029008029004, + rli=1.2064840230894305, + alphap=2.4500000000000002, + bt=5.7000000000000002, + eps=0.33333333333333331, + kappa=1.8500000000000001, + kappa95=1.6517857142857142, + p0=626431.90482713911, + pperim=24.081367139525412, + q0=1, + qpsi=3.5, + rmajor=8, + rminor=2.6666666666666665, + sf=1.4372507312498271, + triang=0.5, + triang95=0.33333333333333331, + expected_normalised_total_beta=2.4784688886891844, + expected_alphaj=1.9008029008029004, + expected_rli=1.2064840230894305, + expected_bp=0.96008591022564971, + expected_qstar=2.9008029008029004, + expected_plascur=18398455.678867526, + ), + ), +) +def test_culcur(culcurparam, monkeypatch, physics): + """ + Automatically generated Regression Unit Test for culcur. + + This test was generated using data from tests/regression/scenarios/large-tokamak/IN.DAT. + + :param culcurparam: the data used to mock and assert in this test. + :type culcurparam: culcurparam + + :param monkeypatch: pytest fixture used to mock module/class variables + :type monkeypatch: _pytest.monkeypatch.monkeypatch + """ + + monkeypatch.setattr( + physics_variables, "normalised_total_beta", culcurparam.normalised_total_beta + ) + + monkeypatch.setattr(physics_variables, "beta", culcurparam.beta) + + _, _, bp, qstar, plascur = physics.culcur( + icurr=culcurparam.icurr, + iprofile=culcurparam.iprofile, + alphaj=culcurparam.alphaj, + rli=culcurparam.rli, + alphap=culcurparam.alphap, + bt=culcurparam.bt, + eps=culcurparam.eps, + kappa=culcurparam.kappa, + kappa95=culcurparam.kappa95, + p0=culcurparam.p0, + pperim=culcurparam.pperim, + q0=culcurparam.q0, + qpsi=culcurparam.qpsi, + rmajor=culcurparam.rmajor, + rminor=culcurparam.rminor, + sf=culcurparam.sf, + triang=culcurparam.triang, + triang95=culcurparam.triang95, + ) + + assert physics_variables.normalised_total_beta == pytest.approx( + culcurparam.expected_normalised_total_beta + ) + + assert bp == pytest.approx(culcurparam.expected_bp) + + assert qstar == pytest.approx(culcurparam.expected_qstar) + + assert plascur == pytest.approx(culcurparam.expected_plascur) + + +@pytest.mark.parametrize( + ("arguments", "expected"), + ( + ( + { + "qbar": 2.5, + "aspect": 2.7, + "rminor": 1.5, + "bt": 12, + "kappa": 1.85, + "delta": 0.5, + }, + 37.43306888647351, + ), + ( + { + "qbar": 2.5, + "aspect": 3.0, + "rminor": 1.5, + "bt": 12, + "kappa": 1.85, + "delta": 0.5, + }, + 31.893383344142052, + ), + ), +) +def test_plasc(arguments, expected, physics): + assert physics.plasc(**arguments) == pytest.approx(expected) + + +@pytest.mark.parametrize( + ("arguments", "expected"), + ( + ( + { + "icurr": 2, + "ip": 1.6e7, + "qbar": 2.5, + "aspect": 2.7, + "bt": 12, + "kappa": 1.85, + "delta": 0.5, + "perim": 24, + }, + 3.4726549397470703, + ), + ( + { + "icurr": 2, + "ip": 1.6e7, + "qbar": 2.5, + "aspect": 3.0, + "bt": 12, + "kappa": 1.85, + "delta": 0.5, + "perim": 24, + }, + 2.958739919272374, + ), + ( + { + "icurr": 3, + "ip": 1.6e7, + "qbar": 2.5, + "aspect": 3.0, + "bt": 12, + "kappa": 1.85, + "delta": 0.5, + "perim": 24, + }, + 0.8377580413333333, + ), + ), +) +def test_bpol(arguments, expected, physics): + assert physics.bpol(**arguments) == pytest.approx(expected) + + +def test_culblm(physics): + assert physics.culblm(12, 4.879, 18300000, 2.5) == pytest.approx(0.0297619) + + +def test_conhas(physics): + assert physics.conhas(5, 5, 12, 0.5, 0.33, 1.85, 2e3) == pytest.approx( + 2.518876726889116 + ) + + +class PlasmaCompositionParam(NamedTuple): + ftritbm: Any = None + + impurity_arr_frac: Any = None + + impurity_arr_z: Any = None + + impurity_arr_amass: Any = None + + alphat: Any = None + + ignite: Any = None + + falpe: Any = None + + afuel: Any = None + + ftrit: Any = None + + deni: Any = None + + aion: Any = None + + dnitot: Any = None + + protium: Any = None + + zeffai: Any = None + + rncne: Any = None + + rnone: Any = None + + falpi: Any = None + + ralpne: Any = None + + dlamee: Any = None + + rnbeam: Any = None + + zeff: Any = None + + dnz: Any = None + + pcoef: Any = None + + alpharate: Any = None + + rnfene: Any = None + + abeam: Any = None + + dlamie: Any = None + + te: Any = None + + protonrate: Any = None + + fdeut: Any = None + + alphan: Any = None + + dnbeam: Any = None + + fhe3: Any = None + + dnalp: Any = None + + dene: Any = None + + dnprot: Any = None + + iscz: Any = None + + err242: Any = None + + err243: Any = None + + ptarmw: Any = None + + lambdaio: Any = None + + drsep: Any = None + + fio: Any = None + + rho_star: Any = None + + nu_star: Any = None + + beta_mcdonald: Any = None + + itart_r: Any = None + + first_call: Any = None + + expected_impurity_arr_frac: Any = None + + expected_falpe: Any = None + + expected_afuel: Any = None + + expected_deni: Any = None + + expected_aion: Any = None + + expected_dnitot: Any = None + + expected_zeffai: Any = None + + expected_falpi: Any = None + + expected_dlamee: Any = None + + expected_zeff: Any = None + + expected_dnz: Any = None + + expected_abeam: Any = None + + expected_dlamie: Any = None + + expected_dnalp: Any = None + + expected_dnprot: Any = None + + expected_first_call: Any = None + + +@pytest.mark.parametrize( + "plasmacompositionparam", + ( + PlasmaCompositionParam( + ftritbm=9.9999999999999995e-07, + impurity_arr_frac=[ + 0.90000000000000002, + 0.10000000000000001, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0.00038000000000000008, + 5.0000000000000021e-06, + ], + impurity_arr_z=[1, 2, 4, 6, 7, 8, 10, 14, 18, 26, 28, 36, 54, 74], + impurity_arr_amass=[ + 1.01, + 4.0030000000000001, + 9.0099999999999998, + 12.01, + 14.01, + 15.999000000000001, + 20.18, + 28.09, + 39.950000000000003, + 55.850000000000001, + 58.700000000000003, + 83.799999999999997, + 131.30000000000001, + 183.84999999999999, + ], + alphat=1.45, + ignite=0, + falpe=0, + afuel=0, + ftrit=0.5, + deni=0, + aion=0, + dnitot=0, + protium=0, + zeffai=0, + rncne=0, + rnone=0, + falpi=0, + ralpne=0.10000000000000001, + dlamee=0, + rnbeam=0, + zeff=0, + dnz=0, + pcoef=0, + alpharate=0, + rnfene=0, + abeam=0, + dlamie=0, + te=12, + protonrate=0, + fdeut=0.5, + alphan=1, + dnbeam=0, + fhe3=0, + dnalp=0, + dene=7.5e19, + dnprot=0, + iscz=0, + err242=0, + err243=0, + ptarmw=0, + lambdaio=0, + drsep=0, + fio=0, + rho_star=0, + nu_star=0, + beta_mcdonald=0, + itart_r=0, + first_call=1, + expected_impurity_arr_frac=[ + 0.78128900936605694, + 0.10000000000000001, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0.00038000000000000008, + 5.0000000000000021e-06, + ], + expected_falpe=0.6845930883190634, + expected_afuel=2.5, + expected_deni=5.8589175702454272e19, + expected_aion=2.7265017998473029, + expected_dnitot=6.6125550702454276e19, + expected_zeffai=0.43248858851447464, + expected_falpi=0.3154069116809366, + expected_dlamee=17.510652035055571, + expected_zeff=2.0909945616489103, + expected_dnz=28875000000000004, + expected_abeam=2.0000010000000001, + expected_dlamie=17.810652035055568, + expected_dnalp=7.5e18, + expected_dnprot=7500000000000000, + expected_first_call=0, + ), + PlasmaCompositionParam( + ftritbm=9.9999999999999995e-07, + impurity_arr_frac=( + 0.78128900936605694, + 0.10000000000000001, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0.00038000000000000008, + 5.0000000000000021e-06, + ), + impurity_arr_z=numpy.array( + numpy.array( + (1, 2, 4, 6, 7, 8, 10, 14, 18, 26, 28, 36, 54, 74), order="F" + ), + order="F", + ).transpose(), + impurity_arr_amass=numpy.array( + numpy.array( + ( + 1.01, + 4.0030000000000001, + 9.0099999999999998, + 12.01, + 14.01, + 15.999000000000001, + 20.18, + 28.09, + 39.950000000000003, + 55.850000000000001, + 58.700000000000003, + 83.799999999999997, + 131.30000000000001, + 183.84999999999999, + ), + order="F", + ), + order="F", + ).transpose(), + alphat=1.45, + ignite=0, + falpe=0.6845930883190634, + afuel=2.5, + ftrit=0.5, + deni=5.8589175702454272e19, + aion=2.7265017998473029, + dnitot=6.6125550702454276e19, + protium=0, + zeffai=0.43248858851447464, + rncne=0, + rnone=0, + falpi=0.3154069116809366, + ralpne=0.10000000000000001, + dlamee=17.510652035055571, + rnbeam=0, + zeff=2.0909945616489103, + dnz=28875000000000004, + pcoef=1.0521775929921553, + alpharate=1.973996644759543e17, + rnfene=0, + abeam=2.0000010000000001, + dlamie=17.810652035055568, + te=12, + protonrate=540072280299564.38, + fdeut=0.5, + alphan=1, + dnbeam=0, + fhe3=0, + dnalp=7.5e18, + dene=7.5e19, + dnprot=7500000000000000, + iscz=0, + err242=0, + err243=0, + ptarmw=33.990985729118783, + lambdaio=0.00157, + drsep=-0.014999999999999999, + fio=0.40999999999999998, + rho_star=0, + nu_star=0, + beta_mcdonald=0, + itart_r=0, + first_call=0, + expected_impurity_arr_frac=( + 0.78128900936605694, + 0.10000000000000001, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0.00038000000000000008, + 5.0000000000000021e-06, + ), + expected_falpe=0.73096121787894142, + expected_afuel=2.5, + expected_deni=5.8576156204039725e19, + expected_aion=2.7262064639685937, + expected_dnitot=6.6125550702454276e19, + expected_zeffai=0.43258985127992111, + expected_falpi=0.26903878212105858, + expected_dlamee=17.510652035055571, + expected_zeff=2.0909945616489103, + expected_dnz=28875000000000004, + expected_abeam=2.0000010000000001, + expected_dlamie=17.810652035055568, + expected_dnalp=7.5e18, + expected_dnprot=20519498414548412, + expected_first_call=0, + ), + ), +) +def test_plasma_composition(plasmacompositionparam, monkeypatch, physics): + """ + Automatically generated Regression Unit Test for plasma_composition. + + This test was generated using data from tests/regression/scenarios/large-tokamak/IN.DAT. + + :param plasmacompositionparam: the data used to mock and assert in this test. + :type plasmacompositionparam: plasmacompositionparam + + :param monkeypatch: pytest fixture used to mock module/class variables + :type monkeypatch: _pytest.monkeypatch.monkeypatch + """ + impurity_radiation_module.init_impurity_radiation_module() + initialise_imprad() + + monkeypatch.setattr( + current_drive_variables, "ftritbm", plasmacompositionparam.ftritbm + ) + + monkeypatch.setattr( + impurity_radiation_module, + "impurity_arr_frac", + plasmacompositionparam.impurity_arr_frac, + ) + + monkeypatch.setattr( + impurity_radiation_module, + "impurity_arr_z", + plasmacompositionparam.impurity_arr_z, + ) + + monkeypatch.setattr( + impurity_radiation_module, + "impurity_arr_amass", + plasmacompositionparam.impurity_arr_amass, + ) + + monkeypatch.setattr(physics_variables, "alphat", plasmacompositionparam.alphat) + + monkeypatch.setattr(physics_variables, "ignite", plasmacompositionparam.ignite) + + monkeypatch.setattr(physics_variables, "falpe", plasmacompositionparam.falpe) + + monkeypatch.setattr(physics_variables, "afuel", plasmacompositionparam.afuel) + + monkeypatch.setattr(physics_variables, "ftrit", plasmacompositionparam.ftrit) + + monkeypatch.setattr(physics_variables, "deni", plasmacompositionparam.deni) + + monkeypatch.setattr(physics_variables, "aion", plasmacompositionparam.aion) + + monkeypatch.setattr(physics_variables, "dnitot", plasmacompositionparam.dnitot) + + monkeypatch.setattr(physics_variables, "protium", plasmacompositionparam.protium) + + monkeypatch.setattr(physics_variables, "zeffai", plasmacompositionparam.zeffai) + + monkeypatch.setattr(physics_variables, "rncne", plasmacompositionparam.rncne) + + monkeypatch.setattr(physics_variables, "rnone", plasmacompositionparam.rnone) + + monkeypatch.setattr(physics_variables, "falpi", plasmacompositionparam.falpi) + + monkeypatch.setattr(physics_variables, "ralpne", plasmacompositionparam.ralpne) + + monkeypatch.setattr(physics_variables, "dlamee", plasmacompositionparam.dlamee) + + monkeypatch.setattr(physics_variables, "rnbeam", plasmacompositionparam.rnbeam) + + monkeypatch.setattr(physics_variables, "zeff", plasmacompositionparam.zeff) + + monkeypatch.setattr(physics_variables, "dnz", plasmacompositionparam.dnz) + + monkeypatch.setattr(physics_variables, "pcoef", plasmacompositionparam.pcoef) + + monkeypatch.setattr( + physics_variables, "alpharate", plasmacompositionparam.alpharate + ) + + monkeypatch.setattr(physics_variables, "rnfene", plasmacompositionparam.rnfene) + + monkeypatch.setattr(physics_variables, "abeam", plasmacompositionparam.abeam) + + monkeypatch.setattr(physics_variables, "dlamie", plasmacompositionparam.dlamie) + + monkeypatch.setattr(physics_variables, "te", plasmacompositionparam.te) + + monkeypatch.setattr( + physics_variables, "protonrate", plasmacompositionparam.protonrate + ) + + monkeypatch.setattr(physics_variables, "fdeut", plasmacompositionparam.fdeut) + + monkeypatch.setattr(physics_variables, "alphan", plasmacompositionparam.alphan) + + monkeypatch.setattr(physics_variables, "dnbeam", plasmacompositionparam.dnbeam) + + monkeypatch.setattr(physics_variables, "fhe3", plasmacompositionparam.fhe3) + + monkeypatch.setattr(physics_variables, "dnalp", plasmacompositionparam.dnalp) + + monkeypatch.setattr(physics_variables, "dene", plasmacompositionparam.dene) + + monkeypatch.setattr(physics_variables, "dnprot", plasmacompositionparam.dnprot) + + monkeypatch.setattr(physics_module, "iscz", plasmacompositionparam.iscz) + + monkeypatch.setattr(physics_module, "err242", plasmacompositionparam.err242) + + monkeypatch.setattr(physics_module, "err243", plasmacompositionparam.err243) + + monkeypatch.setattr(physics_module, "ptarmw", plasmacompositionparam.ptarmw) + + monkeypatch.setattr(physics_module, "lambdaio", plasmacompositionparam.lambdaio) + + monkeypatch.setattr(physics_module, "drsep", plasmacompositionparam.drsep) + + monkeypatch.setattr(physics_module, "fio", plasmacompositionparam.fio) + + monkeypatch.setattr(physics_module, "rho_star", plasmacompositionparam.rho_star) + + monkeypatch.setattr(physics_module, "nu_star", plasmacompositionparam.nu_star) + + monkeypatch.setattr( + physics_module, "beta_mcdonald", plasmacompositionparam.beta_mcdonald + ) + + monkeypatch.setattr(physics_module, "itart_r", plasmacompositionparam.itart_r) + + monkeypatch.setattr(physics_module, "first_call", plasmacompositionparam.first_call) + + physics.plasma_composition() + + assert impurity_radiation_module.impurity_arr_frac == pytest.approx( + plasmacompositionparam.expected_impurity_arr_frac + ) + + assert physics_variables.falpe == pytest.approx( + plasmacompositionparam.expected_falpe + ) + + assert physics_variables.afuel == pytest.approx( + plasmacompositionparam.expected_afuel + ) + + assert physics_variables.deni == pytest.approx(plasmacompositionparam.expected_deni) + + assert physics_variables.aion == pytest.approx(plasmacompositionparam.expected_aion) + + assert physics_variables.dnitot == pytest.approx( + plasmacompositionparam.expected_dnitot + ) + + assert physics_variables.zeffai == pytest.approx( + plasmacompositionparam.expected_zeffai + ) + + assert physics_variables.falpi == pytest.approx( + plasmacompositionparam.expected_falpi + ) + + assert physics_variables.dlamee == pytest.approx( + plasmacompositionparam.expected_dlamee + ) + + assert physics_variables.zeff == pytest.approx(plasmacompositionparam.expected_zeff) + + assert physics_variables.dnz == pytest.approx(plasmacompositionparam.expected_dnz) + + assert physics_variables.abeam == pytest.approx( + plasmacompositionparam.expected_abeam + ) + + assert physics_variables.dlamie == pytest.approx( + plasmacompositionparam.expected_dlamie + ) + + assert physics_variables.dnalp == pytest.approx( + plasmacompositionparam.expected_dnalp + ) + + assert physics_variables.dnprot == pytest.approx( + plasmacompositionparam.expected_dnprot + ) + + assert physics_module.first_call == pytest.approx( + plasmacompositionparam.expected_first_call + ) + + +class VscalcParam(NamedTuple): + csawth: Any = None + + eps: Any = None + + facoh: Any = None + + gamma: Any = None + + kappa: Any = None + + plascur: Any = None + + rli: Any = None + + rmajor: Any = None + + rplas: Any = None + + tburn: Any = None + + theat: Any = None + + expected_phiint: Any = None + + expected_rlp: Any = None + + expected_vsbrn: Any = None + + expected_vsind: Any = None + + expected_vsres: Any = None + + expected_vsstt: Any = None + + +@pytest.mark.parametrize( + "vscalcparam", + ( + VscalcParam( + csawth=1, + eps=0.33333333333333331, + facoh=0.59999999999999998, + gamma=0.30000000000000004, + kappa=1.8500000000000001, + plascur=18398455.678867526, + rli=1.2064840230894305, + rmajor=8, + rplas=3.7767895536275952e-09, + tburn=1000, + theat=10, + expected_phiint=111.57651734747576, + expected_rlp=1.4075705307248088e-05, + expected_vsbrn=42.109179697761263, + expected_vsind=258.97124024420435, + expected_vsres=55.488435095110333, + expected_vsstt=356.56885503707593, + ), + VscalcParam( + csawth=1, + eps=0.33333333333333331, + facoh=0.59999999999999998, + gamma=0.30000000000000004, + kappa=1.8500000000000001, + plascur=18398455.678867526, + rli=1.2064840230894305, + rmajor=8, + rplas=3.7767895536275952e-09, + tburn=0, + theat=10, + expected_phiint=111.57651734747576, + expected_rlp=1.4075705307248088e-05, + expected_vsbrn=0.41692257126496302, + expected_vsind=258.97124024420435, + expected_vsres=55.488435095110333, + expected_vsstt=314.87659791057968, + ), + ), +) +def test_vscalc(vscalcparam, physics): + """ + Automatically generated Regression Unit Test for vscalc. + + This test was generated using data from tests/regression/scenarios/large-tokamak/IN.DAT. + + :param vscalcparam: the data used to mock and assert in this test. + :type vscalcparam: vscalcparam + """ + + phiint, rlp, vsbrn, vsind, vsres, vsstt = physics.vscalc( + csawth=vscalcparam.csawth, + eps=vscalcparam.eps, + facoh=vscalcparam.facoh, + gamma=vscalcparam.gamma, + kappa=vscalcparam.kappa, + plascur=vscalcparam.plascur, + rli=vscalcparam.rli, + rmajor=vscalcparam.rmajor, + rplas=vscalcparam.rplas, + tburn=vscalcparam.tburn, + theat=vscalcparam.theat, + ) + + assert phiint == pytest.approx(vscalcparam.expected_phiint) + + assert rlp == pytest.approx(vscalcparam.expected_rlp) + + assert vsbrn == pytest.approx(vscalcparam.expected_vsbrn) + + assert vsind == pytest.approx(vscalcparam.expected_vsind) + + assert vsres == pytest.approx(vscalcparam.expected_vsres) + + assert vsstt == pytest.approx(vscalcparam.expected_vsstt) + + +class PhyauxParam(NamedTuple): + tauratio: Any = None + + burnup_in: Any = None + + aspect: Any = None + + dene: Any = None + + deni: Any = None + + dnalp: Any = None + + fusionrate: Any = None + + alpharate: Any = None + + plascur: Any = None + + sbar: Any = None + + taueff: Any = None + + vol: Any = None + + expected_burnup: Any = None + + expected_dntau: Any = None + + expected_figmer: Any = None + + expected_fusrat: Any = None + + expected_qfuel: Any = None + + expected_rndfuel: Any = None + + expected_taup: Any = None + + +@pytest.mark.parametrize( + "phyauxparam", + ( + PhyauxParam( + tauratio=1, + burnup_in=0, + aspect=3, + dene=7.5e19, + deni=5.8589175702454272e19, + dnalp=7.5e18, + fusionrate=1.9852091609123786e17, + alpharate=1.973996644759543e17, + plascur=18398455.678867526, + sbar=1, + taueff=3.401323521525641, + vol=1888.1711539956691, + expected_burnup=0.20383432558954095, + expected_dntau=2.5509926411442307e20, + expected_figmer=55.195367036602576, + expected_fusrat=3.7484146722826997e20, + expected_qfuel=1.8389516394951276e21, + expected_rndfuel=3.7484146722826997e20, + expected_taup=37.993985551650177, + ), + PhyauxParam( + tauratio=1, + burnup_in=0, + aspect=3, + dene=7.5e19, + deni=5.8576156204039725e19, + dnalp=7.5e18, + fusionrate=1.9843269653375773e17, + alpharate=1.9731194318497056e17, + plascur=18398455.678867526, + sbar=1, + taueff=3.402116961408892, + vol=1888.1711539956691, + expected_burnup=0.20387039462081086, + expected_dntau=2.5515877210566689e20, + expected_figmer=55.195367036602576, + expected_fusrat=3.7467489360461772e20, + expected_qfuel=1.8378092331723546e21, + expected_rndfuel=3.7467489360461772e20, + expected_taup=38.010876984618747, + ), + ), +) +def test_phyaux(phyauxparam, monkeypatch, physics): + """ + Automatically generated Regression Unit Test for phyaux. + + This test was generated using data from tests/regression/scenarios/large-tokamak/IN.DAT. + + :param phyauxparam: the data used to mock and assert in this test. + :type phyauxparam: phyauxparam + + :param monkeypatch: pytest fixture used to mock module/class variables + :type monkeypatch: _pytest.monkeypatch.monkeypatch + """ + + monkeypatch.setattr(physics_variables, "tauratio", phyauxparam.tauratio) + + monkeypatch.setattr(physics_variables, "burnup_in", phyauxparam.burnup_in) + + burnup, dntau, figmer, fusrat, qfuel, rndfuel, taup = physics.phyaux( + aspect=phyauxparam.aspect, + dene=phyauxparam.dene, + deni=phyauxparam.deni, + dnalp=phyauxparam.dnalp, + fusionrate=phyauxparam.fusionrate, + alpharate=phyauxparam.alpharate, + plascur=phyauxparam.plascur, + sbar=phyauxparam.sbar, + taueff=phyauxparam.taueff, + vol=phyauxparam.vol, + ) + + assert burnup == pytest.approx(phyauxparam.expected_burnup) + + assert dntau == pytest.approx(phyauxparam.expected_dntau) + + assert figmer == pytest.approx(phyauxparam.expected_figmer) + + assert fusrat == pytest.approx(phyauxparam.expected_fusrat) + + assert qfuel == pytest.approx(phyauxparam.expected_qfuel) + + assert rndfuel == pytest.approx(phyauxparam.expected_rndfuel) + + assert taup == pytest.approx(phyauxparam.expected_taup) + + +def test_rether(physics): + assert physics.rether( + 1.0, 1.45, 7.5e19, 17.81065204, 12.0, 13.0, 0.43258985 + ) == pytest.approx(0.028360489673597476) + + +class PohmParam(NamedTuple): + aspect: Any = None + + plasma_res_factor: Any = None + + facoh: Any = None + + kappa95: Any = None + + plascur: Any = None + + rmajor: Any = None + + rminor: Any = None + + ten: Any = None + + vol: Any = None + + zeff: Any = None + + expected_pohmpv: Any = None + + expected_pohmmw: Any = None + + expected_rpfac: Any = None + + expected_rplas: Any = None + + +@pytest.mark.parametrize( + "pohmparam", + ( + PohmParam( + aspect=3, + plasma_res_factor=0.70000000000000007, + facoh=0.59999999999999998, + kappa95=1.6517857142857142, + plascur=18398455.678867526, + rmajor=8, + rminor=2.6666666666666665, + ten=12.626131115905864, + vol=1888.1711539956691, + zeff=2.0909945616489103, + expected_pohmpv=0.0004062519138005805, + expected_pohmmw=0.7670731448937912, + expected_rpfac=2.5, + expected_rplas=3.7767895536275952e-09, + ), + ), +) +def test_pohm(pohmparam, monkeypatch, physics): + """ + Automatically generated Regression Unit Test for pohm. + + This test was generated using data from tests/regression/scenarios/large-tokamak/IN.DAT. + + :param pohmparam: the data used to mock and assert in this test. + :type pohmparam: pohmparam + + :param monkeypatch: pytest fixture used to mock module/class variables + :type monkeypatch: _pytest.monkeypatch.monkeypatch + """ + + monkeypatch.setattr(physics_variables, "aspect", pohmparam.aspect) + + monkeypatch.setattr( + physics_variables, "plasma_res_factor", pohmparam.plasma_res_factor + ) + + pohmpv, pohmmw, rpfac, rplas = physics.pohm( + facoh=pohmparam.facoh, + kappa95=pohmparam.kappa95, + plascur=pohmparam.plascur, + rmajor=pohmparam.rmajor, + rminor=pohmparam.rminor, + ten=pohmparam.ten, + vol=pohmparam.vol, + zeff=pohmparam.zeff, + ) + + assert pohmpv == pytest.approx(pohmparam.expected_pohmpv) + + assert pohmmw == pytest.approx(pohmparam.expected_pohmmw) + + assert rpfac == pytest.approx(pohmparam.expected_rpfac) + + assert rplas == pytest.approx(pohmparam.expected_rplas) + + +class CuldlmParam(NamedTuple): + idensl: Any = None + + bt: Any = None + + pdivt: Any = None + + plascur: Any = None + + prn1: Any = None + + q95: Any = None + + qcyl: Any = None + + rmajor: Any = None + + rminor: Any = None + + sarea: Any = None + + zeff: Any = None + + expected_dnelimt: Any = None + + expected_dlimit: Any = None + + +@pytest.mark.parametrize( + "culdlmparam", + ( + CuldlmParam( + idensl=7, + bt=5.7000000000000002, + pdivt=169.86588182297265, + plascur=18398455.678867526, + prn1=0.54903846872792261, + q95=3.5, + qcyl=2.9008029008029004, + rmajor=8, + rminor=2.6666666666666665, + sarea=1173.8427771245592, + zeff=2.0909945616489103, + expected_dnelimt=8.2355770309188387e19, + expected_dlimit=( + 4.6776897596806603e19, + 9.6979327595095458e19, + 3.8452719591725253e19, + 3.0917086651329429e21, + 4.0085150551984223e20, + 7.3686495535714296e19, + 8.2355770309188387e19, + ), + ), + ), +) +def test_culdlm(culdlmparam, physics): + """ + Automatically generated Regression Unit Test for culdlm. + + This test was generated using data from tests/regression/scenarios/large-tokamak/IN.DAT. + + :param culdlmparam: the data used to mock and assert in this test. + :type culdlmparam: culdlmparam + + :param monkeypatch: pytest fixture used to mock module/class variables + :type monkeypatch: _pytest.monkeypatch.monkeypatch + """ + + dlimit, dnelimt = physics.culdlm( + idensl=culdlmparam.idensl, + bt=culdlmparam.bt, + pdivt=culdlmparam.pdivt, + plascur=culdlmparam.plascur, + prn1=culdlmparam.prn1, + q95=culdlmparam.q95, + qcyl=culdlmparam.qcyl, + rmajor=culdlmparam.rmajor, + rminor=culdlmparam.rminor, + sarea=culdlmparam.sarea, + zeff=culdlmparam.zeff, + ) + + assert dnelimt == pytest.approx(culdlmparam.expected_dnelimt) + + assert dlimit == pytest.approx(culdlmparam.expected_dlimit) + + +class PcondParam(NamedTuple): + iradloss: Any = None + + tauee_in: Any = None + + pradpv: Any = None + + kappaa_ipb: Any = None + + pohmmw: Any = None + + falpha: Any = None + + ptaue: Any = None + + gtaue: Any = None + + ftaue: Any = None + + rtaue: Any = None + + qtaue: Any = None + + iinvqd: Any = None + + isc: Any = None + + ignite: Any = None + + afuel: Any = None + + palpmw: Any = None + + aspect: Any = None + + bt: Any = None + + dene: Any = None + + dnitot: Any = None + + dnla: Any = None + + eps: Any = None + + hfact: Any = None + + kappa: Any = None + + kappa95: Any = None + + pchargemw: Any = None + + pinjmw: Any = None + + plascur: Any = None + + pcoreradpv: Any = None + + q: Any = None + + qstar: Any = None + + rmajor: Any = None + + rminor: Any = None + + te: Any = None + + ten: Any = None + + tin: Any = None + + vol: Any = None + + xarea: Any = None + + zeff: Any = None + + expected_kappaa_ipb: Any = None + + expected_ptaue: Any = None + + expected_ftaue: Any = None + + expected_rtaue: Any = None + + expected_kappaa: Any = None + + expected_powerht: Any = None + + expected_ptrepv: Any = None + + expected_ptripv: Any = None + + expected_tauee: Any = None + + expected_taueff: Any = None + + expected_tauei: Any = None + + +@pytest.mark.parametrize( + "pcondparam", + ( + PcondParam( + iradloss=1, + tauee_in=0, + pradpv=0.11824275660100725, + kappaa_ipb=1.68145080681586, + pohmmw=0.63634001890069991, + falpha=0.94999999999999996, + ptaue=0.40999999999999998, + gtaue=0, + ftaue=1645.9881192671726, + rtaue=-0.63, + qtaue=0, + iinvqd=1, + isc=32, + ignite=0, + afuel=2.5, + palpmw=319.03020327154269, + aspect=3, + bt=5.2375830857646202, + dene=8.0593948787884524e19, + dnitot=7.1529510234203251e19, + dnla=8.925359201116491e19, + eps=0.33333333333333331, + hfact=6.1946504123280199, + kappa=1.8500000000000001, + kappa95=1.6517857142857142, + pchargemw=1.2453296074483358, + pinjmw=75.397788712812741, + plascur=16616203.759182997, + pcoreradpv=0.047757569353246924, + q=3.5610139569387185, + qstar=2.9513713188821282, + rmajor=8, + rminor=2.6666666666666665, + te=12.437097421317889, + ten=13.745148298980761, + tin=13.745148298980761, + vol=1888.1711539956691, + xarea=38.39822223637151, + zeff=2.4987360098030775, + expected_kappaa_ipb=1.68145080681586, + expected_ptaue=0.40999999999999998, + expected_ftaue=823.65887428773408, + expected_rtaue=-0.63, + expected_kappaa=1.7187938085542791, + expected_ptrepv=0.012570664670798823, + expected_ptripv=0.011156836223364355, + expected_tauee=21.17616899712392, + expected_tauei=21.17616899712392, + expected_taueff=21.17616899712392, + expected_powerht=290.18368660937881, + ), + PcondParam( + iradloss=1, + tauee_in=0, + pradpv=0.11824275660100725, + kappaa_ipb=1.68145080681586, + pohmmw=0.63634001890069991, + falpha=0.94999999999999996, + ptaue=0.44, + gtaue=0, + ftaue=146.42448015009589, + rtaue=-0.65000000000000002, + qtaue=0, + iinvqd=1, + isc=33, + ignite=0, + afuel=2.5, + palpmw=319.03020327154269, + aspect=3, + bt=5.2375830857646202, + dene=8.0593948787884524e19, + dnitot=7.1529510234203251e19, + dnla=8.925359201116491e19, + eps=0.33333333333333331, + hfact=0.96163409847948844, + kappa=1.8500000000000001, + kappa95=1.6517857142857142, + pchargemw=1.2453296074483358, + pinjmw=75.397788712812741, + plascur=16616203.759182997, + pcoreradpv=0.047757569353246924, + q=3.5610139569387185, + qstar=2.9513713188821282, + rmajor=8, + rminor=2.6666666666666665, + te=12.437097421317889, + ten=13.745148298980761, + tin=13.745148298980761, + vol=1888.1711539956691, + xarea=38.39822223637151, + zeff=2.4987360098030775, + expected_kappaa_ipb=1.68145080681586, + expected_ptaue=0.44, + expected_ftaue=143.29591882802001, + expected_rtaue=-0.65000000000000002, + expected_kappaa=1.7187938085542791, + expected_ptrepv=0.081458458765440875, + expected_ptripv=0.072296788376262536, + expected_tauee=3.2679051814806361, + expected_tauei=3.2679051814806361, + expected_taueff=3.2679051814806366, + expected_powerht=290.18368660937881, + ), + PcondParam( + iradloss=1, + tauee_in=0, + pradpv=0.11824275660100725, + kappaa_ipb=1.68145080681586, + pohmmw=0.63634001890069991, + falpha=0.94999999999999996, + ptaue=0.40999999999999998, + gtaue=0, + ftaue=176.74003304700352, + rtaue=-0.68999999999999995, + qtaue=0, + iinvqd=1, + isc=34, + ignite=0, + afuel=2.5, + palpmw=319.03020327154269, + aspect=3, + bt=5.2375830857646202, + dene=8.0593948787884524e19, + dnitot=7.1529510234203251e19, + dnla=8.925359201116491e19, + eps=0.33333333333333331, + hfact=1.1960655150953154, + kappa=1.8500000000000001, + kappa95=1.6517857142857142, + pchargemw=1.2453296074483358, + pinjmw=75.397788712812741, + plascur=16616203.759182997, + pcoreradpv=0.047757569353246924, + q=3.5610139569387185, + qstar=2.9513713188821282, + rmajor=8, + rminor=2.6666666666666665, + te=12.437097421317889, + ten=13.745148298980761, + tin=13.745148298980761, + vol=1888.1711539956691, + xarea=38.39822223637151, + zeff=2.4987360098030775, + expected_kappaa_ipb=1.68145080681586, + expected_ptaue=0.40999999999999998, + expected_ftaue=178.90696306034835, + expected_rtaue=-0.68999999999999995, + expected_kappaa=1.7187938085542791, + expected_ptrepv=0.081327750398391824, + expected_ptripv=0.072180780839479111, + expected_tauee=3.2731572946627923, + expected_tauei=3.2731572946627923, + expected_taueff=3.2731572946627923, + expected_powerht=290.18368660937881, + ), + PcondParam( + iradloss=1, + tauee_in=0, + pradpv=0.11824275660100725, + kappaa_ipb=1.68145080681586, + pohmmw=0.63634001890069991, + falpha=0.94999999999999996, + ptaue=0.40000000000000002, + gtaue=0, + ftaue=238.88549012959402, + rtaue=-0.68999999999999995, + qtaue=0, + iinvqd=1, + isc=35, + ignite=0, + afuel=2.5, + palpmw=319.03020327154269, + aspect=3, + bt=5.2375830857646202, + dene=8.0593948787884524e19, + dnitot=7.1529510234203251e19, + dnla=8.925359201116491e19, + eps=0.33333333333333331, + hfact=0.78453691772934719, + kappa=1.8500000000000001, + kappa95=1.6517857142857142, + pchargemw=1.2453296074483358, + pinjmw=75.397788712812741, + plascur=16616203.759182997, + pcoreradpv=0.047757569353246924, + q=3.5610139569387185, + qstar=2.9513713188821282, + rmajor=8, + rminor=2.6666666666666665, + te=12.437097421317889, + ten=13.745148298980761, + tin=13.745148298980761, + vol=1888.1711539956691, + xarea=38.39822223637151, + zeff=2.4987360098030775, + expected_kappaa_ipb=1.68145080681586, + expected_ptaue=0.40000000000000002, + expected_ftaue=120.20885852490557, + expected_rtaue=-0.68999999999999995, + expected_kappaa=1.7187938085542791, + expected_ptrepv=0.12077931279593926, + expected_ptripv=0.10719520783694242, + expected_tauee=2.2040075681235445, + expected_tauei=2.2040075681235445, + expected_taueff=2.2040075681235445, + expected_powerht=290.18368660937881, + ), + PcondParam( + iradloss=1, + tauee_in=0, + pradpv=0.11824275660100725, + kappaa_ipb=1.68145080681586, + pohmmw=0.63634001890069991, + falpha=0.94999999999999996, + ptaue=0.39000000000000001, + gtaue=0, + ftaue=185.98072240082502, + rtaue=-0.69999999999999996, + qtaue=0, + iinvqd=1, + isc=36, + ignite=0, + afuel=2.5, + palpmw=319.03020327154269, + aspect=3, + bt=5.2375830857646202, + dene=8.0593948787884524e19, + dnitot=7.1529510234203251e19, + dnla=8.925359201116491e19, + eps=0.33333333333333331, + hfact=1.1619079679077555, + kappa=1.8500000000000001, + kappa95=1.6517857142857142, + pchargemw=1.2453296074483358, + pinjmw=75.397788712812741, + plascur=16616203.759182997, + pcoreradpv=0.047757569353246924, + q=3.5610139569387185, + qstar=2.9513713188821282, + rmajor=8, + rminor=2.6666666666666665, + te=12.437097421317889, + ten=13.745148298980761, + tin=13.745148298980761, + vol=1888.1711539956691, + xarea=38.39822223637151, + zeff=2.4987360098030775, + expected_kappaa_ipb=1.68145080681586, + expected_ptaue=0.39000000000000001, + expected_ftaue=188.57285952117329, + expected_rtaue=-0.69999999999999996, + expected_kappaa=1.7187938085542791, + expected_ptrepv=0.081309182573405442, + expected_ptripv=0.072164301346324039, + expected_tauee=3.2739047552801135, + expected_tauei=3.2739047552801135, + expected_taueff=3.2739047552801135, + expected_powerht=290.18368660937881, + ), + PcondParam( + iradloss=1, + tauee_in=0, + pradpv=0.11824275660100725, + kappaa_ipb=1.68145080681586, + pohmmw=0.63634001890069991, + falpha=0.94999999999999996, + ptaue=0.51000000000000001, + gtaue=0, + ftaue=104.36916202452747, + rtaue=-0.58999999999999997, + qtaue=0, + iinvqd=1, + isc=37, + ignite=0, + afuel=2.5, + palpmw=319.03020327154269, + aspect=3, + bt=5.2375830857646202, + dene=8.0593948787884524e19, + dnitot=7.1529510234203251e19, + dnla=8.925359201116491e19, + eps=0.33333333333333331, + hfact=1.7340642483550435, + kappa=1.8500000000000001, + kappa95=1.6517857142857142, + pchargemw=1.2453296074483358, + pinjmw=75.397788712812741, + plascur=16616203.759182997, + pcoreradpv=0.047757569353246924, + q=3.5610139569387185, + qstar=2.9513713188821282, + rmajor=8, + rminor=2.6666666666666665, + te=12.437097421317889, + ten=13.745148298980761, + tin=13.745148298980761, + vol=1888.1711539956691, + xarea=38.39822223637151, + zeff=2.4987360098030775, + expected_kappaa_ipb=1.68145080681586, + expected_ptaue=0.51000000000000001, + expected_ftaue=103.56301150501412, + expected_rtaue=-0.58999999999999997, + expected_kappaa=1.7187938085542791, + expected_ptrepv=0.08142612910014517, + expected_ptripv=0.072268094843318462, + expected_tauee=3.269202679985145, + expected_tauei=3.269202679985145, + expected_taueff=3.2692026799851455, + expected_powerht=290.18368660937881, + ), + PcondParam( + iradloss=1, + tauee_in=0, + pradpv=0.11824275660100725, + kappaa_ipb=1.68145080681586, + pohmmw=0.63634001890069991, + falpha=0.94999999999999996, + ptaue=0.54000000000000004, + gtaue=0, + ftaue=92.132683025124891, + rtaue=-0.60999999999999999, + qtaue=0, + iinvqd=1, + isc=38, + ignite=0, + afuel=2.5, + palpmw=319.03020327154269, + aspect=3, + bt=5.2375830857646202, + dene=8.0593948787884524e19, + dnitot=7.1529510234203251e19, + dnla=8.925359201116491e19, + eps=0.33333333333333331, + hfact=1.1117392853827024, + kappa=1.8500000000000001, + kappa95=1.6517857142857142, + pchargemw=1.2453296074483358, + pinjmw=75.397788712812741, + plascur=16616203.759182997, + pcoreradpv=0.047757569353246924, + q=3.5610139569387185, + qstar=2.9513713188821282, + rmajor=8, + rminor=2.6666666666666665, + te=12.437097421317889, + ten=13.745148298980761, + tin=13.745148298980761, + vol=1888.1711539956691, + xarea=38.39822223637151, + zeff=2.4987360098030775, + expected_kappaa_ipb=1.68145080681586, + expected_ptaue=0.54000000000000004, + expected_ftaue=130.75063341866976, + expected_rtaue=-0.60999999999999999, + expected_kappaa=1.7187938085542791, + expected_ptrepv=0.072709146314778414, + expected_ptripv=0.064531515128155068, + expected_tauee=3.6611421391548524, + expected_tauei=3.6611421391548524, + expected_taueff=3.6611421391548529, + expected_powerht=290.18368660937881, + ), + PcondParam( + iradloss=1, + tauee_in=0, + pradpv=0.11824275660100725, + kappaa_ipb=1.68145080681586, + pohmmw=0.63634001890069991, + falpha=0.94999999999999996, + ptaue=0.48999999999999999, + gtaue=0, + ftaue=78.856230211754649, + rtaue=-0.55000000000000004, + qtaue=0, + iinvqd=1, + isc=39, + ignite=0, + afuel=2.5, + palpmw=319.03020327154269, + aspect=3, + bt=5.2375830857646202, + dene=8.0593948787884524e19, + dnitot=7.1529510234203251e19, + dnla=8.925359201116491e19, + eps=0.33333333333333331, + hfact=0.84477227311274361, + kappa=1.8500000000000001, + kappa95=1.6517857142857142, + pchargemw=1.2453296074483358, + pinjmw=75.397788712812741, + plascur=16616203.759182997, + pcoreradpv=0.047757569353246924, + q=3.5610139569387185, + qstar=2.9513713188821282, + rmajor=8, + rminor=2.6666666666666665, + te=12.437097421317889, + ten=13.745148298980761, + tin=13.745148298980761, + vol=1888.1711539956691, + xarea=38.39822223637151, + zeff=2.4987360098030775, + expected_kappaa_ipb=1.68145080681586, + expected_ptaue=0.48999999999999999, + expected_ftaue=85.223040995670956, + expected_rtaue=-0.55000000000000004, + expected_kappaa=1.7187938085542791, + expected_ptrepv=0.078529089520063822, + expected_ptripv=0.069696886639614319, + expected_tauee=3.3898077909969717, + expected_tauei=3.3898077909969717, + expected_taueff=3.3898077909969717, + expected_powerht=290.18368660937881, + ), + PcondParam( + iradloss=1, + tauee_in=0, + pradpv=0.11824275660100725, + kappaa_ipb=1.68145080681586, + pohmmw=0.63634001890069991, + falpha=0.94999999999999996, + ptaue=0.44800000000000001, + gtaue=0, + ftaue=238.73238207972739, + rtaue=-0.73499999999999999, + qtaue=0, + iinvqd=1, + isc=40, + ignite=0, + afuel=2.5, + palpmw=319.03020327154269, + aspect=3, + bt=5.2375830857646202, + dene=8.0593948787884524e19, + dnitot=7.1529510234203251e19, + dnla=8.925359201116491e19, + eps=0.33333333333333331, + hfact=1.6096667103064701, + kappa=1.8500000000000001, + kappa95=1.6517857142857142, + pchargemw=1.2453296074483358, + pinjmw=75.397788712812741, + plascur=16616203.759182997, + pcoreradpv=0.047757569353246924, + q=3.5610139569387185, + qstar=2.9513713188821282, + rmajor=8, + rminor=2.6666666666666665, + te=12.437097421317889, + ten=13.745148298980761, + tin=13.745148298980761, + vol=1888.1711539956691, + xarea=38.39822223637151, + zeff=2.4987360098030775, + expected_kappaa_ipb=1.68145080681586, + expected_ptaue=0.44800000000000001, + expected_ftaue=232.72166245933104, + expected_rtaue=-0.73499999999999999, + expected_kappaa=1.7187938085542791, + expected_ptrepv=0.081359821043062386, + expected_ptripv=0.072209244483967094, + expected_tauee=3.2718670722507683, + expected_tauei=3.2718670722507683, + expected_taueff=3.2718670722507692, + expected_powerht=290.18368660937881, + ), + PcondParam( + iradloss=1, + tauee_in=0, + pradpv=0.11824275660100725, + kappaa_ipb=1.68145080681586, + pohmmw=0.63634001890069991, + falpha=0.94999999999999996, + ptaue=0.32000000000000001, + gtaue=0, + ftaue=52.028076004704893, + rtaue=-0.46999999999999997, + qtaue=0, + iinvqd=1, + isc=41, + ignite=0, + afuel=2.5, + palpmw=319.03020327154269, + aspect=3, + bt=5.2375830857646202, + dene=8.0593948787884524e19, + dnitot=7.1529510234203251e19, + dnla=8.925359201116491e19, + eps=0.33333333333333331, + hfact=0.67053301699102119, + kappa=1.8500000000000001, + kappa95=1.6517857142857142, + pchargemw=1.2453296074483358, + pinjmw=75.397788712812741, + plascur=16616203.759182997, + pcoreradpv=0.047757569353246924, + q=3.5610139569387185, + qstar=2.9513713188821282, + rmajor=8, + rminor=2.6666666666666665, + te=12.437097421317889, + ten=13.745148298980761, + tin=13.745148298980761, + vol=1888.1711539956691, + xarea=38.39822223637151, + zeff=2.4987360098030775, + expected_kappaa_ipb=1.68145080681586, + expected_ptaue=0.32000000000000001, + expected_ftaue=50.282659177654601, + expected_rtaue=-0.46999999999999997, + expected_kappaa=1.7187938085542791, + expected_ptrepv=0.081513009259203975, + expected_ptripv=0.072345203550858064, + expected_tauee=3.2657182196344126, + expected_tauei=3.2657182196344126, + expected_taueff=3.2657182196344126, + expected_powerht=290.18368660937881, + ), + PcondParam( + iradloss=1, + tauee_in=0, + pradpv=0.11824275660100725, + kappaa_ipb=1.68145080681586, + pohmmw=0.63634001890069991, + falpha=0.94999999999999996, + ptaue=-0.0078747350665397467, + gtaue=0, + ftaue=178.10069717955975, + rtaue=-0.73999999999999999, + qtaue=0, + iinvqd=1, + isc=42, + ignite=0, + afuel=2.5, + palpmw=319.03020327154269, + aspect=3, + bt=5.2375830857646202, + dene=8.0593948787884524e19, + dnitot=7.1529510234203251e19, + dnla=8.925359201116491e19, + eps=0.33333333333333331, + hfact=2.1212580310552207, + kappa=1.8500000000000001, + kappa95=1.6517857142857142, + pchargemw=1.2453296074483358, + pinjmw=75.397788712812741, + plascur=16616203.759182997, + pcoreradpv=0.047757569353246924, + q=3.5610139569387185, + qstar=2.9513713188821282, + rmajor=8, + rminor=2.6666666666666665, + te=12.437097421317889, + ten=13.745148298980761, + tin=13.745148298980761, + vol=1888.1711539956691, + xarea=38.39822223637151, + zeff=2.4987360098030775, + expected_kappaa_ipb=1.68145080681586, + expected_ptaue=-0.0078747350665397467, + expected_ftaue=241.51291454983658, + expected_rtaue=-0.73999999999999999, + expected_kappaa=1.7187938085542791, + expected_ptrepv=0.073097992274882811, + expected_ptripv=0.064876627403966491, + expected_tauee=3.6416666339340682, + expected_tauei=3.6416666339340682, + expected_taueff=3.6416666339340686, + expected_powerht=290.18368660937881, + ), + PcondParam( + iradloss=1, + tauee_in=0, + pradpv=0.11824275660100725, + kappaa_ipb=1.68145080681586, + pohmmw=0.63634001890069991, + falpha=0.94999999999999996, + ptaue=0.02, + gtaue=0, + ftaue=17.002723443677841, + rtaue=-0.28999999999999998, + qtaue=0, + iinvqd=1, + isc=43, + ignite=0, + afuel=2.5, + palpmw=319.03020327154269, + aspect=3, + bt=5.2375830857646202, + dene=8.0593948787884524e19, + dnitot=7.1529510234203251e19, + dnla=8.925359201116491e19, + eps=0.33333333333333331, + hfact=50.095480115636271, + kappa=1.8500000000000001, + kappa95=1.6517857142857142, + pchargemw=1.2453296074483358, + pinjmw=75.397788712812741, + plascur=16616203.759182997, + pcoreradpv=0.047757569353246924, + q=3.5610139569387185, + qstar=2.9513713188821282, + rmajor=8, + rminor=2.6666666666666665, + te=12.437097421317889, + ten=13.745148298980761, + tin=13.745148298980761, + vol=1888.1711539956691, + xarea=38.39822223637151, + zeff=2.4987360098030775, + expected_kappaa_ipb=1.68145080681586, + expected_ptaue=0.02, + expected_ftaue=17.002214349414931, + expected_rtaue=-0.28999999999999998, + expected_kappaa=1.7187938085542791, + expected_ptrepv=0.081423406537449478, + expected_ptripv=0.072265678488503571, + expected_tauee=3.2693119926464509, + expected_tauei=3.2693119926464509, + expected_taueff=3.2693119926464513, + expected_powerht=290.18368660937881, + ), + PcondParam( + iradloss=1, + tauee_in=0, + pradpv=0.11824275660100725, + kappaa_ipb=1.68145080681586, + pohmmw=0.63634001890069991, + falpha=0.94999999999999996, + ptaue=-0.029999999999999999, + gtaue=0, + ftaue=21.102743356890517, + rtaue=-0.33000000000000002, + qtaue=0, + iinvqd=1, + isc=44, + ignite=0, + afuel=2.5, + palpmw=319.03020327154269, + aspect=3, + bt=5.2375830857646202, + dene=8.0593948787884524e19, + dnitot=7.1529510234203251e19, + dnla=8.925359201116491e19, + eps=0.33333333333333331, + hfact=87.869318916638761, + kappa=1.8500000000000001, + kappa95=1.6517857142857142, + pchargemw=1.2453296074483358, + pinjmw=75.397788712812741, + plascur=16616203.759182997, + pcoreradpv=0.047757569353246924, + q=3.5610139569387185, + qstar=2.9513713188821282, + rmajor=8, + rminor=2.6666666666666665, + te=12.437097421317889, + ten=13.745148298980761, + tin=13.745148298980761, + vol=1888.1711539956691, + xarea=38.39822223637151, + zeff=2.4987360098030775, + expected_kappaa_ipb=1.68145080681586, + expected_ptaue=-0.029999999999999999, + expected_ftaue=21.103103603854958, + expected_rtaue=-0.33000000000000002, + expected_kappaa=1.7187938085542791, + expected_ptrepv=0.081419881443596701, + expected_ptripv=0.072262549863580605, + expected_tauee=3.2694535383156871, + expected_tauei=3.2694535383156871, + expected_taueff=3.2694535383156871, + expected_powerht=290.18368660937881, + ), + PcondParam( + iradloss=1, + tauee_in=0, + pradpv=0.11824275660100725, + kappaa_ipb=1.68145080681586, + pohmmw=0.63634001890069991, + falpha=0.94999999999999996, + ptaue=0.070000000000000007, + gtaue=0, + ftaue=13.697325239330771, + rtaue=-0.25, + qtaue=0, + iinvqd=1, + isc=45, + ignite=0, + afuel=2.5, + palpmw=319.03020327154269, + aspect=3, + bt=5.2375830857646202, + dene=8.0593948787884524e19, + dnitot=7.1529510234203251e19, + dnla=8.925359201116491e19, + eps=0.33333333333333331, + hfact=28.562137619592285, + kappa=1.8500000000000001, + kappa95=1.6517857142857142, + pchargemw=1.2453296074483358, + pinjmw=75.397788712812741, + plascur=16616203.759182997, + pcoreradpv=0.047757569353246924, + q=3.5610139569387185, + qstar=2.9513713188821282, + rmajor=8, + rminor=2.6666666666666665, + te=12.437097421317889, + ten=13.745148298980761, + tin=13.745148298980761, + vol=1888.1711539956691, + xarea=38.39822223637151, + zeff=2.4987360098030775, + expected_kappaa_ipb=1.68145080681586, + expected_ptaue=0.070000000000000007, + expected_ftaue=13.699210029839019, + expected_rtaue=-0.25, + expected_kappaa=1.7187938085542791, + expected_ptrepv=0.081421142032658531, + expected_ptripv=0.072263668673609824, + expected_tauee=3.2694029195542003, + expected_tauei=3.2694029195542003, + expected_taueff=3.2694029195542003, + expected_powerht=290.18368660937881, + ), + PcondParam( + iradloss=1, + tauee_in=0, + pradpv=0.11824275660100725, + kappaa_ipb=1.68145080681586, + pohmmw=0.63634001890069991, + falpha=0.94999999999999996, + ptaue=0.44, + gtaue=0, + ftaue=251.73181499774617, + rtaue=-0.72999999999999998, + qtaue=0, + iinvqd=1, + isc=46, + ignite=0, + afuel=2.5, + palpmw=319.03020327154269, + aspect=3, + bt=5.2375830857646202, + dene=8.0593948787884524e19, + dnitot=7.1529510234203251e19, + dnla=8.925359201116491e19, + eps=0.33333333333333331, + hfact=0.50082256309019457, + kappa=1.8500000000000001, + kappa95=1.6517857142857142, + pchargemw=1.2453296074483358, + pinjmw=75.397788712812741, + plascur=16616203.759182997, + pcoreradpv=0.047757569353246924, + q=3.5610139569387185, + qstar=2.9513713188821282, + rmajor=8, + rminor=2.6666666666666665, + te=12.437097421317889, + ten=13.745148298980761, + tin=13.745148298980761, + vol=1888.1711539956691, + xarea=38.39822223637151, + zeff=2.4987360098030775, + expected_kappaa_ipb=1.68145080681586, + expected_ptaue=0.44, + expected_ftaue=230.82001145150934, + expected_rtaue=-0.72999999999999998, + expected_kappaa=1.7187938085542791, + expected_ptrepv=0.079599509500323962, + expected_ptripv=0.070646915991500636, + expected_tauee=3.3442231132583498, + expected_tauei=3.3442231132583498, + expected_taueff=3.3442231132583502, + expected_powerht=290.18368660937881, + ), + PcondParam( + iradloss=1, + tauee_in=0, + pradpv=0.11824275660100725, + kappaa_ipb=1.68145080681586, + pohmmw=0.63634001890069991, + falpha=0.94999999999999996, + ptaue=0.32000000000000001, + gtaue=0, + ftaue=116.17488441727863, + rtaue=-0.46999999999999997, + qtaue=0, + iinvqd=1, + isc=47, + ignite=0, + afuel=2.5, + palpmw=319.03020327154269, + aspect=3, + bt=5.2375830857646202, + dene=8.0593948787884524e19, + dnitot=7.1529510234203251e19, + dnla=8.925359201116491e19, + eps=0.33333333333333331, + hfact=0.77961193402355955, + kappa=1.8500000000000001, + kappa95=1.6517857142857142, + pchargemw=1.2453296074483358, + pinjmw=75.397788712812741, + plascur=16616203.759182997, + pcoreradpv=0.047757569353246924, + q=3.5610139569387185, + qstar=2.9513713188821282, + rmajor=8, + rminor=2.6666666666666665, + te=12.437097421317889, + ten=13.745148298980761, + tin=13.745148298980761, + vol=1888.1711539956691, + xarea=38.39822223637151, + zeff=2.4987360098030775, + expected_kappaa_ipb=1.68145080681586, + expected_ptaue=0.32000000000000001, + expected_ftaue=58.462387646846778, + expected_rtaue=-0.46999999999999997, + expected_kappaa=1.7187938085542791, + expected_ptrepv=0.070108167457759038, + expected_ptripv=0.062223069561580698, + expected_tauee=3.7969687288631331, + expected_tauei=3.7969687288631331, + expected_taueff=3.7969687288631335, + expected_powerht=290.18368660937881, + ), + ), +) +def test_pcond(pcondparam, monkeypatch, physics): + """ + Automatically generated Regression Unit Test for pcond. + + This test was generated using data from tests/regression/scenarios/large-tokamak/IN.DAT. + + :param pcondparam: the data used to mock and assert in this test. + :type pcondparam: pcondparam + + :param monkeypatch: pytest fixture used to mock module/class variables + :type monkeypatch: _pytest.monkeypatch.monkeypatch + """ + + monkeypatch.setattr(physics_variables, "iradloss", pcondparam.iradloss) + + monkeypatch.setattr(physics_variables, "tauee_in", pcondparam.tauee_in) + + monkeypatch.setattr(physics_variables, "pradpv", pcondparam.pradpv) + + monkeypatch.setattr(physics_variables, "kappaa_ipb", pcondparam.kappaa_ipb) + + monkeypatch.setattr(physics_variables, "pohmmw", pcondparam.pohmmw) + + monkeypatch.setattr(physics_variables, "falpha", pcondparam.falpha) + + monkeypatch.setattr(startup_variables, "ptaue", pcondparam.ptaue) + + monkeypatch.setattr(startup_variables, "gtaue", pcondparam.gtaue) + + monkeypatch.setattr(startup_variables, "ftaue", pcondparam.ftaue) + + monkeypatch.setattr(startup_variables, "rtaue", pcondparam.rtaue) + + monkeypatch.setattr(startup_variables, "qtaue", pcondparam.qtaue) + + kappaa, ptrepv, ptripv, tauee, tauei, taueff, powerht = physics.pcond( + iinvqd=pcondparam.iinvqd, + isc=pcondparam.isc, + ignite=pcondparam.ignite, + afuel=pcondparam.afuel, + palpmw=pcondparam.palpmw, + aspect=pcondparam.aspect, + bt=pcondparam.bt, + dene=pcondparam.dene, + dnitot=pcondparam.dnitot, + dnla=pcondparam.dnla, + eps=pcondparam.eps, + hfact=pcondparam.hfact, + kappa=pcondparam.kappa, + kappa95=pcondparam.kappa95, + pchargemw=pcondparam.pchargemw, + pinjmw=pcondparam.pinjmw, + plascur=pcondparam.plascur, + pcoreradpv=pcondparam.pcoreradpv, + q=pcondparam.q, + qstar=pcondparam.qstar, + rmajor=pcondparam.rmajor, + rminor=pcondparam.rminor, + te=pcondparam.te, + ten=pcondparam.ten, + tin=pcondparam.tin, + vol=pcondparam.vol, + xarea=pcondparam.xarea, + zeff=pcondparam.zeff, + ) + + assert physics_variables.kappaa_ipb == pytest.approx(pcondparam.expected_kappaa_ipb) + + assert startup_variables.ptaue == pytest.approx(pcondparam.expected_ptaue) + + assert startup_variables.ftaue == pytest.approx(pcondparam.expected_ftaue) + + assert startup_variables.rtaue == pytest.approx(pcondparam.expected_rtaue) + + assert kappaa == pytest.approx(pcondparam.expected_kappaa) + + assert powerht == pytest.approx(pcondparam.expected_powerht) + + assert ptrepv == pytest.approx(pcondparam.expected_ptrepv) + + assert ptripv == pytest.approx(pcondparam.expected_ptripv) + + assert tauee == pytest.approx(pcondparam.expected_tauee) + + assert taueff == pytest.approx(pcondparam.expected_taueff) + + assert tauei == pytest.approx(pcondparam.expected_tauei)