@@ -12,8 +12,9 @@ avoiding repeated index arithmetic throughout the code.
1212## Mode Indexing Convention
1313
1414For linear index i ∈ [1, numpert_total]:
15- - m_modes[i] = (i-1) % mpert + mlow
16- - n_modes[i] = (i-1) ÷ mpert + nlow
15+
16+ - m_modes[i] = (i-1) % mpert + mlow
17+ - n_modes[i] = (i-1) ÷ mpert + nlow
1718
1819This matches the convention used in ForceFreeStates where modes are ordered as:
1920(m1,n1), (m2,n1), ..., (mpert,n1), (m1,n2), (m2,n2), ..., (mpert,npert)
@@ -110,119 +111,119 @@ function write_outputs_to_HDF5(
110111
111112 # Forcing modes
112113 forcing_group = haskey (pe_group, " ForcingModes" ) ? pe_group[" ForcingModes" ] : create_group (pe_group, " ForcingModes" )
113- forcing_group[" n" ] = [mode. n for mode in intr. forcing_modes]
114- forcing_group[" m" ] = [mode. m for mode in intr. forcing_modes]
114+ forcing_group[" n" ] = [mode. n for mode in intr. forcing_modes]
115+ forcing_group[" m" ] = [mode. m for mode in intr. forcing_modes]
115116 forcing_group[" amplitude" ] = [mode. amplitude for mode in intr. forcing_modes]
116117
117118 # Control-surface forcing/response spectra in the three Pharr field representations
118119 # (all tesla; flux/weber is never stored). b̃ = root-area-weighted (coordinate-invariant).
119- ! isempty (state. forcing_b) && (pe_group[" forcing_b" ] = state. forcing_b)
120- ! isempty (state. forcing_b_rootarea) && (pe_group[" forcing_b_root_area" ] = state. forcing_b_rootarea)
121- ! isempty (state. forcing_b_area) && (pe_group[" forcing_b_area" ] = state. forcing_b_area)
122- ! isempty (state. response_b) && (pe_group[" response_b" ] = state. response_b)
120+ ! isempty (state. forcing_b) && (pe_group[" forcing_b" ] = state. forcing_b)
121+ ! isempty (state. forcing_b_rootarea) && (pe_group[" forcing_b_root_area" ] = state. forcing_b_rootarea)
122+ ! isempty (state. forcing_b_area) && (pe_group[" forcing_b_area" ] = state. forcing_b_area)
123+ ! isempty (state. response_b) && (pe_group[" response_b" ] = state. response_b)
123124 ! isempty (state. response_b_rootarea) && (pe_group[" response_b_root_area" ] = state. response_b_rootarea)
124- ! isempty (state. response_b_area) && (pe_group[" response_b_area" ] = state. response_b_area)
125+ ! isempty (state. response_b_area) && (pe_group[" response_b_area" ] = state. response_b_area)
125126
126127 # Control surface matrices [numpert_total × numpert_total], in coordinate-invariant
127128 # root-area-weighted field (b̃) space. Recover the area-weighted field b̄ with the stored
128129 # operator S ≡ rootarea_to_area_weight (b̄ = S·b̃): e.g. L_b̄ = S·L̃·S†; recover flux with the
129130 # scalar surface_area A: Φ = A·b̄ (internally R = S·A, Φ = R·b̃). [Pharr 2026]
130131 mat_group = haskey (pe_group, " ResponseMatrices" ) ? pe_group[" ResponseMatrices" ] : create_group (pe_group, " ResponseMatrices" )
131- ! isempty (state. plasma_inductance) && (mat_group[" plasma_inductance" ] = state. plasma_inductance)
132+ ! isempty (state. plasma_inductance) && (mat_group[" plasma_inductance" ] = state. plasma_inductance)
132133 ! isempty (state. surface_inductance) && (mat_group[" surface_inductance" ] = state. surface_inductance)
133- ! isempty (state. permeability) && (mat_group[" permeability" ] = state. permeability)
134- ! isempty (state. reluctance) && (mat_group[" reluctance" ] = state. reluctance)
134+ ! isempty (state. permeability) && (mat_group[" permeability" ] = state. permeability)
135+ ! isempty (state. reluctance) && (mat_group[" reluctance" ] = state. reluctance)
135136 ! isempty (state. rootarea_to_area_weight) && (mat_group[" rootarea_to_area_weight_operator" ] = state. rootarea_to_area_weight)
136- (state. surface_area != 0.0 ) && (mat_group[" surface_area" ] = state. surface_area)
137+ (state. surface_area != 0.0 ) && (mat_group[" surface_area" ] = state. surface_area)
137138
138139 # Response fields (ComplexF64 directly)
139140 response_group = haskey (pe_group, " Response" ) ? pe_group[" Response" ] : create_group (pe_group, " Response" )
140141 ! isempty (state. psi_grid) && (response_group[" psi" ] = state. psi_grid)
141142 have_xi = ! isnothing (state. xi_modes)
142- have_b = have_xi && ! isnothing (state. b_modes)
143- response_group[" xi_psi" ] = have_xi ? state. xi_modes. psi : ComplexF64[]
144- response_group[" b_psi_area_weighted" ] = have_b ? state. b_modes. b_psi_area_weighted : ComplexF64[]
145- response_group[" Jb_theta" ] = have_b ? state. b_modes. theta : ComplexF64[]
146- response_group[" Jb_zeta" ] = have_b ? state. b_modes. zeta : ComplexF64[]
147- response_group[" b_n" ] = ! isnothing (state. b_n_modes) ? state. b_n_modes : ComplexF64[]
148- response_group[" xi_n" ] = ! isnothing (state. xi_n_modes) ? state. xi_n_modes : ComplexF64[]
143+ have_b = have_xi && ! isnothing (state. b_modes)
144+ response_group[" xi_psi" ] = have_xi ? state. xi_modes. psi : ComplexF64[]
145+ response_group[" b_psi_area_weighted" ] = have_b ? state. b_modes. b_psi_area_weighted : ComplexF64[]
146+ response_group[" Jb_theta" ] = have_b ? state. b_modes. theta : ComplexF64[]
147+ response_group[" Jb_zeta" ] = have_b ? state. b_modes. zeta : ComplexF64[]
148+ response_group[" b_n" ] = ! isnothing (state. b_n_modes) ? state. b_n_modes : ComplexF64[]
149+ response_group[" xi_n" ] = ! isnothing (state. xi_n_modes) ? state. xi_n_modes : ComplexF64[]
149150
150151 # Clebsch displacements for PENTRC (matches Fortran gpout_xclebsch)
151152 if have_xi
152- response_group[" xi_clebsch_psi" ] = state. xi_modes. clebsch_psi
153- response_group[" dxi_clebsch_psidpsi" ] = state. xi_modes. clebsch_psi1
153+ response_group[" xi_clebsch_psi" ] = state. xi_modes. clebsch_psi
154+ response_group[" dxi_clebsch_psidpsi" ] = state. xi_modes. clebsch_psi1
154155 response_group[" xi_clebsch_alpha" ] = state. xi_modes. clebsch_alpha
155156 end
156157
157158 # Contravariant displacement (from gpeq_contra, all J-weighted)
158159 if have_xi
159160 response_group[" Jxi_psi" ] = state. xi_modes. psi_J
160161 response_group[" Jxi_theta" ] = state. xi_modes. theta
161- response_group[" Jxi_zeta" ] = state. xi_modes. zeta
162+ response_group[" Jxi_zeta" ] = state. xi_modes. zeta
162163 end
163164
164165 # Covariant components (from gpeq_cova)
165166 if have_xi
166- response_group[" xi_cov_psi" ] = state. xi_modes. cova_psi
167+ response_group[" xi_cov_psi" ] = state. xi_modes. cova_psi
167168 response_group[" xi_cov_theta" ] = state. xi_modes. cova_theta
168- response_group[" xi_cov_zeta" ] = state. xi_modes. cova_zeta
169+ response_group[" xi_cov_zeta" ] = state. xi_modes. cova_zeta
169170 end
170171 if have_xi
171172 response_group[" Jxi_theta_reg" ] = state. xi_modes. theta_reg
172- response_group[" Jxi_zeta_reg" ] = state. xi_modes. zeta_reg
173+ response_group[" Jxi_zeta_reg" ] = state. xi_modes. zeta_reg
173174 end
174175 if have_b
175176 response_group[" Jb_theta_reg" ] = state. b_modes. theta_reg
176- response_group[" Jb_zeta_reg" ] = state. b_modes. zeta_reg
177- response_group[" b_cov_psi" ] = state. b_modes. cova_psi
177+ response_group[" Jb_zeta_reg" ] = state. b_modes. zeta_reg
178+ response_group[" b_cov_psi" ] = state. b_modes. cova_psi
178179 response_group[" b_cov_theta" ] = state. b_modes. cova_theta
179- response_group[" b_cov_zeta" ] = state. b_modes. cova_zeta
180+ response_group[" b_cov_zeta" ] = state. b_modes. cova_zeta
180181 end
181182
182183 # R,Z,φ cylindrical components in mode-space (from gpeq_rzphi)
183184 if have_xi
184- response_group[" xi_R" ] = state. xi_modes. R
185- response_group[" xi_Z" ] = state. xi_modes. Z
185+ response_group[" xi_R" ] = state. xi_modes. R
186+ response_group[" xi_Z" ] = state. xi_modes. Z
186187 response_group[" xi_phi" ] = state. xi_modes. phi
187188 end
188189 if have_b
189- response_group[" b_R" ] = state. b_modes. R
190- response_group[" b_Z" ] = state. b_modes. Z
190+ response_group[" b_R" ] = state. b_modes. R
191+ response_group[" b_Z" ] = state. b_modes. Z
191192 response_group[" b_phi" ] = state. b_modes. phi
192193 end
193194
194195 # Singular coupling
195196 coupling_group = haskey (pe_group, " SingularCoupling" ) ? pe_group[" SingularCoupling" ] : create_group (pe_group, " SingularCoupling" )
196197
197198 # Coupling matrices [n_rational × numpert_total]
198- ! isempty (state. C_resonant_area_weighted_field) && (coupling_group[" C_resonant_area_weighted_field" ] = state. C_resonant_area_weighted_field)
199+ ! isempty (state. C_resonant_area_weighted_field) && (coupling_group[" C_resonant_area_weighted_field" ] = state. C_resonant_area_weighted_field)
199200 ! isempty (state. C_resonant_current) && (coupling_group[" C_resonant_current" ] = state. C_resonant_current)
200- ! isempty (state. C_island_width_sq) && (coupling_group[" C_island_width_sq" ] = state. C_island_width_sq)
201+ ! isempty (state. C_island_width_sq) && (coupling_group[" C_island_width_sq" ] = state. C_island_width_sq)
201202 ! isempty (state. C_penetrated_area_weighted_field) && (coupling_group[" C_penetrated_area_weighted_field" ] = state. C_penetrated_area_weighted_field)
202- ! isempty (state. C_delta_prime) && (coupling_group[" C_Delta_prime" ] = state. C_delta_prime)
203+ ! isempty (state. C_delta_prime) && (coupling_group[" C_Delta_prime" ] = state. C_delta_prime)
203204
204205 # Applied resonant vectors [n_rational]
205- ! isempty (state. resonant_area_weighted_field) && (coupling_group[" resonant_area_weighted_field" ] = state. resonant_area_weighted_field)
206- ! isempty (state. resonant_current) && (coupling_group[" resonant_current" ] = state. resonant_current)
207- ! isempty (state. island_width_sq) && (coupling_group[" island_width_sq" ] = state. island_width_sq)
208- ! isempty (state. penetrated_area_weighted_field) && (coupling_group[" penetrated_area_weighted_field" ] = state. penetrated_area_weighted_field)
209- ! isempty (state. delta_prime) && (coupling_group[" Delta_prime" ] = state. delta_prime)
210- ! isempty (state. forcing_solution_weights) && (coupling_group[" forcing_solution_weights" ] = state. forcing_solution_weights)
206+ ! isempty (state. resonant_area_weighted_field) && (coupling_group[" resonant_area_weighted_field" ] = state. resonant_area_weighted_field)
207+ ! isempty (state. resonant_current) && (coupling_group[" resonant_current" ] = state. resonant_current)
208+ ! isempty (state. island_width_sq) && (coupling_group[" island_width_sq" ] = state. island_width_sq)
209+ ! isempty (state. penetrated_area_weighted_field) && (coupling_group[" penetrated_area_weighted_field" ] = state. penetrated_area_weighted_field)
210+ ! isempty (state. delta_prime) && (coupling_group[" Delta_prime" ] = state. delta_prime)
211+ ! isempty (state. forcing_solution_weights) && (coupling_group[" forcing_solution_weights" ] = state. forcing_solution_weights)
211212 ! isempty (state. rational_area) && (coupling_group[" rational_area" ] = state. rational_area)
212- ! isempty (state. island_half_width) && (coupling_group[" island_half_width" ] = state. island_half_width)
213+ ! isempty (state. island_half_width) && (coupling_group[" island_half_width" ] = state. island_half_width)
213214 ! isempty (state. chirikov_parameter) && (coupling_group[" chirikov_parameter" ] = state. chirikov_parameter)
214215
215216 # Metadata [n_rational]
216- ! isempty (state. rational_psi) && (coupling_group[" rational_psi" ] = state. rational_psi)
217- ! isempty (state. rational_q) && (coupling_group[" rational_q" ] = state. rational_q)
218- ! isempty (state. rational_m_res) && (coupling_group[" rational_m" ] = state. rational_m_res)
219- ! isempty (state. rational_n) && (coupling_group[" rational_n" ] = state. rational_n)
217+ ! isempty (state. rational_psi) && (coupling_group[" rational_psi" ] = state. rational_psi)
218+ ! isempty (state. rational_q) && (coupling_group[" rational_q" ] = state. rational_q)
219+ ! isempty (state. rational_m_res) && (coupling_group[" rational_m" ] = state. rational_m_res)
220+ ! isempty (state. rational_n) && (coupling_group[" rational_n" ] = state. rational_n)
220221
221222 # Energies
222223 energy_group = haskey (pe_group, " Energies" ) ? pe_group[" Energies" ] : create_group (pe_group, " Energies" )
223- energy_group[" vacuum_energy" ] = state. vacuum_energy
224- energy_group[" surface_energy" ] = state. surface_energy
225- energy_group[" plasma_energy" ] = state. plasma_energy
224+ energy_group[" vacuum_energy" ] = state. vacuum_energy
225+ energy_group[" surface_energy" ] = state. surface_energy
226+ energy_group[" plasma_energy" ] = state. plasma_energy
226227 energy_group[" toroidal_torque" ] = state. toroidal_torque
227228
228229 annotate_pe! (pe_group)
@@ -261,7 +262,8 @@ const PE_H5_ANNOTATIONS = [
261262 " Response/xi_cov_psi" => (; long_name= " covariant radial displacement ξ_ψ = ξ·e_ψ" , units= " m^2" , dims= (" psi" , " mode" ), attach= (1 => " Response/psi" ,)),
262263 " Response/xi_cov_theta" => (; long_name= " covariant poloidal displacement ξ_θ = ξ·e_θ" , units= " m^2" , dims= (" psi" , " mode" ), attach= (1 => " Response/psi" ,)),
263264 " Response/xi_cov_zeta" => (; long_name= " covariant toroidal displacement ξ_ζ = ξ·e_ζ" , units= " m^2" , dims= (" psi" , " mode" ), attach= (1 => " Response/psi" ,)),
264- " Response/xi_clebsch_psi" => (; long_name= " Clebsch displacement component ξ^ψ (PENTRC input, gpout_xclebsch convention)" , dims= (" psi" , " mode" ), attach= (1 => " Response/psi" ,)),
265+ " Response/xi_clebsch_psi" =>
266+ (; long_name= " Clebsch displacement component ξ^ψ (PENTRC input, gpout_xclebsch convention)" , dims= (" psi" , " mode" ), attach= (1 => " Response/psi" ,)),
265267 " Response/dxi_clebsch_psidpsi" =>
266268 (; long_name= " regularized ψ_N derivative of ξ^ψ (× singfac²/(singfac²+reg_spot²))" , dims= (" psi" , " mode" ), attach= (1 => " Response/psi" ,)),
267269 " Response/xi_clebsch_alpha" =>
@@ -345,7 +347,10 @@ const PE_H5_ANNOTATIONS = [
345347 " Energies/vacuum_energy" => (; long_name= " perturbed vacuum energy" , units= " J" ),
346348 " Energies/surface_energy" => (; long_name= " perturbed surface energy" , units= " J" ),
347349 " Energies/plasma_energy" => (; long_name= " perturbed plasma energy" , units= " J" ),
348- " Energies/toroidal_torque" => (; long_name= " net toroidal torque on the plasma" , units= " N*m" )
350+ " Energies/toroidal_torque" => (;
351+ long_name= " boundary-response toroidal torque −2n·Im⟨Φ_tot,Λ⁻¹Φ_tot⟩/4: equals the volume-integrated Euler-Lagrange kinetic torque for converged self-consistent solutions; distinct construction from the KineticForces NTV torque" ,
352+ units= " N*m"
353+ )
349354]
350355
351356# Attach long_name/units/dims + dimension scales (declared in-table) to the
0 commit comments