diff --git a/src/extract/objectives.jl b/src/extract/objectives.jl index c6d862b1..3aa91d62 100644 --- a/src/extract/objectives.jl +++ b/src/extract/objectives.jl @@ -81,9 +81,35 @@ end # ========================= # const ObjectiveFunctionsLibrary = OrderedCollections.OrderedDict{Symbol,ObjectiveFunction}() +function calculate_greenwald_fraction(dd::IMAS.dd) + try + eqt = dd.equilibrium.time_slice[] + cp1d = dd.core_profiles.profiles_1d[] + ne_line = IMAS.ne_line(eqt, cp1d) + Ip_MA = eqt.global_quantities.ip / 1e6 # Convert to MA + a_minor = eqt.boundary.minor_radius # Get minor radius from equilibrium + n_Greenwald = (Ip_MA / (π * a_minor^2)) * 1e20 # Greenwald limit [m⁻³] + return ne_line / n_Greenwald + catch + return 0.0 + end +end + +function calculate_bootstrap_fraction(dd::IMAS.dd) + try + I_bootstrap = @ddtime(dd.summary.global_quantities.current_bootstrap.value) + I_p = dd.equilibrium.time_slice[].global_quantities.ip + return I_bootstrap / I_p + catch + return 0.0 + end +end + function update_ObjectiveFunctionsLibrary!() empty!(ObjectiveFunctionsLibrary) #! format: off + + # Original FUSE objectives ObjectiveFunction(:min_levelized_CoE, "\$/kWh", dd -> dd.costing.levelized_CoE, -Inf) ObjectiveFunction(:min_log10_levelized_CoE, "log₁₀(\$/kW)", dd -> log10(dd.costing.levelized_CoE), -Inf) ObjectiveFunction(:min_capital_cost, "\$B", dd -> dd.costing.cost_direct_capital.cost / 1E3, -Inf) @@ -97,6 +123,14 @@ function update_ObjectiveFunctionsLibrary!() ObjectiveFunction(:min_βn, "", dd -> dd.equilibrium.time_slice[].global_quantities.beta_normal, -Inf) ObjectiveFunction(:min_R0, "m", dd -> dd.equilibrium.time_slice[].boundary.geometric_axis.r, -Inf) ObjectiveFunction(:max_zeff, "", dd -> @ddtime(dd.summary.volume_average.zeff.value), Inf) + + # New physics objectives for my studies + ObjectiveFunction(:max_βp, "", dd -> dd.equilibrium.time_slice[].global_quantities.beta_pol, Inf) + ObjectiveFunction(:max_h98, "", dd -> @ddtime(dd.summary.global_quantities.h_98.value), Inf) + ObjectiveFunction(:max_tau_e, "s", dd -> @ddtime(dd.summary.global_quantities.tau_energy.value), Inf) + ObjectiveFunction(:max_fbs, "", dd -> calculate_bootstrap_fraction(dd), Inf) + ObjectiveFunction(:max_greenwald_fraction, "", dd -> calculate_greenwald_fraction(dd), Inf) + #! format: on return ObjectiveFunctionsLibrary end diff --git a/src/get_from.jl b/src/get_from.jl index 80ad7121..b37dc8e5 100644 --- a/src/get_from.jl +++ b/src/get_from.jl @@ -121,6 +121,20 @@ function get_from(dd::IMAS.dd{T}, what::Val{:zeff_ped}, from_where::Symbol, rho_ return error("`get_from(dd, $what, Val(:$from_where))` doesn't exist yet") end +# ne_sep [m^-3] +function get_from(dd::IMAS.dd{T}, what::Val{:ne_sep}, from_where::Symbol; time0::Float64=dd.global_time)::T where {T<:Real} + if from_where == :core_profiles + cp1d = dd.core_profiles.profiles_1d[time0] + return cp1d.electrons.density_thermal[end] + elseif from_where == :pulse_schedule + if !ismissing(dd.pulse_schedule.density_control.n_e_separatrix, :reference) + return get_time_array(dd.pulse_schedule.density_control.n_e_separatrix, :reference, time0, :linear) + end + error("`get_from(dd, $what, Val(:$from_where))` does not have data") + end + return error("`get_from(dd, $what, Val(:$from_where))` doesn't exist yet") +end + Base.Docs.@doc """ get_from(dd::IMAS.dd, what::Symbol, from_where::Symbol; time0::Float64=dd.global_time) @@ -141,6 +155,8 @@ Supported quantities for `what`: - Possible sources (`from_where`): `:core_profiles`, `:summary`, `:pulse_schedule` - `:zeff_ped` - Effective charge at the pedestal [-] - Possible sources (`from_where`): `:core_profiles`, `:summary`, `:pulse_schedule` +- `:ne_sep` - Electron density at the separatrix [m^-3] + - Possible sources (`from_where`): `:core_profiles`, `:pulse_schedule` `time0` defines the time point at which to retrieve the value, default is `dd.global_time`.