@@ -33,10 +33,10 @@ Base.@kwdef mutable struct FUSEparameters__ActorFluxMatcher{T<:Real} <: Paramete
3333 xtol:: Entry{T} = Entry {T} (" -" , " Tolerance on the solution vector" ; default= 1E-3 , check= x -> @assert x > 0.0 " must be: xtol > 0.0" )
3434 algorithm:: Switch{Symbol} =
3535 Switch {Symbol} (
36- [:basic_polyalg , :polyalg , :broyden , :anderson , :simple_trust , :trust , :simple , :old_anderson , :custom , :none ],
36+ [:default , : basic_polyalg , :polyalg , :broyden , :anderson , :simple_trust , :simple_dfsane , :trust , :simple , :old_anderson , :custom , :none ],
3737 " -" ,
3838 " Optimizing algorithm used for the flux matching" ;
39- default= :basic_polyalg
39+ default= :default
4040 )
4141 custom_algorithm:: Entry{NonlinearSolve.AbstractNonlinearSolveAlgorithm} =
4242 Entry {NonlinearSolve.AbstractNonlinearSolveAlgorithm} (" -" , " User-defined custom solver from NonlinearSolve" )
@@ -116,7 +116,7 @@ function _step(actor::ActorFluxMatcher{D,P}) where {D<:Real,P<:Real}
116116
117117 # Apply replay profiles if any evolve options are set to :replay
118118 evolve_densities = evolve_densities_dictionary (cp1d, par)
119- if par. evolve_Te == :replay || par. evolve_Ti == :replay || par. evolve_rotation == :replay ||
119+ if par. evolve_Te == :replay || par. evolve_Ti == :replay || par. evolve_rotation == :replay ||
120120 (! isempty (evolve_densities) && any (evolve == :replay for (_, evolve) in evolve_densities))
121121 finalize (step (actor. actor_replay))
122122 end
@@ -160,24 +160,36 @@ function _step(actor::ActorFluxMatcher{D,P}) where {D<:Real,P<:Real}
160160 end
161161
162162 autodiff = NonlinearSolve. ADTypes. AutoFiniteDiff ()
163- if typeof (dd) . parameters[ 1 ] <: ForwardDiff.Dual
163+ if D <: ForwardDiff.Dual
164164 autodiff = NonlinearSolve. ADTypes. AutoForwardDiff ()
165165 end
166166
167+ algorithm = if par. algorithm === :default
168+ if actor. actor_ct. actor_turb. par. model === :TGLFNN
169+ # combines speed and robustness, but needs smooth derivatives
170+ :basic_polyalg
171+ else
172+ # derivative-free method
173+ :simple_dfsane
174+ end
175+ else
176+ par. algorithm
177+ end
178+
167179 # Different defaults for gradient-based methods
168180 if par. max_iterations != 0
169181 max_iterations = abs (par. max_iterations)
170- elseif par . algorithm in (:trust , :simple_trust , :broyden , :polyalg )
182+ elseif algorithm in (:trust , :simple_trust , :broyden , :polyalg )
171183 max_iterations = 50
172184 else
173185 max_iterations = 500
174186 end
175187
176188 res = try
177- if par . algorithm == :none
189+ if algorithm == :none
178190 res = (zero= opt_parameters,)
179191
180- elseif par . algorithm == :simple
192+ elseif algorithm == :simple
181193 ftol = Inf # always use xtol condition as in NonlinearSolve.jl
182194 res = flux_match_simple (actor, opt_parameters, initial_cp1d, z_scaled_history, err_history, max_iterations, ftol, par. xtol, prog)
183195
@@ -198,10 +210,10 @@ function _step(actor::ActorFluxMatcher{D,P}) where {D<:Real,P<:Real}
198210 problem = NonlinearSolve. NonlinearProblem (f!, opt_parameters, initial_cp1d)
199211
200212 # 3. Algorithm selection
201- alg = if par . algorithm == :old_anderson
213+ alg = if algorithm == :old_anderson
202214 NonlinearSolve. NLsolveJL (; method= :anderson , m= 4 , beta= - par. step_size * 5 )
203215
204- elseif par . algorithm == :anderson
216+ elseif algorithm == :anderson
205217 NonlinearSolve. FixedPointAccelerationJL (;
206218 algorithm= :Anderson ,
207219 m= 5 , # history length
@@ -210,29 +222,32 @@ function _step(actor::ActorFluxMatcher{D,P}) where {D<:Real,P<:Real}
210222 replace_invalids= :ReplaceVector
211223 )
212224
213- elseif par . algorithm == :broyden
225+ elseif algorithm == :broyden
214226 NonlinearSolve. Broyden (; autodiff)
215227
216- elseif par . algorithm == :trust
228+ elseif algorithm == :trust
217229 NonlinearSolve. TrustRegion (; autodiff)
218230
219- elseif par . algorithm == :simple_trust
231+ elseif algorithm == :simple_trust
220232 NonlinearSolve. SimpleTrustRegion (; autodiff)
221233
222- elseif par. algorithm === :basic_polyalg
234+ elseif algorithm == :simple_dfsane
235+ NonlinearSolve. SimpleDFSane ()
236+
237+ elseif algorithm === :basic_polyalg
223238 NonlinearSolve. NonlinearSolvePolyAlgorithm ((NonlinearSolve. Broyden (; autodiff),
224239 NonlinearSolve. SimpleTrustRegion (; autodiff)))
225240
226- elseif par . algorithm == :polyalg
241+ elseif algorithm == :polyalg
227242 # Default NonlinearSolve algorithm
228243 NonlinearSolve. FastShortcutNonlinearPolyalg (; autodiff)
229244
230- elseif par . algorithm == :custom
245+ elseif algorithm == :custom
231246 ismissing (par. custom_algorithm) && error (" custom_algorithm must be set to a NonlinearSolve algorithm for algorithm=:custom" )
232247 par. custom_algorithm
233248
234249 else
235- error (" Unsupported algorithm: $(par . algorithm) " )
250+ error (" Unsupported algorithm: $(algorithm) " )
236251 end
237252
238253 # 4. Solve with matching tolerances and iteration limits
@@ -268,7 +283,7 @@ function _step(actor::ActorFluxMatcher{D,P}) where {D<:Real,P<:Real}
268283 end
269284
270285 # detect cases where all optimization calls failed
271- if par . algorithm != :none && isempty (err_history)
286+ if algorithm != :none && isempty (err_history)
272287 flux_match_errors (actor, opt_parameters, initial_cp1d)
273288 error (" FluxMatcher failed" )
274289 end
@@ -823,13 +838,13 @@ function pack_z_profiles(cp1d::IMAS.core_profiles__profiles_1d{D}, par::Override
823838 if par. evolve_rotation == :flux_match
824839 # Use TGYRO approach: evolve normalized rotation shear f_rot = (dω/dr) / w0_norm
825840 w0_norm = calculate_w0_norm (cp1d. electrons. temperature[1 ])
826-
841+
827842 # Calculate rotation shear dω/dr
828843 dw_dr = IMAS. gradient (cp1d. grid. rho_tor_norm, cp1d. rotation_frequency_tor_sonic)[cp_gridpoints]
829-
844+
830845 # Convert to normalized rotation shear f_rot
831846 f_rot = dw_dr ./ w0_norm
832-
847+
833848 append! (z_profiles, f_rot)
834849 push! (profiles_paths, (:rotation_frequency_tor_sonic ,))
835850 push! (fluxes_paths, (:momentum_tor ,))
@@ -907,13 +922,13 @@ function unpack_z_profiles(
907922 if par. evolve_rotation == :flux_match
908923 # Use TGYRO approach: convert normalized rotation shear back to rotation frequency
909924 w0_norm = calculate_w0_norm (cp1d. electrons. temperature[1 ])
910-
925+
911926 # Get normalized rotation shear f_rot from z_profiles
912927 f_rot_evolved = z_profiles[counter+ 1 : counter+ N]
913-
928+
914929 # Convert to rotation shear: dω/dr = f_rot * w0_norm
915930 dw_dr_evolved = f_rot_evolved .* w0_norm
916-
931+
917932 # Use the new profile_from_rotation_shear_transport function
918933 cp1d. rotation_frequency_tor_sonic = IMAS. profile_from_rotation_shear_transport (
919934 cp1d. rotation_frequency_tor_sonic,
@@ -1075,8 +1090,8 @@ function evolve_densities_dict_creation(
10751090 quasi_neutrality_specie:: Union{Symbol,Bool} = false )
10761091
10771092 parse_list = vcat (
1078- [[sym, :flux_match ] for sym in flux_match_species],
1079- [[sym, :match_ne_scale ] for sym in match_ne_scale_species],
1093+ [[sym, :flux_match ] for sym in flux_match_species],
1094+ [[sym, :match_ne_scale ] for sym in match_ne_scale_species],
10801095 [[sym, :fixed ] for sym in fixed_species],
10811096 [[sym, :replay ] for sym in replay_species]
10821097 )
@@ -1129,7 +1144,7 @@ end
11291144
11301145Calculate TGYRO normalization frequency w0_norm = cs/R₀ where:
11311146
1132- cs = sound speed at axis = √(kB*Te(0)/md)
1147+ cs = sound speed at axis = √(kB*Te(0)/md)
11331148"""
11341149function calculate_w0_norm (Te_axis)
11351150 cs_axis = sqrt (IMAS. mks. k_B * Te_axis / IMAS. mks. m_d) # sound speed at axis
@@ -1145,29 +1160,29 @@ Replay profiles from replay_dd to current dd for channels set to :replay
11451160function _step (replay_actor:: ActorReplay , actor:: ActorFluxMatcher , replay_dd:: IMAS.dd )
11461161 dd = actor. dd
11471162 par = actor. par
1148-
1163+
11491164 time0 = dd. global_time
11501165 cp1d = dd. core_profiles. profiles_1d[time0]
11511166 replay_cp1d = replay_dd. core_profiles. profiles_1d[time0]
11521167 rho = cp1d. grid. rho_tor_norm
1153-
1168+
11541169 # Get the transport grid boundary for blending
11551170 rho_nml = par. rho_transport[end ]
11561171 rho_ped = par. rho_transport[end ]
1157-
1172+
11581173 # Replay electron temperature if set to :replay
11591174 if par. evolve_Te == :replay
11601175 cp1d. electrons. temperature = IMAS. blend_core_edge (replay_cp1d. electrons. temperature, cp1d. electrons. temperature, rho, rho_nml, rho_ped)
11611176 end
1162-
1163- # Replay ion temperature if set to :replay
1177+
1178+ # Replay ion temperature if set to :replay
11641179 if par. evolve_Ti == :replay
11651180 Ti_replay = IMAS. blend_core_edge (replay_cp1d. t_i_average, cp1d. t_i_average, rho, rho_nml, rho_ped)
11661181 for ion in cp1d. ion
11671182 ion. temperature = Ti_replay
11681183 end
11691184 end
1170-
1185+
11711186 # Replay rotation if set to :replay
11721187 if par. evolve_rotation == :replay
11731188 i_nml = IMAS. argmin_abs (rho, rho_nml)
@@ -1177,15 +1192,15 @@ function _step(replay_actor::ActorReplay, actor::ActorFluxMatcher, replay_dd::IM
11771192 ω_core[1 : i_nml] = ω_core[1 : i_nml] .- ω_core[i_nml] .+ ω_edge[i_nml]
11781193 cp1d. rotation_frequency_tor_sonic = ω_core
11791194 end
1180-
1195+
11811196 # Handle density replays
11821197 evolve_densities = evolve_densities_dictionary (cp1d, par)
11831198 if ! isempty (evolve_densities)
11841199 # Replay electron density if set to :replay
11851200 if evolve_densities[:electrons ] == :replay
11861201 cp1d. electrons. density_thermal = IMAS. blend_core_edge (replay_cp1d. electrons. density_thermal, cp1d. electrons. density_thermal, rho, rho_nml, rho_ped; method= :scale )
11871202 end
1188-
1203+
11891204 # Replay ion densities if set to :replay
11901205 for (ion, replay_ion) in zip (cp1d. ion, replay_cp1d. ion)
11911206 ion_symbol = Symbol (ion. label)
@@ -1195,7 +1210,7 @@ function _step(replay_actor::ActorReplay, actor::ActorFluxMatcher, replay_dd::IM
11951210 end
11961211 end
11971212 end
1198-
1213+
11991214 # Ensure quasi neutrality if needed
12001215 for (species, evolve) in evolve_densities
12011216 if evolve == :quasi_neutrality
@@ -1204,6 +1219,6 @@ function _step(replay_actor::ActorReplay, actor::ActorFluxMatcher, replay_dd::IM
12041219 end
12051220 end
12061221 end
1207-
1222+
12081223 return replay_actor
12091224end
0 commit comments