2 use,
intrinsic :: ieee_arithmetic, only: ieee_value,ieee_quiet_nan, &
33 double precision,
parameter,
private :: trace_q_min=2.d0
79 private :: trace_summary_seed,trace_summary_multi
80 private :: trace_summary_twist_seed,trace_summary_twist_multi
81 private :: trace_summary_mapping_seed,trace_summary_mapping_multi
82 private :: trace_summary_topology_multi
83 private :: trace_summary_validate,trace_summary_init_result
84 private :: trace_summary_init_twist_result
85 private :: trace_summary_init_mapping_result
86 private :: trace_summary_init_topology_result
87 private :: trace_summary_locate_seed,trace_summary_trace_seed
88 private :: trace_summary_trace_twist_seed
89 private :: trace_summary_init_state,trace_summary_advance_state
90 private :: trace_summary_trace_state_to_end,trace_summary_trace_states_grouped
91 private :: trace_summary_advance_state_in_grid
92 private :: trace_summary_rk2_step,trace_summary_rk45_cartesian_step
93 private :: trace_summary_rk45_spherical_step
94 private :: trace_intersect_domain
95 private :: trace_summary_accumulate_twist,trace_twist_density_at_point
96 private :: trace_tangent_accumulate_twist,trace_tangent_fill_twist_result
97 private :: sample_b_curlb_at_point
98 private :: sample_b_curlb_spherical_at_point
99 private :: sample_b_at_point,trace_summary_fill_mapping
100 private :: trace_total_b_at_cell,trace_bhat_at_cell
101 private :: sample_bhat_gradbhat_at_point
102 private :: sample_bhat_gradbhat_cellfd_at_point
103 private :: sample_bhat_gradbhat_xeps_at_point
104 private :: sample_bhat_gradbhat_interpderiv_at_point
105 private :: trace_debug_locate_point,trace_locate_point_with_hint
106 private :: trace_tangent_rhs
107 private :: trace_advance_tangent_state_rk2,trace_project_to_perp_bhat
108 private :: trace_tangent_rk2_trial,trace_endpoint_b_bhat
109 private :: trace_tangent_rk2_trial_from_rhs
110 private :: trace_tangent_state_advance_in_grid_rk45_cartesian
111 private :: trace_tangent_rk45_cartesian_step
112 private :: trace_tangent_rhs_cartesian_located
113 private :: trace_tangent_rk45_cartesian_finish_boundary
114 private :: trace_tangent_trace_states_grouped_rk45_spherical
115 private :: trace_tangent_state_advance_in_grid_rk45_spherical
116 private :: trace_tangent_rk45_spherical_step
117 private :: trace_tangent_rk45_spherical_finish_boundary
118 private :: trace_q0_finalize_from_states
119 private :: trace_sample_b_on_domain_face_limit
120 private :: trace_locate_face_limit_grid
121 private :: trace_face_normal,trace_project_to_boundary_face
122 private :: trace_make_perp_basis,trace_debug_nan
123 private :: trace_face_from_dim_side,trace_face_bn,trace_face_is_boundary
124 private :: trace_boundary_face_at_point
125 private :: trace_periodic_phi,trace_physical_dimension
126 private :: trace_normalize_position,trace_clamp_sample_position
127 private :: trace_coordinate_in_domain,trace_spherical_corner_slopes
128 private :: trace_is_supported_summary_geometry
129 private :: trace_effective_step,trace_spherical_metric_ok
130 private :: trace_segment_length
131 private :: trace_summary_twist_status_from_states
132 private :: trace_init_qperp_result,trace_qperp_single_core
133 private :: trace_qperp_compute_q0_scalars
134 private :: trace_qperp_project_to_boundary_face
135 private :: trace_tangent_state_init
136 private :: trace_tangent_trace_states_grouped
137 private :: trace_tangent_state_advance_in_grid
138 private :: trace_tangent_state_finalize_boundary
139 private :: trace_qperp_prepare_seed_result
140 private :: trace_qperp_compute_scalars
141 private :: trace_qperp_finalize_from_states
142 private :: trace_spherical_rmin_q_prepare_seed_result
143 private :: trace_spherical_rmin_q_finalize_from_states
144 private :: trace_spherical_radial_q_finalize_from_states
145 private :: trace_spherical_radial_q_face_pair_admitted
146 private :: trace_spherical_radial_endpoint_matrix
147 private :: trace_spherical_radial_project_to_surface
148 private :: trace_spherical_qperp_prepare_seed_result
149 private :: trace_spherical_qperp_finalize_from_states
150 private :: trace_spherical_qperp_compute_from_states
151 private :: trace_spherical_q_from_endpoint_matrices
152 private :: trace_spherical_basis,trace_spherical_coord_to_cart
153 private :: trace_cart_to_spherical_coord
154 private :: trace_spherical_sample_b_bhat_cart
155 private :: trace_spherical_sample_bhat_gradbhat_covariant
156 private :: trace_spherical_sample_bhat_gradbhat_cartfd
157 private :: trace_spherical_bhat_cart_to_rhs
158 private :: trace_spherical_endpoint_b_bhat
159 private :: trace_spherical_face_probe_coord
160 private :: trace_spherical_physical_cell_scale
161 private :: trace_spherical_cell_scale_from_widths
162 private :: trace_spherical_interp_ctx_build
163 private :: trace_spherical_interp_ctx_build_cached
164 private :: trace_spherical_effective_step_ctx
165 private :: trace_spherical_sample_bsph_ctx
166 private :: trace_spherical_sample_b_bhat_cart_ctx
167 private :: trace_spherical_sample_cached_curlb_ctx
168 private :: trace_spherical_sample_bhat_gradbhat_covariant_ctx
169 private :: get_k_spherical_ctx
170 private :: trace_spherical_interp_ctx_fill
171 private :: trace_spherical_interp_ctx_load_bcorners
172 private :: trace_interp_weights_block,trace_interp_index_3d
173 private :: trace_interp_weights_block_near,trace_interp_index_3d_near
174 private :: trace_spherical_local_cell_widths
175 private :: trace_spherical_profile_add_count
176 private :: trace_spherical_profile_add_time
177 private :: trace_spherical_profile_note_trace_steps
178 private :: trace_spherical_profile_time
179 private :: trace_cartesian_like_geometry,trace_rk45_position_integrator
180 private :: trace_cartesian_rhs_bhat
181 private :: trace_cartesian_local_cell_size
182 private :: trace_rk45_try_boundary_finish
183 private :: trace_rk2_stats_note_direction
184 private :: trace_rk2_stats_note_step
185 private :: trace_rk2_stats_note_completion
186 private :: trace_rk2_stats_note_step_limit
187 private :: trace_rk2_stats_note_group_iteration
188 private :: trace_rk2_stats_note_grid_group
189 private :: trace_rk2_stats_note_rhs
190 private :: trace_rk2_stats_add_grouped_time
191 private :: trace_rk45_stats_note_direction
192 private :: trace_rk45_stats_note_attempt
193 private :: trace_rk45_stats_note_tangent_error
195 type,
private :: trace_sph_interp_ctx
196 logical :: valid=.false.
199 double precision :: x(3)=zero
200 double precision :: xd(3)=zero
201 double precision :: dxc(3)=zero
202 double precision :: w(0:1,3)=zero
203 double precision :: dxloc(3)=zero
204 double precision :: r=zero,theta=zero,phi=zero
205 double precision :: sin_theta=zero,cos_theta=zero
206 double precision :: sin_phi=zero,cos_phi=zero
207 double precision :: rsin_theta=zero
208 double precision :: h_local=zero
209 logical :: bcorner_valid=.false.
210 double precision :: bcorner(0:1,0:1,0:1,3)=zero
211 logical :: slopes_valid=.false.
212 double precision :: slopes(0:1,0:1,0:1,3,3)=zero
213 end type trace_sph_interp_ctx
215 type,
private :: trace_spherical_curl_cache_block
216 double precision,
dimension(:^D&,:),
allocatable :: current
217 logical :: ready=.false.
218 end type trace_spherical_curl_cache_block
220 type(trace_spherical_curl_cache_block),
allocatable,
private :: &
221 trace_spherical_curl_cache(:)
222 logical,
private :: trace_spherical_curl_cache_ready=.false.
224 integer,
parameter,
private :: trace_step_control_fixed=0
225 integer,
parameter,
private :: trace_step_control_cell_fraction=1
226 integer,
private :: trace_step_control_mode=trace_step_control_fixed
227 double precision,
private :: trace_step_fraction=0.1d0
228 double precision,
private :: trace_step_min=0.d0
230 integer,
parameter,
private :: trace_integrator_rk2=0
231 integer,
parameter,
private :: trace_integrator_rk45_cartesian=1
232 integer,
parameter,
private :: trace_integrator_rk45_spherical=2
233 integer,
parameter,
private :: trace_tangent_group_rk2_general=1
234 integer,
parameter,
private :: trace_tangent_group_rk2_short_boundary=2
235 integer,
parameter,
private :: trace_tangent_group_rk45_cartesian=3
236 integer,
parameter,
private :: trace_rk45_reject_error=1
237 integer,
parameter,
private :: trace_rk45_reject_stage_failure=2
238 integer,
parameter,
private :: trace_rk45_reject_stage_outside=3
239 integer,
parameter,
private :: trace_rk45_reject_boundary=4
240 integer,
parameter,
private :: trace_rk45_reject_tangent_error=5
241 integer,
private :: trace_integrator_mode=trace_integrator_rk2
242 double precision,
private :: trace_rk45_atol=1.
d-8
243 double precision,
private :: trace_rk45_rtol=1.
d-6
244 double precision,
private :: trace_rk45_safety=0.9d0
245 double precision,
private :: trace_rk45_min_shrink=0.2d0
246 double precision,
private :: trace_rk45_max_grow=5.d0
247 double precision,
private :: trace_rk45_tangent_floor=1.d0
248 double precision,
private :: trace_rk45_tangent_rtol=2.
d-5
249 logical,
private :: trace_rk2_stats_enabled=.false.
250 integer(kind=8),
private :: trace_rk2_directions=0_8
251 integer(kind=8),
private :: trace_rk2_completed_directions=0_8
252 integer(kind=8),
private :: trace_rk2_total_steps=0_8
253 integer(kind=8),
private :: trace_rk2_boundary_completions=0_8
254 integer(kind=8),
private :: trace_rk2_max_steps_failures=0_8
255 integer(kind=8),
private :: trace_rk2_domain_limited_steps=0_8
256 integer(kind=8),
private :: trace_rk2_grid_transition_steps=0_8
257 integer(kind=8),
private :: trace_rk2_cell_fraction_limited=0_8
258 integer(kind=8),
private :: trace_rk2_dl_limited=0_8
259 integer(kind=8),
private :: trace_rk2_dl_min_limited=0_8
260 integer(kind=8),
private :: trace_rk2_group_iterations=0_8
261 integer(kind=8),
private :: trace_rk2_grid_groups=0_8
262 integer(kind=8),
private :: trace_rk2_group_state_sum=0_8
263 integer(kind=8),
private :: trace_rk2_group_state_max=0_8
264 integer(kind=8),
private :: trace_rk2_rhs_calls=0_8
265 double precision,
private :: trace_rk2_sum_step_length=0.d0
266 double precision,
private :: trace_rk2_min_step_length=huge(one)
267 double precision,
private :: trace_rk2_max_step_length=0.d0
268 double precision,
private :: trace_rk2_grouped_time=0.d0
269 integer(kind=8),
private :: trace_rk2_max_steps_per_direction=0_8
270 logical,
private :: trace_rk45_stats_enabled=.false.
271 integer(kind=8),
private :: trace_rk45_directions=0_8
272 integer(kind=8),
private :: trace_rk45_attempts=0_8
273 integer(kind=8),
private :: trace_rk45_accepted=0_8
274 integer(kind=8),
private :: trace_rk45_rejected=0_8
275 integer(kind=8),
private :: trace_rk45_rejected_error=0_8
276 integer(kind=8),
private :: trace_rk45_rejected_position_error=0_8
277 integer(kind=8),
private :: trace_rk45_rejected_tangent_error=0_8
278 integer(kind=8),
private :: trace_rk45_rejected_stage_failure=0_8
279 integer(kind=8),
private :: trace_rk45_rejected_stage_outside=0_8
280 integer(kind=8),
private :: trace_rk45_rejected_boundary=0_8
281 integer(kind=8),
private :: trace_rk45_boundary_limited=0_8
282 double precision,
private :: trace_rk45_sum_accepted_h=0.d0
283 double precision,
private :: trace_rk45_min_accepted_h=huge(one)
284 double precision,
private :: trace_rk45_max_accepted_h=0.d0
285 integer(kind=8),
private :: trace_rk45_tangent_error_samples=0_8
286 integer(kind=8),
private :: trace_rk45_tangent_would_reject=0_8
287 double precision,
private :: trace_rk45_sum_tangent_error_ratio=0.d0
288 double precision,
private :: trace_rk45_max_tangent_error_ratio=0.d0
289 double precision,
private :: trace_rk45_max_tangent_u_error_ratio=0.d0
290 double precision,
private :: trace_rk45_max_tangent_v_error_ratio=0.d0
291 double precision,
private :: trace_rk45_max_position_error_ratio=0.d0
293 logical,
private :: trace_spherical_profile_enabled=.false.
294 logical,
parameter,
private :: trace_spherical_profile_timers=.false.
295 integer(kind=8),
private :: trace_profile_seeds=0_8
296 integer(kind=8),
private :: trace_profile_directions=0_8
297 integer(kind=8),
private :: trace_profile_steps=0_8
298 integer(kind=8),
private :: trace_profile_boundary_events=0_8
299 integer(kind=8),
private :: trace_profile_endpoint_finalizations=0_8
300 integer(kind=8),
private :: trace_profile_context_requests=0_8
301 integer(kind=8),
private :: trace_profile_same_cell_hits=0_8
302 integer(kind=8),
private :: trace_profile_same_grid_hits=0_8
303 integer(kind=8),
private :: trace_profile_full_context_builds=0_8
304 integer(kind=8),
private :: trace_profile_context_failures=0_8
305 integer(kind=8),
private :: trace_profile_cache_invalidations=0_8
306 integer(kind=8),
private :: trace_profile_b_samples=0_8
307 integer(kind=8),
private :: trace_profile_curl_samples=0_8
308 integer(kind=8),
private :: trace_profile_grad_samples=0_8
309 integer(kind=8),
private :: trace_profile_grad_success=0_8
310 integer(kind=8),
private :: trace_profile_grad_fallbacks=0_8
311 integer(kind=8),
private :: trace_profile_b_corner_loads=0_8
312 integer(kind=8),
private :: trace_profile_b_corner_hits=0_8
313 integer(kind=8),
private :: trace_profile_hlocal_evals=0_8
314 integer(kind=8),
private :: trace_profile_face_probes=0_8
315 integer(kind=8),
private :: trace_profile_tangent_systems=0_8
316 integer(kind=8),
private :: trace_profile_q_tangent_systems=0_8
317 integer(kind=8),
private :: trace_profile_qperp_tangent_systems=0_8
318 integer(kind=8),
private :: trace_profile_combined_tangent_systems=0_8
319 integer(kind=8),
private :: trace_profile_max_steps_per_trace=0_8
320 double precision,
private :: trace_profile_time_context=0.d0
321 double precision,
private :: trace_profile_time_b_interp=0.d0
322 double precision,
private :: trace_profile_time_curl_interp=0.d0
323 double precision,
private :: trace_profile_time_grad_bhat=0.d0
324 double precision,
private :: trace_profile_time_step=0.d0
325 double precision,
private :: trace_profile_time_tangent=0.d0
327 type,
private :: trace_summary_state
328 double precision :: x(
ndim)
329 double precision :: footpoint(
ndim)
330 double precision :: length
331 double precision :: twist
334 integer :: twist_status
340 logical :: accumulate_twist
341 double precision :: rk45_h
342 type(trace_sph_interp_ctx) :: sph_cache
343 end type trace_summary_state
345 type,
private :: trace_tangent_state
351 double precision :: x(
ndim)
352 double precision :: u(
ndim)
353 double precision :: v(
ndim)
354 double precision :: p(
ndim)
355 double precision :: q(
ndim)
356 double precision :: length
357 double precision :: twist
361 integer :: twist_status
363 double precision :: endpoint(
ndim)
364 double precision :: endpoint_b(
ndim)
365 double precision :: endpoint_bhat(
ndim)
366 double precision :: u_perp(
ndim)
367 double precision :: v_perp(
ndim)
368 double precision :: p_perp(
ndim)
369 double precision :: q_perp(
ndim)
370 double precision :: rk45_h
371 logical :: accumulate_twist
372 type(trace_sph_interp_ctx) :: sph_cache
373 end type trace_tangent_state
377 double precision :: forward_footpoint(
ndim)
378 double precision :: backward_footpoint(
ndim)
379 double precision :: forward_length
380 double precision :: backward_length
381 double precision :: total_length
382 integer :: forward_nstep
383 integer :: backward_nstep
384 integer :: forward_status
385 integer :: backward_status
390 double precision :: forward_twist
391 double precision :: backward_twist
392 double precision :: total_twist
393 logical :: valid_twist
394 integer :: status_twist
399 double precision :: source_b(3)
400 double precision :: forward_footpoint(
ndim)
401 double precision :: backward_footpoint(
ndim)
402 double precision :: forward_b(3)
403 double precision :: backward_b(3)
404 double precision :: forward_length
405 double precision :: backward_length
406 double precision :: source_bn
407 double precision :: forward_bn
408 double precision :: backward_bn
409 integer :: forward_face
410 integer :: backward_face
411 integer :: forward_status
412 integer :: backward_status
418 double precision :: qperp
419 double precision :: logqperp
420 double precision :: n2
421 double precision :: bfactor
422 double precision :: q0
423 double precision :: logq0
424 double precision :: qperp0
425 double precision :: logqperp0
426 double precision :: n2_qperp0
427 double precision :: bfactor_qperp0
428 double precision :: forward_bn_q0
429 double precision :: backward_bn_q0
430 double precision :: b_seed(
ndim)
431 double precision :: bhat_seed(
ndim)
432 double precision :: forward_endpoint(
ndim)
433 double precision :: backward_endpoint(
ndim)
434 double precision :: forward_b(
ndim)
435 double precision :: backward_b(
ndim)
436 double precision :: forward_bhat(
ndim)
437 double precision :: backward_bhat(
ndim)
438 double precision :: forward_length
439 double precision :: backward_length
440 integer :: forward_nstep
441 integer :: backward_nstep
444 double precision :: u_forward_perp(
ndim)
445 double precision :: v_forward_perp(
ndim)
446 double precision :: u_backward_perp(
ndim)
447 double precision :: v_backward_perp(
ndim)
448 integer :: forward_face
449 integer :: backward_face
450 integer :: forward_status
451 integer :: backward_status
453 integer :: status_qperp0
457 logical :: valid_qperp0
462 double precision :: length_forward
463 double precision :: length_backward
464 double precision :: length_total
465 double precision :: twist_forward
466 double precision :: twist_backward
467 double precision :: twist_total
468 double precision :: forward_endpoint(
ndim)
469 double precision :: backward_endpoint(
ndim)
470 integer :: forward_nstep
471 integer :: backward_nstep
472 integer :: forward_face
473 integer :: backward_face
474 integer :: forward_status
475 integer :: backward_status
476 double precision :: map_forward_endpoint(
ndim)
477 double precision :: map_backward_endpoint(
ndim)
478 double precision :: map_forward_length
479 double precision :: map_backward_length
480 integer :: map_forward_face
481 integer :: map_backward_face
482 integer :: map_forward_status
483 integer :: map_backward_status
484 double precision :: source_b(3)
485 double precision :: forward_b(3)
486 double precision :: backward_b(3)
487 double precision :: source_bn
488 double precision :: forward_bn
489 double precision :: backward_bn
491 logical :: has_mapping
492 logical :: valid_twist
494 integer :: status_twist
501 character(len=*),
intent(in) :: mode
502 double precision,
intent(in) :: step_fraction,step_min
504 character(len=len(mode)) :: mode_lc
509 code=iachar(mode_lc(i:i))
510 if (code>=iachar(
'A') .and. code<=iachar(
'Z'))
then
511 mode_lc(i:i)=achar(code+iachar(
'a')-iachar(
'A'))
515 select case (trim(mode_lc))
516 case (
'cell_fraction')
517 trace_step_control_mode=trace_step_control_cell_fraction
519 trace_step_control_mode=trace_step_control_fixed
521 trace_step_fraction=step_fraction
522 trace_step_min=max(zero,step_min)
526 max_grow,tangent_floor,tangent_rtol)
527 character(len=*),
intent(in) :: mode
528 double precision,
intent(in) :: atol,rtol,safety,min_shrink,max_grow
529 double precision,
intent(in) :: tangent_floor,tangent_rtol
531 character(len=len(mode)) :: mode_lc
536 code=iachar(mode_lc(i:i))
537 if (code>=iachar(
'A') .and. code<=iachar(
'Z'))
then
538 mode_lc(i:i)=achar(code+iachar(
'a')-iachar(
'A'))
542 select case (trim(mode_lc))
543 case (
'rk45_cartesian')
544 trace_integrator_mode=trace_integrator_rk45_cartesian
545 case (
'rk45_spherical')
546 trace_integrator_mode=trace_integrator_rk45_spherical
548 trace_integrator_mode=trace_integrator_rk2
550 trace_rk45_atol=max(atol,zero)
551 trace_rk45_rtol=max(rtol,zero)
552 trace_rk45_safety=max(0.1d0,min(safety,one))
553 trace_rk45_min_shrink=max(0.01d0,min(min_shrink,one))
554 trace_rk45_max_grow=max(one,max_grow)
555 trace_rk45_tangent_floor=max(tangent_floor,smalldouble)
556 trace_rk45_tangent_rtol=max(tangent_rtol,smalldouble)
560 logical,
intent(in) :: enabled
562 trace_rk2_stats_enabled=enabled
566 trace_rk2_directions=0_8
567 trace_rk2_completed_directions=0_8
568 trace_rk2_total_steps=0_8
569 trace_rk2_boundary_completions=0_8
570 trace_rk2_max_steps_failures=0_8
571 trace_rk2_domain_limited_steps=0_8
572 trace_rk2_grid_transition_steps=0_8
573 trace_rk2_cell_fraction_limited=0_8
574 trace_rk2_dl_limited=0_8
575 trace_rk2_dl_min_limited=0_8
576 trace_rk2_group_iterations=0_8
577 trace_rk2_grid_groups=0_8
578 trace_rk2_group_state_sum=0_8
579 trace_rk2_group_state_max=0_8
580 trace_rk2_rhs_calls=0_8
581 trace_rk2_sum_step_length=0.d0
582 trace_rk2_min_step_length=huge(one)
583 trace_rk2_max_step_length=0.d0
584 trace_rk2_grouped_time=0.d0
585 trace_rk2_max_steps_per_direction=0_8
589 character(len=*),
intent(in) :: label
591 double precision :: mean_group_size,mean_h,mean_steps_per_direction
593 if (.not.trace_rk2_stats_enabled)
return
596 if (trace_rk2_total_steps>0_8)
then
597 mean_h=trace_rk2_sum_step_length/dble(trace_rk2_total_steps)
599 mean_steps_per_direction=zero
600 if (trace_rk2_completed_directions>0_8)
then
601 mean_steps_per_direction=dble(trace_rk2_total_steps)/ &
602 dble(trace_rk2_completed_directions)
605 if (trace_rk2_grid_groups>0_8)
then
606 mean_group_size=dble(trace_rk2_group_state_sum)/ &
607 dble(trace_rk2_grid_groups)
610 write(*,
'(a)')
'[mt_rk2] Cartesian field-line RK2 summary: '// &
612 write(*,
'(a,i0)')
' traced_directions: ',trace_rk2_directions
613 write(*,
'(a,i0)')
' completed_directions: ', &
614 trace_rk2_completed_directions
615 write(*,
'(a,i0)')
' total_steps: ',trace_rk2_total_steps
616 write(*,
'(a,es12.4)')
' mean_step_length: ',mean_h
617 if (trace_rk2_total_steps>0_8)
then
618 write(*,
'(a,es12.4)')
' min_step_length: ', &
619 trace_rk2_min_step_length
620 write(*,
'(a,es12.4)')
' max_step_length: ', &
621 trace_rk2_max_step_length
623 write(*,
'(a,es12.4)')
' mean_steps_per_direction: ', &
624 mean_steps_per_direction
625 write(*,
'(a,i0)')
' max_steps_per_direction: ', &
626 trace_rk2_max_steps_per_direction
627 write(*,
'(a,i0)')
' boundary_completions: ', &
628 trace_rk2_boundary_completions
629 write(*,
'(a,i0)')
' max_steps_failures: ', &
630 trace_rk2_max_steps_failures
631 write(*,
'(a,i0)')
' domain_boundary_limited_steps: ', &
632 trace_rk2_domain_limited_steps
633 write(*,
'(a,i0)')
' block_grid_clipped_steps: 0'
634 write(*,
'(a,i0)')
' grid_transition_steps: ', &
635 trace_rk2_grid_transition_steps
636 write(*,
'(a,i0)')
' cell_fraction_limited_evals: ', &
637 trace_rk2_cell_fraction_limited
638 write(*,
'(a,i0)')
' dL_cap_limited_evals: ',trace_rk2_dl_limited
639 write(*,
'(a,i0)')
' dL_min_limited_evals: ',trace_rk2_dl_min_limited
640 write(*,
'(a,i0)')
' grouped_driver_outer_iterations: ', &
641 trace_rk2_group_iterations
642 write(*,
'(a,i0)')
' grouped_driver_parallel_batches: ', &
643 trace_rk2_grid_groups
644 write(*,
'(a,es12.4)')
' grouped_driver_mean_batch_size: ', &
646 write(*,
'(a,i0)')
' grouped_driver_max_batch_size: ', &
647 trace_rk2_group_state_max
648 write(*,
'(a,es12.4)')
' grouped_driver_cpu_time: ', &
649 trace_rk2_grouped_time
650 write(*,
'(a,i0)')
' trace_tangent_rhs_calls: ',trace_rk2_rhs_calls
651 write(*,
'(a)')
' note: Cartesian RK2 grouped tracing does not clip '// &
652 'steps to AMR block/grid boundaries; grid changes are counted after '// &
653 'accepted full steps.'
656 subroutine trace_rk2_stats_note_direction()
657 if (.not.trace_rk2_stats_enabled)
return
659 trace_rk2_directions=trace_rk2_directions+1_8
661 end subroutine trace_rk2_stats_note_direction
663 subroutine trace_rk2_stats_note_step(h,domain_limited,grid_transition)
664 double precision,
intent(in) :: h
665 logical,
intent(in) :: domain_limited,grid_transition
667 if (.not.trace_rk2_stats_enabled)
return
669 trace_rk2_total_steps=trace_rk2_total_steps+1_8
670 trace_rk2_sum_step_length=trace_rk2_sum_step_length+abs(h)
671 trace_rk2_min_step_length=min(trace_rk2_min_step_length,abs(h))
672 trace_rk2_max_step_length=max(trace_rk2_max_step_length,abs(h))
673 if (domain_limited) trace_rk2_domain_limited_steps= &
674 trace_rk2_domain_limited_steps+1_8
675 if (grid_transition) trace_rk2_grid_transition_steps= &
676 trace_rk2_grid_transition_steps+1_8
678 end subroutine trace_rk2_stats_note_step
680 subroutine trace_rk2_stats_note_completion(status,nstep)
681 integer,
intent(in) :: status,
nstep
683 if (.not.trace_rk2_stats_enabled)
return
685 trace_rk2_completed_directions=trace_rk2_completed_directions+1_8
686 trace_rk2_max_steps_per_direction=max( &
687 trace_rk2_max_steps_per_direction,int(
nstep,kind=8))
690 trace_rk2_boundary_completions=trace_rk2_boundary_completions+1_8
692 trace_rk2_max_steps_failures=trace_rk2_max_steps_failures+1_8
695 end subroutine trace_rk2_stats_note_completion
697 subroutine trace_rk2_stats_note_step_limit(step_cap,cell_step,actual_step)
698 double precision,
intent(in) :: step_cap,cell_step,actual_step
700 double precision :: tol
702 if (.not.trace_rk2_stats_enabled)
return
703 tol=100.d0*epsilon(one)*max(one,step_cap,cell_step,actual_step)
705 if (actual_step>=step_cap-tol)
then
706 trace_rk2_dl_limited=trace_rk2_dl_limited+1_8
707 else if (trace_step_min>zero .and. actual_step>=trace_step_min-tol .and. &
708 actual_step>cell_step+tol)
then
709 trace_rk2_dl_min_limited=trace_rk2_dl_min_limited+1_8
711 trace_rk2_cell_fraction_limited=trace_rk2_cell_fraction_limited+1_8
714 end subroutine trace_rk2_stats_note_step_limit
716 subroutine trace_rk2_stats_note_group_iteration()
717 if (.not.trace_rk2_stats_enabled)
return
719 trace_rk2_group_iterations=trace_rk2_group_iterations+1_8
721 end subroutine trace_rk2_stats_note_group_iteration
723 subroutine trace_rk2_stats_note_grid_group(group_size)
724 integer,
intent(in) :: group_size
726 if (.not.trace_rk2_stats_enabled)
return
728 trace_rk2_grid_groups=trace_rk2_grid_groups+1_8
729 trace_rk2_group_state_sum=trace_rk2_group_state_sum+ &
730 int(group_size,kind=8)
731 trace_rk2_group_state_max=max(trace_rk2_group_state_max, &
732 int(group_size,kind=8))
734 end subroutine trace_rk2_stats_note_grid_group
736 subroutine trace_rk2_stats_note_rhs()
737 if (.not.trace_rk2_stats_enabled)
return
739 trace_rk2_rhs_calls=trace_rk2_rhs_calls+1_8
740 end subroutine trace_rk2_stats_note_rhs
742 subroutine trace_rk2_stats_add_grouped_time(dt)
743 double precision,
intent(in) ::
dt
745 if (.not.trace_rk2_stats_enabled)
return
747 trace_rk2_grouped_time=trace_rk2_grouped_time+
dt
749 end subroutine trace_rk2_stats_add_grouped_time
752 logical,
intent(in) :: enabled
754 trace_rk45_stats_enabled=enabled
758 trace_rk45_directions=0_8
759 trace_rk45_attempts=0_8
760 trace_rk45_accepted=0_8
761 trace_rk45_rejected=0_8
762 trace_rk45_rejected_error=0_8
763 trace_rk45_rejected_position_error=0_8
764 trace_rk45_rejected_tangent_error=0_8
765 trace_rk45_rejected_stage_failure=0_8
766 trace_rk45_rejected_stage_outside=0_8
767 trace_rk45_rejected_boundary=0_8
768 trace_rk45_boundary_limited=0_8
769 trace_rk45_sum_accepted_h=0.d0
770 trace_rk45_min_accepted_h=huge(one)
771 trace_rk45_max_accepted_h=0.d0
772 trace_rk45_tangent_error_samples=0_8
773 trace_rk45_tangent_would_reject=0_8
774 trace_rk45_sum_tangent_error_ratio=0.d0
775 trace_rk45_max_tangent_error_ratio=0.d0
776 trace_rk45_max_tangent_u_error_ratio=0.d0
777 trace_rk45_max_tangent_v_error_ratio=0.d0
778 trace_rk45_max_position_error_ratio=0.d0
782 character(len=*),
intent(in) :: label
784 double precision :: mean_h,mean_reject_per_trace,mean_tangent_error
786 if (.not.trace_rk45_stats_enabled)
return
787 if (trace_integrator_mode/=trace_integrator_rk45_cartesian .and. &
788 trace_integrator_mode/=trace_integrator_rk45_spherical)
return
791 if (trace_rk45_accepted>0_8)
then
792 mean_h=trace_rk45_sum_accepted_h/dble(trace_rk45_accepted)
794 mean_reject_per_trace=zero
795 if (trace_rk45_directions>0_8)
then
796 mean_reject_per_trace=dble(trace_rk45_rejected)/dble(trace_rk45_directions)
799 select case (trace_integrator_mode)
800 case (trace_integrator_rk45_cartesian)
801 write(*,
'(a)')
'[mt_rk45] Cartesian field-line RK45 summary: '// &
803 case (trace_integrator_rk45_spherical)
804 write(*,
'(a)')
'[mt_rk45] Spherical field-line RK45 summary: '// &
807 write(*,
'(a,i0)')
' traced_directions: ',trace_rk45_directions
808 write(*,
'(a,i0)')
' attempts: ',trace_rk45_attempts
809 write(*,
'(a,i0)')
' accepted_steps: ',trace_rk45_accepted
810 write(*,
'(a,i0)')
' rejected_steps: ',trace_rk45_rejected
811 write(*,
'(a,i0)')
' rejected_error_steps: ', &
812 trace_rk45_rejected_error
813 write(*,
'(a,i0)')
' rejected_position_error_steps: ', &
814 trace_rk45_rejected_position_error
815 write(*,
'(a,i0)')
' rejected_tangent_error_steps: ', &
816 trace_rk45_rejected_tangent_error
817 write(*,
'(a,i0)')
' rejected_stage_failure_steps: ', &
818 trace_rk45_rejected_stage_failure
819 write(*,
'(a,i0)')
' rejected_stage_outside_steps: ', &
820 trace_rk45_rejected_stage_outside
821 write(*,
'(a,i0)')
' rejected_boundary_steps: ', &
822 trace_rk45_rejected_boundary
823 write(*,
'(a,es12.4)')
' rejected_steps_per_direction: ', &
824 mean_reject_per_trace
825 write(*,
'(a,i0)')
' boundary_limited_steps: ', &
826 trace_rk45_boundary_limited
827 write(*,
'(a,es12.4)')
' mean_accepted_step: ',mean_h
828 if (trace_rk45_accepted>0_8)
then
829 write(*,
'(a,es12.4)')
' min_accepted_step: ', &
830 trace_rk45_min_accepted_h
831 write(*,
'(a,es12.4)')
' max_accepted_step: ', &
832 trace_rk45_max_accepted_h
834 if (trace_rk45_tangent_error_samples>0_8)
then
835 write(*,
'(a)')
' error_control_mode: position_tangent'
836 mean_tangent_error=trace_rk45_sum_tangent_error_ratio/ &
837 dble(trace_rk45_tangent_error_samples)
838 write(*,
'(a,i0)')
' tangent_error_samples: ', &
839 trace_rk45_tangent_error_samples
840 write(*,
'(a,i0)')
' tangent_would_reject_steps: ', &
841 trace_rk45_tangent_would_reject
842 write(*,
'(a,es12.4)')
' max_position_error_ratio: ', &
843 trace_rk45_max_position_error_ratio
844 write(*,
'(a,es12.4)')
' mean_tangent_error_ratio: ', &
846 write(*,
'(a,es12.4)')
' max_tangent_error_ratio: ', &
847 trace_rk45_max_tangent_error_ratio
848 write(*,
'(a,es12.4)')
' max_tangent_u_error_ratio: ', &
849 trace_rk45_max_tangent_u_error_ratio
850 write(*,
'(a,es12.4)')
' max_tangent_v_error_ratio: ', &
851 trace_rk45_max_tangent_v_error_ratio
852 write(*,
'(a,es12.4)')
' tangent_error_rtol: ', &
853 trace_rk45_tangent_rtol
854 write(*,
'(a,es12.4)')
' tangent_error_floor: ', &
855 trace_rk45_tangent_floor
856 write(*,
'(a)')
' tangent_error_note: standard-logQ tangent '// &
857 'traces use position+tangent RK45 accept/reject.'
859 write(*,
'(a)')
' error_control_mode: position'
861 write(*,
'(a)')
' note: this experimental RK45 mode traces '// &
862 'position/length/twist and tangent-transport Q products where enabled.'
865 subroutine trace_rk45_stats_note_direction()
866 if (.not.trace_rk45_stats_enabled)
return
867 if (trace_integrator_mode/=trace_integrator_rk45_cartesian .and. &
868 trace_integrator_mode/=trace_integrator_rk45_spherical)
return
870 trace_rk45_directions=trace_rk45_directions+1_8
872 end subroutine trace_rk45_stats_note_direction
874 subroutine trace_rk45_stats_note_attempt(accepted,boundary_limited,h, &
876 logical,
intent(in) :: accepted,boundary_limited
877 double precision,
intent(in) :: h
878 integer,
intent(in),
optional :: reject_reason
880 if (.not.trace_rk45_stats_enabled)
return
881 if (trace_integrator_mode/=trace_integrator_rk45_cartesian .and. &
882 trace_integrator_mode/=trace_integrator_rk45_spherical)
return
884 trace_rk45_attempts=trace_rk45_attempts+1_8
886 trace_rk45_accepted=trace_rk45_accepted+1_8
887 trace_rk45_sum_accepted_h=trace_rk45_sum_accepted_h+abs(h)
888 trace_rk45_min_accepted_h=min(trace_rk45_min_accepted_h,abs(h))
889 trace_rk45_max_accepted_h=max(trace_rk45_max_accepted_h,abs(h))
890 if (boundary_limited) trace_rk45_boundary_limited= &
891 trace_rk45_boundary_limited+1_8
893 trace_rk45_rejected=trace_rk45_rejected+1_8
894 if (
present(reject_reason))
then
895 select case (reject_reason)
896 case (trace_rk45_reject_error)
897 trace_rk45_rejected_error=trace_rk45_rejected_error+1_8
898 trace_rk45_rejected_position_error= &
899 trace_rk45_rejected_position_error+1_8
900 case (trace_rk45_reject_tangent_error)
901 trace_rk45_rejected_error=trace_rk45_rejected_error+1_8
902 trace_rk45_rejected_tangent_error= &
903 trace_rk45_rejected_tangent_error+1_8
904 case (trace_rk45_reject_stage_failure)
905 trace_rk45_rejected_stage_failure= &
906 trace_rk45_rejected_stage_failure+1_8
907 case (trace_rk45_reject_stage_outside)
908 trace_rk45_rejected_stage_outside= &
909 trace_rk45_rejected_stage_outside+1_8
910 case (trace_rk45_reject_boundary)
911 trace_rk45_rejected_boundary=trace_rk45_rejected_boundary+1_8
916 end subroutine trace_rk45_stats_note_attempt
918 subroutine trace_rk45_stats_note_tangent_error(position_error_ratio, &
919 u_error_ratio,v_error_ratio)
920 double precision,
intent(in) :: position_error_ratio
921 double precision,
intent(in) :: u_error_ratio,v_error_ratio
923 double precision :: tangent_error_ratio
925 if (.not.trace_rk45_stats_enabled)
return
926 if (trace_integrator_mode/=trace_integrator_rk45_cartesian .and. &
927 trace_integrator_mode/=trace_integrator_rk45_spherical)
return
928 tangent_error_ratio=max(u_error_ratio,v_error_ratio)
930 trace_rk45_tangent_error_samples= &
931 trace_rk45_tangent_error_samples+1_8
932 trace_rk45_sum_tangent_error_ratio= &
933 trace_rk45_sum_tangent_error_ratio+tangent_error_ratio
934 trace_rk45_max_tangent_error_ratio= &
935 max(trace_rk45_max_tangent_error_ratio,tangent_error_ratio)
936 trace_rk45_max_tangent_u_error_ratio= &
937 max(trace_rk45_max_tangent_u_error_ratio,u_error_ratio)
938 trace_rk45_max_tangent_v_error_ratio= &
939 max(trace_rk45_max_tangent_v_error_ratio,v_error_ratio)
940 trace_rk45_max_position_error_ratio= &
941 max(trace_rk45_max_position_error_ratio,position_error_ratio)
942 if (tangent_error_ratio>trace_rk45_tangent_rtol) &
943 trace_rk45_tangent_would_reject= &
944 trace_rk45_tangent_would_reject+1_8
946 end subroutine trace_rk45_stats_note_tangent_error
949 logical,
intent(in) :: enabled
951 trace_spherical_profile_enabled=enabled
955 trace_profile_seeds=0_8
956 trace_profile_directions=0_8
957 trace_profile_steps=0_8
958 trace_profile_boundary_events=0_8
959 trace_profile_endpoint_finalizations=0_8
960 trace_profile_context_requests=0_8
961 trace_profile_same_cell_hits=0_8
962 trace_profile_same_grid_hits=0_8
963 trace_profile_full_context_builds=0_8
964 trace_profile_context_failures=0_8
965 trace_profile_cache_invalidations=0_8
966 trace_profile_b_samples=0_8
967 trace_profile_curl_samples=0_8
968 trace_profile_grad_samples=0_8
969 trace_profile_grad_success=0_8
970 trace_profile_grad_fallbacks=0_8
971 trace_profile_b_corner_loads=0_8
972 trace_profile_b_corner_hits=0_8
973 trace_profile_hlocal_evals=0_8
974 trace_profile_face_probes=0_8
975 trace_profile_tangent_systems=0_8
976 trace_profile_q_tangent_systems=0_8
977 trace_profile_qperp_tangent_systems=0_8
978 trace_profile_combined_tangent_systems=0_8
979 trace_profile_max_steps_per_trace=0_8
980 trace_profile_time_context=0.d0
981 trace_profile_time_b_interp=0.d0
982 trace_profile_time_curl_interp=0.d0
983 trace_profile_time_grad_bhat=0.d0
984 trace_profile_time_step=0.d0
985 trace_profile_time_tangent=0.d0
989 integer,
intent(in) :: nseed
991 if (.not.trace_spherical_profile_enabled)
return
992 call trace_spherical_profile_add_count(trace_profile_seeds, &
993 int(max(nseed,0),kind=8))
997 character(len=*),
intent(in) :: label
999 double precision :: avg_steps,denom,hit_denom
1001 if (.not.trace_spherical_profile_enabled)
return
1004 denom=max(one,dble(trace_profile_directions))
1005 avg_steps=dble(trace_profile_steps)/denom
1006 hit_denom=max(one,dble(trace_profile_context_requests))
1008 write(*,
'(a)')
'[mt_profile] spherical topology profiling summary '// &
1010 write(*,
'(a,i0)')
' seeds: ',trace_profile_seeds
1011 write(*,
'(a,i0)')
' traced_directions: ',trace_profile_directions
1012 write(*,
'(a,i0)')
' accepted_steps_all_integrators: ', &
1014 write(*,
'(a,es12.4)')
' avg_steps_per_counted_trace: ',avg_steps
1015 write(*,
'(a,i0)')
' max_steps_per_trace: ', &
1016 trace_profile_max_steps_per_trace
1017 write(*,
'(a)')
' note: accepted steps include counted spherical '// &
1018 'summary and tangent integrations; shared Q/Qperp tangent '// &
1019 'transport is counted once.'
1020 write(*,
'(a)')
' note: profiling counters are diagnostic and may '// &
1021 'significantly slow hot loops; do not use profiling-on wall time '// &
1022 'as production timing.'
1023 write(*,
'(a,i0)')
' boundary_events: ',trace_profile_boundary_events
1024 write(*,
'(a,i0)')
' endpoint_finalizations: ', &
1025 trace_profile_endpoint_finalizations
1026 write(*,
'(a,i0)')
' context_requests: ',trace_profile_context_requests
1027 write(*,
'(a,i0,a,f6.2,a)')
' same_cell_hits: ', &
1028 trace_profile_same_cell_hits,
' (', &
1029 100.d0*dble(trace_profile_same_cell_hits)/hit_denom,
'%)'
1030 write(*,
'(a,i0,a,f6.2,a)')
' same_grid_hits: ', &
1031 trace_profile_same_grid_hits,
' (', &
1032 100.d0*dble(trace_profile_same_grid_hits)/hit_denom,
'%)'
1033 write(*,
'(a,i0,a,f6.2,a)')
' full_context_builds: ', &
1034 trace_profile_full_context_builds,
' (', &
1035 100.d0*dble(trace_profile_full_context_builds)/hit_denom,
'%)'
1036 write(*,
'(a,i0)')
' context_failures: ',trace_profile_context_failures
1037 write(*,
'(a,i0)')
' cache_invalidations: ', &
1038 trace_profile_cache_invalidations
1039 write(*,
'(a,i0)')
' B_samples: ',trace_profile_b_samples
1040 write(*,
'(a,i0)')
' curl_samples: ',trace_profile_curl_samples
1041 write(*,
'(a,i0)')
' grad_bhat_samples: ',trace_profile_grad_samples
1042 write(*,
'(a,i0)')
' grad_bhat_success: ',trace_profile_grad_success
1043 write(*,
'(a,i0)')
' grad_bhat_fallbacks: ', &
1044 trace_profile_grad_fallbacks
1045 write(*,
'(a,i0)')
' B_corner_loads: ',trace_profile_b_corner_loads
1046 write(*,
'(a,i0)')
' B_corner_cache_hits: ', &
1047 trace_profile_b_corner_hits
1048 write(*,
'(a,i0)')
' h_local_evals: ',trace_profile_hlocal_evals
1049 write(*,
'(a,i0)')
' boundary_face_probes: ', &
1050 trace_profile_face_probes
1051 write(*,
'(a,i0)')
' tangent_systems: ', &
1052 trace_profile_tangent_systems
1053 write(*,
'(a,i0)')
' q_tangent_systems: ', &
1054 trace_profile_q_tangent_systems
1055 write(*,
'(a,i0)')
' qperp_tangent_systems: ', &
1056 trace_profile_qperp_tangent_systems
1057 write(*,
'(a,i0)')
' combined_q_qperp_tangent_systems: ', &
1058 trace_profile_combined_tangent_systems
1059 write(*,
'(a)')
' timing_cpu_seconds:'
1060 if (.not.trace_spherical_profile_timers)
then
1061 write(*,
'(a)')
' disabled (hot-loop timers distort profiling runs)'
1064 write(*,
'(a,es12.4)')
' context: ',trace_profile_time_context
1065 write(*,
'(a,es12.4)')
' B_interp: ',trace_profile_time_b_interp
1066 write(*,
'(a,es12.4)')
' curl_interp: ', &
1067 trace_profile_time_curl_interp
1068 write(*,
'(a,es12.4)')
' grad_bhat: ',trace_profile_time_grad_bhat
1069 write(*,
'(a,es12.4)')
' step_size: ',trace_profile_time_step
1070 write(*,
'(a,es12.4)')
' tangent_transport: ', &
1071 trace_profile_time_tangent
1074 subroutine trace_spherical_profile_add_count(counter,delta)
1075 integer(kind=8),
intent(inout) :: counter
1076 integer(kind=8),
intent(in) :: delta
1078 if (.not.trace_spherical_profile_enabled)
return
1080 counter=counter+delta
1081 end subroutine trace_spherical_profile_add_count
1083 subroutine trace_spherical_profile_add_time(timer,dt)
1084 double precision,
intent(inout) :: timer
1085 double precision,
intent(in) ::
dt
1087 if (.not.trace_spherical_profile_enabled)
return
1088 if (.not.trace_spherical_profile_timers)
return
1091 end subroutine trace_spherical_profile_add_time
1093 subroutine trace_spherical_profile_note_trace_steps(nstep)
1094 integer,
intent(in) ::
nstep
1096 if (.not.trace_spherical_profile_enabled)
return
1098 trace_profile_max_steps_per_trace=max(trace_profile_max_steps_per_trace, &
1101 end subroutine trace_spherical_profile_note_trace_steps
1103 double precision function trace_spherical_profile_time()
result(tnow)
1104 if (.not.trace_spherical_profile_timers)
then
1109 end function trace_spherical_profile_time
1112 integer,
intent(out) :: status
1114 double precision :: bvec(ixg^t,1:3)
1115 integer :: iigrid,igrid,idirmin
1116 integer :: ixi^
l,ixo^
l,ixa^
l
1121 if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
then
1125 if (.not.
b0field .and. .not.
allocated(iw_mag))
then
1131 allocate(trace_spherical_curl_cache(
max_blocks))
1135 if (iximin1>ixamin1 .or. iximax1<ixamax1 .or. &
1136 iximin2>ixamin2 .or. iximax2<ixamax2 .or. &
1137 iximin3>ixamin3 .or. iximax3<ixamax3)
then
1145 allocate(trace_spherical_curl_cache(igrid)%current( &
1146 lbound(ps(igrid)%w,1):ubound(ps(igrid)%w,1), &
1147 lbound(ps(igrid)%w,2):ubound(ps(igrid)%w,2), &
1148 lbound(ps(igrid)%w,3):ubound(ps(igrid)%w,3),1:3))
1149 trace_spherical_curl_cache(igrid)%current=zero
1151 if (
allocated(iw_mag))
then
1152 bvec(:,:,:,1)=ps(igrid)%w(:,:,:,iw_mag(1))
1153 bvec(:,:,:,2)=ps(igrid)%w(:,:,:,iw_mag(2))
1154 bvec(:,:,:,3)=ps(igrid)%w(:,:,:,iw_mag(3))
1159 trace_spherical_curl_cache(igrid)%current,idirmin,1,3)
1161 trace_spherical_curl_cache(igrid)%current(ixo^s,1:3)= &
1162 trace_spherical_curl_cache(igrid)%current(ixo^s,1:3) &
1163 +ps(igrid)%J0(ixo^s,1:3)
1165 trace_spherical_curl_cache(igrid)%ready=.true.
1167 trace_spherical_curl_cache_ready=.true.
1174 if (
allocated(trace_spherical_curl_cache))
then
1175 do igrid=1,
size(trace_spherical_curl_cache)
1176 if (
allocated(trace_spherical_curl_cache(igrid)%current))
then
1177 deallocate(trace_spherical_curl_cache(igrid)%current)
1179 trace_spherical_curl_cache(igrid)%ready=.false.
1181 deallocate(trace_spherical_curl_cache)
1183 trace_spherical_curl_cache_ready=.false.
1189 double precision,
intent(in) :: seed(
ndim),dl
1190 integer,
intent(in) :: max_steps
1192 double precision,
intent(in),
optional :: b_min
1194 if (
present(b_min))
then
1195 call trace_summary_seed(seed,dl,max_steps,result,b_min)
1197 call trace_summary_seed(seed,dl,max_steps,result)
1203 double precision,
intent(in) :: seed(
ndim),dl
1204 integer,
intent(in) :: max_steps
1206 double precision,
intent(in),
optional :: b_min
1208 if (
present(b_min))
then
1209 call trace_summary_twist_seed(seed,dl,max_steps,result,b_min)
1211 call trace_summary_twist_seed(seed,dl,max_steps,result)
1218 double precision,
intent(in) :: seed(
ndim),dl
1219 integer,
intent(in) :: max_steps
1221 double precision,
intent(in),
optional :: b_min
1222 double precision,
intent(in),
optional :: source_normal(3)
1224 if (
present(b_min))
then
1225 if (
present(source_normal))
then
1226 call trace_summary_mapping_seed(seed,dl,max_steps,result,b_min, &
1229 call trace_summary_mapping_seed(seed,dl,max_steps,result,b_min)
1232 if (
present(source_normal))
then
1233 call trace_summary_mapping_seed(seed,dl,max_steps,result, &
1234 source_normal=source_normal)
1236 call trace_summary_mapping_seed(seed,dl,max_steps,result)
1243 double precision,
intent(in) :: seed(
ndim),dl
1244 integer,
intent(in) :: max_steps
1246 double precision,
intent(in),
optional :: b_min
1248 if (
present(b_min))
then
1249 call trace_qperp_single_core(seed,dl,max_steps,result,b_min)
1251 call trace_qperp_single_core(seed,dl,max_steps,result)
1257 double precision,
intent(in) :: seed(
ndim)
1258 double precision,
intent(out) :: bhat(3),grad_bhat(3,3)
1259 integer,
intent(out) :: status
1260 double precision,
intent(in),
optional :: b_min
1262 logical,
intent(in),
optional :: spherical_cartfd
1263 logical :: use_cartfd
1265 double precision :: field_min
1274 else if (
ndim/=3 .or. .not.trace_is_supported_summary_geometry())
then
1279 field_min=smalldouble
1280 if (
present(b_min)) field_min=max(b_min,zero)
1282 call trace_summary_locate_seed(seed,located,igrid)
1283 status=located%forward_status
1287 if (
present(spherical_cartfd)) use_cartfd=spherical_cartfd
1288 if (geo_coordinate==geo_spherical)
then
1289 if (use_cartfd)
then
1290 call trace_spherical_sample_bhat_gradbhat_cartfd(seed,igrid, &
1291 field_min,bhat,grad_bhat,status)
1293 call trace_spherical_sample_bhat_gradbhat_covariant(seed,igrid, &
1294 field_min,bhat,grad_bhat,status)
1297 call sample_bhat_gradbhat_at_point(seed,igrid,field_min,bhat, &
1305 double precision,
intent(in) :: xhit(
ndim)
1306 integer,
intent(in) :: face_id
1307 double precision,
intent(out) :: b(
ndim),bhat(
ndim)
1308 integer,
intent(out) :: status
1309 double precision,
intent(in),
optional :: b_min
1311 double precision :: field_min,xprobe(
ndim),b3(3),bhat3(3)
1312 double precision :: xface,span
1313 integer :: normal_dim,side,igrid
1325 if (.not.trace_face_is_boundary(face_id))
then
1330 field_min=smalldouble
1331 if (
present(b_min)) field_min=max(b_min,zero)
1334 select case(face_id)
1364 span=max(abs(xprobmax1-xprobmin1), &
1365 max(abs(xprobmax2-xprobmin2),abs(xprobmax3-xprobmin3)))
1367 xprobe(normal_dim)=xface-side*1.
d-6*max(one,span)
1368 call trace_debug_locate_point(xprobe,igrid,status)
1371 call trace_sample_b_on_domain_face_limit(xhit,face_id,igrid,field_min, &
1381 grad_current,status_current,bhat_xeps,grad_xeps,status_xeps,b_min)
1383 double precision,
intent(in) :: seed(
ndim),eps
1384 double precision,
intent(out) :: bhat_current(3),grad_current(3,3)
1385 double precision,
intent(out) :: bhat_xeps(3),grad_xeps(3,3)
1386 integer,
intent(out) :: status_current,status_xeps
1387 double precision,
intent(in),
optional :: b_min
1390 double precision :: field_min
1409 field_min=smalldouble
1410 if (
present(b_min)) field_min=max(b_min,zero)
1412 call trace_summary_locate_seed(seed,located,igrid)
1413 status_current=located%forward_status
1415 call sample_bhat_gradbhat_at_point(seed,igrid,field_min, &
1416 bhat_current,grad_current,status_current)
1419 call sample_bhat_gradbhat_xeps_at_point(seed,eps,field_min,bhat_xeps, &
1420 grad_xeps,status_xeps)
1424 grad_current,status_current,bhat_xeps,grad_xeps,status_xeps, &
1425 bhat_interp,grad_interp,status_interp,b_min)
1427 double precision,
intent(in) :: seed(
ndim),eps
1428 double precision,
intent(out) :: bhat_current(3),grad_current(3,3)
1429 double precision,
intent(out) :: bhat_xeps(3),grad_xeps(3,3)
1430 double precision,
intent(out) :: bhat_interp(3),grad_interp(3,3)
1431 integer,
intent(out) :: status_current,status_xeps,status_interp
1432 double precision,
intent(in),
optional :: b_min
1435 double precision :: field_min
1459 field_min=smalldouble
1460 if (
present(b_min)) field_min=max(b_min,zero)
1462 call trace_summary_locate_seed(seed,located,igrid)
1463 status_current=located%forward_status
1464 status_interp=located%forward_status
1466 call sample_bhat_gradbhat_cellfd_at_point(seed,igrid,field_min, &
1467 bhat_current,grad_current,status_current)
1470 call sample_bhat_gradbhat_interpderiv_at_point(seed,igrid,field_min, &
1471 bhat_interp,grad_interp,status_interp)
1474 call sample_bhat_gradbhat_xeps_at_point(seed,eps,field_min,bhat_xeps, &
1475 grad_xeps,status_xeps)
1479 x_end,u_end,v_end,bhat_end,u_perp_end,v_perp_end,status,b_min)
1481 double precision,
intent(in) :: seed(
ndim),u0(
ndim),v0(
ndim),dl
1482 integer,
intent(in) ::
nstep
1483 logical,
intent(in) :: forward
1484 double precision,
intent(out) :: x_end(
ndim),u_end(
ndim),v_end(
ndim)
1485 double precision,
intent(out) :: bhat_end(
ndim)
1486 double precision,
intent(out) :: u_perp_end(
ndim),v_perp_end(
ndim)
1487 integer,
intent(out) :: status
1488 double precision,
intent(in),
optional :: b_min
1490 double precision :: field_min,h,bhat3(3),grad_end(3,3)
1491 integer :: igrid,
istep
1507 else if (dl<=zero .or.
nstep<0)
then
1512 field_min=smalldouble
1513 if (
present(b_min)) field_min=max(b_min,zero)
1515 if (.not.forward) h=-dl
1517 call trace_debug_locate_point(x_end,igrid,status)
1521 call trace_advance_tangent_state_rk2(x_end,u_end,v_end,igrid,h, &
1528 call sample_bhat_gradbhat_at_point(x_end,igrid,field_min,bhat3, &
1535 call trace_project_to_perp_bhat(u_end,bhat_end,u_perp_end)
1536 call trace_project_to_perp_bhat(v_end,bhat_end,v_perp_end)
1540 max_steps,forward,x_end,u_end,v_end,bhat_end,b_end,u_perp_end, &
1541 v_perp_end,u_face_end,v_face_end,length,face_id,status,b_min)
1543 double precision,
intent(in) :: seed(
ndim),u0(
ndim),v0(
ndim),dl
1544 integer,
intent(in) :: max_steps
1545 logical,
intent(in) :: forward
1546 double precision,
intent(out) :: x_end(
ndim),u_end(
ndim),v_end(
ndim)
1547 double precision,
intent(out) :: bhat_end(
ndim),b_end(
ndim)
1548 double precision,
intent(out) :: u_perp_end(
ndim),v_perp_end(
ndim)
1549 double precision,
intent(out) :: u_face_end(
ndim),v_face_end(
ndim)
1550 double precision,
intent(out) :: length
1551 integer,
intent(out) :: face_id,status
1552 double precision,
intent(in),
optional :: b_min
1554 double precision :: field_min,h,h_partial,partial_length
1558 integer :: igrid,igrid_trial,
istep,point_domain
1580 else if (dl<=zero .or. max_steps<0)
then
1585 field_min=smalldouble
1586 if (
present(b_min)) field_min=max(b_min,zero)
1588 if (.not.forward) h=-dl
1590 call trace_debug_locate_point(x_end,igrid,status)
1593 do istep=1,max_steps
1598 call trace_tangent_rhs(xold,uold,vold,igrid,field_min,kx1,ku1,kv1, &
1604 {
if (trace_coordinate_in_domain(xprobe(^db),^db)) point_domain=point_domain+1\}
1605 if (point_domain/=
ndim)
then
1606 call trace_intersect_domain(xold,xprobe,xhit,hit_ok,face_id)
1607 if (.not.hit_ok)
then
1608 call trace_boundary_face_at_point(xold,face_id,hit_ok)
1609 if (.not.hit_ok)
then
1620 partial_length=dsqrt(sum((xhit-xold)**2))
1621 if (partial_length<=100.d0*epsilon(one)*max(one,abs(h)))
then
1628 h_partial=sign(partial_length,h)
1629 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold,igrid, &
1630 h_partial,field_min,kx1,ku1,kv1,xtrial,utrial,vtrial,status)
1635 length=length+partial_length
1640 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold,igrid,h, &
1641 field_min,kx1,ku1,kv1,xtrial,utrial,vtrial,status)
1645 {
if (trace_coordinate_in_domain(xtrial(^db),^db)) point_domain=point_domain+1\}
1646 if (point_domain==
ndim)
then
1647 call trace_locate_point_with_hint(xtrial,igrid,igrid_trial,status)
1653 length=length+abs(h)
1655 call trace_intersect_domain(xold,xtrial,xhit,hit_ok,face_id)
1656 if (.not.hit_ok)
then
1657 call trace_boundary_face_at_point(xold,face_id,hit_ok)
1658 if (.not.hit_ok)
then
1669 partial_length=dsqrt(sum((xhit-xold)**2))
1670 if (partial_length<=100.d0*epsilon(one)*max(one,abs(h)))
then
1677 h_partial=sign(partial_length,h)
1678 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold,igrid, &
1679 h_partial,field_min,kx1,ku1,kv1,xtrial,utrial,vtrial,status)
1684 length=length+partial_length
1696 call trace_endpoint_b_bhat(x_end,face_id,igrid,field_min,b_end, &
1700 call trace_project_to_perp_bhat(u_end,bhat_end,u_perp_end)
1701 call trace_project_to_perp_bhat(v_end,bhat_end,v_perp_end)
1702 call trace_project_to_boundary_face(u_end,bhat_end,face_id,u_face_end)
1703 call trace_project_to_boundary_face(v_end,bhat_end,face_id,v_face_end)
1707 x_f,x_b,u_f_perp,v_f_perp,u_b_perp,v_b_perp,b_seed,b_f,b_b, &
1708 length_f,length_b,face_f,face_b,status,N2,bfactor,b_min)
1710 double precision,
intent(in) :: seed(
ndim),dl
1711 integer,
intent(in) :: max_steps
1712 double precision,
intent(out) :: qperp,logqperp,n2,bfactor
1713 double precision,
intent(out) :: x_f(
ndim),x_b(
ndim)
1714 double precision,
intent(out) :: u_f_perp(
ndim),v_f_perp(
ndim)
1715 double precision,
intent(out) :: u_b_perp(
ndim),v_b_perp(
ndim)
1716 double precision,
intent(out) :: b_seed(
ndim),b_f(
ndim),b_b(
ndim)
1717 double precision,
intent(out) :: length_f,length_b
1718 integer,
intent(out) :: face_f,face_b,status
1719 double precision,
intent(in),
optional :: b_min
1723 if (
present(b_min))
then
1730 logqperp=result%logqperp
1732 bfactor=result%bfactor
1733 x_f=result%forward_endpoint
1734 x_b=result%backward_endpoint
1735 u_f_perp=result%u_forward_perp
1736 v_f_perp=result%v_forward_perp
1737 u_b_perp=result%u_backward_perp
1738 v_b_perp=result%v_backward_perp
1739 b_seed=result%B_seed
1740 b_f=result%forward_B
1741 b_b=result%backward_B
1742 length_f=result%forward_length
1743 length_b=result%backward_length
1744 face_f=result%forward_face
1745 face_b=result%backward_face
1746 status=result%status
1749 subroutine trace_init_qperp_result(seed,result)
1750 double precision,
intent(in) :: seed(
ndim)
1754 result%qperp=trace_debug_nan()
1755 result%logqperp=trace_debug_nan()
1756 result%N2=trace_debug_nan()
1757 result%bfactor=trace_debug_nan()
1758 result%q0=trace_debug_nan()
1759 result%logq0=trace_debug_nan()
1760 result%qperp0=trace_debug_nan()
1761 result%logqperp0=trace_debug_nan()
1762 result%N2_qperp0=trace_debug_nan()
1763 result%bfactor_qperp0=trace_debug_nan()
1764 result%forward_Bn_q0=trace_debug_nan()
1765 result%backward_Bn_q0=trace_debug_nan()
1767 result%bhat_seed=zero
1768 result%forward_endpoint=seed
1769 result%backward_endpoint=seed
1770 result%forward_B=zero
1771 result%backward_B=zero
1772 result%forward_bhat=zero
1773 result%backward_bhat=zero
1774 result%forward_length=zero
1775 result%backward_length=zero
1776 result%forward_nstep=0
1777 result%backward_nstep=0
1780 result%u_forward_perp=zero
1781 result%v_forward_perp=zero
1782 result%u_backward_perp=zero
1783 result%v_backward_perp=zero
1791 result%valid=.false.
1792 result%valid_q0=.false.
1793 result%valid_qperp0=.false.
1794 end subroutine trace_init_qperp_result
1796 subroutine trace_qperp_single_core(seed,dL,max_steps,result,b_min)
1797 double precision,
intent(in) :: seed(
ndim),dl
1798 integer,
intent(in) :: max_steps
1800 double precision,
intent(in),
optional :: b_min
1802 double precision :: field_min,b3(3),bseed_norm
1804 integer :: igrid,status,indomain
1806 call trace_init_qperp_result(seed,result)
1811 else if (
ndim/=3 .or. .not.trace_cartesian_like_geometry())
then
1814 else if (dl<=zero .or. max_steps<=0)
then
1820 {
if (trace_coordinate_in_domain(seed(^db),^db)) indomain=indomain+1\}
1821 if (indomain/=
ndim)
then
1826 field_min=smalldouble
1827 if (
present(b_min)) field_min=max(b_min,zero)
1829 call trace_debug_locate_point(seed,igrid,status)
1831 result%status=status
1834 call sample_b_at_point(seed,igrid,field_min,b3,status)
1836 result%status=status
1839 result%B_seed=b3(1:
ndim)
1840 bseed_norm=dsqrt(sum(result%B_seed**2))
1841 if (bseed_norm<=zero .or. bseed_norm<field_min)
then
1845 result%bhat_seed=result%B_seed/bseed_norm
1846 call trace_make_perp_basis(b3/bseed_norm,result%u0,result%v0,status)
1848 result%status=status
1853 result%v0,dl,max_steps,.true.,result%forward_endpoint,u_end, &
1854 v_end,result%forward_bhat,result%forward_B,result%u_forward_perp, &
1855 result%v_forward_perp,u_face,v_face,result%forward_length, &
1856 result%forward_face,status,b_min=field_min)
1857 result%forward_status=status
1859 result%status=status
1864 result%v0,dl,max_steps,.false.,result%backward_endpoint,u_end, &
1865 v_end,result%backward_bhat,result%backward_B,result%u_backward_perp, &
1866 result%v_backward_perp,u_face,v_face,result%backward_length, &
1867 result%backward_face,status,b_min=field_min)
1868 result%backward_status=status
1870 result%status=status
1874 call trace_qperp_compute_scalars(result,field_min)
1875 end subroutine trace_qperp_single_core
1877 subroutine trace_tangent_state_init(seed,u0,v0,igrid,seed_id,direction, &
1878 state,accumulate_twist)
1879 double precision,
intent(in) :: seed(
ndim),u0(
ndim),v0(
ndim)
1880 integer,
intent(in) :: igrid,seed_id,direction
1881 type(trace_tangent_state),
intent(out) :: state
1882 logical,
intent(in),
optional :: accumulate_twist
1884 state%seed_id=seed_id
1885 state%direction=direction
1887 state%complete=.false.
1888 state%has_extra=.false.
1890 call trace_normalize_position(state%x)
1903 call trace_normalize_position(state%endpoint)
1904 state%endpoint_B=zero
1905 state%endpoint_bhat=zero
1911 state%accumulate_twist=.false.
1912 if (
present(accumulate_twist)) state%accumulate_twist=accumulate_twist
1913 state%sph_cache%valid=.false.
1914 if (trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical)
then
1915 call trace_spherical_profile_add_count(trace_profile_directions,1_8)
1916 call trace_spherical_profile_add_count(trace_profile_tangent_systems,1_8)
1918 end subroutine trace_tangent_state_init
1920 subroutine trace_tangent_trace_states_grouped(states,nstate,dL,max_steps, &
1921 threshold,trace_mode)
1925 integer,
intent(in) :: nstate,max_steps
1926 integer,
intent(in),
optional :: trace_mode
1927 type(trace_tangent_state),
intent(inout) :: states(nstate)
1928 double precision,
intent(in) :: dl,threshold
1930 logical,
allocatable :: processed(:)
1931 double precision :: t0,tgroup0,tgroup1
1932 integer :: active_count,group_size,istate,jstate,target_grid,group_mode
1933 logical :: any_active
1934 logical :: profile_tangent
1936 group_mode=trace_tangent_group_rk2_general
1937 if (
present(trace_mode)) group_mode=trace_mode
1938 profile_tangent=(group_mode/=trace_tangent_group_rk45_cartesian .and. &
1939 trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical)
1940 if (profile_tangent) t0=trace_spherical_profile_time()
1942 if (trace_cartesian_like_geometry())
then
1947 if (trace_rk2_stats_enabled)
call cpu_time(tgroup0)
1952 if (states(istate)%active)
then
1954 active_count=active_count+1
1957 if (.not.any_active)
exit
1958 call trace_rk2_stats_note_group_iteration()
1959 call trace_rk2_stats_note_grid_group(active_count)
1962 if (.not.states(jstate)%active) cycle
1963 select case (group_mode)
1964 case (trace_tangent_group_rk2_general)
1965 call trace_tangent_state_advance_in_grid(states(jstate), &
1966 states(jstate)%igrid,dl,max_steps,threshold)
1967 case (trace_tangent_group_rk2_short_boundary)
1968 call trace_tangent_state_advance_in_grid(states(jstate), &
1969 states(jstate)%igrid,dl,max_steps,threshold, &
1970 short_boundary=.true.)
1971 case (trace_tangent_group_rk45_cartesian)
1972 call trace_tangent_state_advance_in_grid_rk45_cartesian( &
1973 states(jstate),states(jstate)%igrid,dl,max_steps,threshold)
1976 states(jstate)%active=.false.
1977 states(jstate)%complete=.true.
1982 if (trace_rk2_stats_enabled)
then
1983 call cpu_time(tgroup1)
1984 call trace_rk2_stats_add_grouped_time(tgroup1-tgroup0)
1989 if (trace_rk2_stats_enabled)
call cpu_time(tgroup0)
1990 allocate(processed(nstate))
1994 if (states(istate)%active)
then
1999 if (.not.any_active)
exit
2000 call trace_rk2_stats_note_group_iteration()
2004 if (.not.states(istate)%active .or. processed(istate)) cycle
2005 target_grid=states(istate)%igrid
2006 if (trace_rk2_stats_enabled)
then
2009 if (states(jstate)%active .and. .not.processed(jstate) .and. &
2010 states(jstate)%igrid==target_grid) group_size=group_size+1
2012 call trace_rk2_stats_note_grid_group(group_size)
2016 if (.not.states(jstate)%active .or. processed(jstate)) cycle
2017 if (states(jstate)%igrid/=target_grid) cycle
2018 select case (group_mode)
2019 case (trace_tangent_group_rk2_general)
2020 call trace_tangent_state_advance_in_grid(states(jstate), &
2021 target_grid,dl,max_steps,threshold)
2022 case (trace_tangent_group_rk2_short_boundary)
2023 call trace_tangent_state_advance_in_grid(states(jstate), &
2024 target_grid,dl,max_steps,threshold,short_boundary=.true.)
2025 case (trace_tangent_group_rk45_cartesian)
2026 call trace_tangent_state_advance_in_grid_rk45_cartesian( &
2027 states(jstate),target_grid,dl,max_steps,threshold)
2030 states(jstate)%active=.false.
2031 states(jstate)%complete=.true.
2033 processed(jstate)=.true.
2038 deallocate(processed)
2039 if (trace_rk2_stats_enabled)
then
2040 call cpu_time(tgroup1)
2041 call trace_rk2_stats_add_grouped_time(tgroup1-tgroup0)
2043 if (profile_tangent)
call trace_spherical_profile_add_time( &
2044 trace_profile_time_tangent,trace_spherical_profile_time()-t0)
2045 end subroutine trace_tangent_trace_states_grouped
2047 subroutine trace_tangent_state_advance_in_grid_rk45_cartesian(state, &
2048 igrid,dL,max_steps,threshold)
2049 type(trace_tangent_state),
intent(inout) :: state
2050 integer,
intent(in) :: igrid,max_steps
2051 double precision,
intent(in) :: dl,threshold
2055 if (.not.state%active)
return
2057 do while(state%active .and. state%igrid==igrid .and. &
2058 state%nstep<max_steps)
2059 call trace_tangent_rk45_cartesian_step(state,dl,threshold,status)
2062 state%active=.false.
2063 state%complete=.true.
2068 if (state%active .and. state%nstep>=max_steps)
then
2070 state%active=.false.
2071 state%complete=.true.
2073 end subroutine trace_tangent_state_advance_in_grid_rk45_cartesian
2075 subroutine trace_tangent_rk45_cartesian_step(state,dL,threshold,status)
2076 type(trace_tangent_state),
intent(inout) :: state
2077 double precision,
intent(in) :: dl,threshold
2078 integer,
intent(out) :: status
2080 double precision,
parameter :: b21=1.d0/5.d0
2081 double precision,
parameter :: b31=3.d0/40.d0,b32=9.d0/40.d0
2082 double precision,
parameter :: b41=3.d0/10.d0,b42=-9.d0/10.d0, &
2084 double precision,
parameter :: b51=-11.d0/54.d0,b52=5.d0/2.d0, &
2085 b53=-70.d0/27.d0,b54=35.d0/27.d0
2086 double precision,
parameter :: b61=1631.d0/55296.d0, &
2087 b62=175.d0/512.d0,b63=575.d0/13824.d0, &
2088 b64=44275.d0/110592.d0,b65=253.d0/4096.d0
2089 double precision,
parameter :: c1=37.d0/378.d0,c3=250.d0/621.d0, &
2090 c4=125.d0/594.d0,c6=512.d0/1771.d0
2091 double precision,
parameter :: cs1=2825.d0/27648.d0, &
2092 cs3=18575.d0/48384.d0,cs4=13525.d0/55296.d0, &
2093 cs5=277.d0/14336.d0,cs6=one/4.d0
2097 double precision :: kx5(
ndim),kx6(
ndim)
2099 double precision :: ku5(
ndim),ku6(
ndim)
2101 double precision :: kv5(
ndim),kv6(
ndim)
2105 double precision :: x5sol(
ndim),x4err(
ndim)
2106 double precision :: u5sol(
ndim),v5sol(
ndim)
2107 double precision :: u4err(
ndim),v4err(
ndim)
2108 double precision :: h,hmax,hfloor,hcell,tol,err,grow,hsigned
2109 double precision :: pos_err_ratio,u_err_ratio,v_err_ratio
2110 double precision :: tan_err_ratio,control_ratio
2111 double precision :: tw1,tw3,tw4,tw6,twist_increment
2112 double precision :: dxb^
d
2113 integer :: igrid1,igrid2,igrid3,igrid4,igrid5,igrid6
2114 integer :: iter,point_domain,reject_reason,twist_status
2115 logical :: boundary_finished,pos_ok,tan_ok
2118 if (.not.trace_cartesian_like_geometry())
then
2131 hmax=abs(trace_effective_step(xold,dl,state%igrid,dxb^
d))
2132 if (hmax<=zero)
then
2139 hfloor=max(trace_step_min,100.d0*epsilon(one)*max(one,hmax))
2143 h=max(hfloor,min(h,hmax))
2145 if (state%direction<0) hsigned=-h
2147 call trace_tangent_rhs_cartesian_located(xold,uold,vold, &
2148 state%igrid,threshold,kx1,ku1,kv1,igrid1,status)
2151 x2=xold+hsigned*b21*kx1
2152 u2=uold+hsigned*b21*ku1
2153 v2=vold+hsigned*b21*kv1
2154 call trace_tangent_rhs_cartesian_located(x2,u2,v2,igrid1, &
2155 threshold,kx2,ku2,kv2,igrid2,status)
2158 call trace_tangent_rk45_cartesian_finish_boundary(state,xold,uold, &
2159 vold,x2,hsigned,threshold,kx1,ku1,kv1,status, &
2161 if (boundary_finished)
return
2162 reject_reason=trace_rk45_reject_stage_failure
2165 reject_reason=trace_rk45_reject_stage_outside
2166 if (trace_rk45_stats_enabled) &
2167 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
2169 if (h<=hfloor*(one+epsilon(one)))
exit
2170 h=max(hfloor,half*h)
2174 x3=xold+hsigned*(b31*kx1+b32*kx2)
2175 u3=uold+hsigned*(b31*ku1+b32*ku2)
2176 v3=vold+hsigned*(b31*kv1+b32*kv2)
2177 call trace_tangent_rhs_cartesian_located(x3,u3,v3,igrid2, &
2178 threshold,kx3,ku3,kv3,igrid3,status)
2181 call trace_tangent_rk45_cartesian_finish_boundary(state,xold,uold, &
2182 vold,x3,hsigned,threshold,kx1,ku1,kv1,status, &
2184 if (boundary_finished)
return
2185 reject_reason=trace_rk45_reject_stage_failure
2188 reject_reason=trace_rk45_reject_stage_outside
2189 if (trace_rk45_stats_enabled) &
2190 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
2192 if (h<=hfloor*(one+epsilon(one)))
exit
2193 h=max(hfloor,half*h)
2197 x4=xold+hsigned*(b41*kx1+b42*kx2+b43*kx3)
2198 u4=uold+hsigned*(b41*ku1+b42*ku2+b43*ku3)
2199 v4=vold+hsigned*(b41*kv1+b42*kv2+b43*kv3)
2200 call trace_tangent_rhs_cartesian_located(x4,u4,v4,igrid3, &
2201 threshold,kx4,ku4,kv4,igrid4,status)
2204 call trace_tangent_rk45_cartesian_finish_boundary(state,xold,uold, &
2205 vold,x4,hsigned,threshold,kx1,ku1,kv1,status, &
2207 if (boundary_finished)
return
2208 reject_reason=trace_rk45_reject_stage_failure
2211 reject_reason=trace_rk45_reject_stage_outside
2212 if (trace_rk45_stats_enabled) &
2213 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
2215 if (h<=hfloor*(one+epsilon(one)))
exit
2216 h=max(hfloor,half*h)
2220 x5s=xold+hsigned*(b51*kx1+b52*kx2+b53*kx3+b54*kx4)
2221 u5s=uold+hsigned*(b51*ku1+b52*ku2+b53*ku3+b54*ku4)
2222 v5s=vold+hsigned*(b51*kv1+b52*kv2+b53*kv3+b54*kv4)
2223 call trace_tangent_rhs_cartesian_located(x5s,u5s,v5s,igrid4, &
2224 threshold,kx5,ku5,kv5,igrid5,status)
2227 call trace_tangent_rk45_cartesian_finish_boundary(state,xold,uold, &
2228 vold,x5s,hsigned,threshold,kx1,ku1,kv1,status, &
2230 if (boundary_finished)
return
2231 reject_reason=trace_rk45_reject_stage_failure
2234 reject_reason=trace_rk45_reject_stage_outside
2235 if (trace_rk45_stats_enabled) &
2236 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
2238 if (h<=hfloor*(one+epsilon(one)))
exit
2239 h=max(hfloor,half*h)
2243 x6=xold+hsigned*(b61*kx1+b62*kx2+b63*kx3+b64*kx4+b65*kx5)
2244 u6=uold+hsigned*(b61*ku1+b62*ku2+b63*ku3+b64*ku4+b65*ku5)
2245 v6=vold+hsigned*(b61*kv1+b62*kv2+b63*kv3+b64*kv4+b65*kv5)
2246 call trace_tangent_rhs_cartesian_located(x6,u6,v6,igrid5, &
2247 threshold,kx6,ku6,kv6,igrid6,status)
2250 call trace_tangent_rk45_cartesian_finish_boundary(state,xold,uold, &
2251 vold,x6,hsigned,threshold,kx1,ku1,kv1,status, &
2253 if (boundary_finished)
return
2254 reject_reason=trace_rk45_reject_stage_failure
2257 reject_reason=trace_rk45_reject_stage_outside
2258 if (trace_rk45_stats_enabled) &
2259 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
2261 if (h<=hfloor*(one+epsilon(one)))
exit
2262 h=max(hfloor,half*h)
2266 x5sol=xold+hsigned*(c1*kx1+c3*kx3+c4*kx4+c6*kx6)
2267 u5sol=uold+hsigned*(c1*ku1+c3*ku3+c4*ku4+c6*ku6)
2268 v5sol=vold+hsigned*(c1*kv1+c3*kv3+c4*kv4+c6*kv6)
2269 x4err=xold+hsigned*(cs1*kx1+cs3*kx3+cs4*kx4+ &
2271 u4err=uold+hsigned*(cs1*ku1+cs3*ku3+cs4*ku4+ &
2273 v4err=vold+hsigned*(cs1*kv1+cs3*kv3+cs4*kv4+ &
2277 {
if (trace_coordinate_in_domain(x5sol(^db),^db)) point_domain=point_domain+1\}
2278 if (point_domain/=
ndim)
then
2279 call trace_tangent_rk45_cartesian_finish_boundary(state,xold,uold, &
2280 vold,x5sol,hsigned,threshold,kx1,ku1,kv1,status, &
2282 if (boundary_finished)
return
2283 if (trace_rk45_stats_enabled) &
2284 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
2285 trace_rk45_reject_boundary)
2290 call trace_cartesian_local_cell_size(xold,igrid1,hcell,status)
2292 err=dsqrt(sum((x5sol-x4err)**2))
2293 tol=trace_rk45_atol+trace_rk45_rtol*max(h,hcell)
2295 pos_err_ratio=err/tol
2299 u_err_ratio=dsqrt(sum((u5sol-u4err)**2))/ &
2300 max(dsqrt(sum(u5sol**2)),trace_rk45_tangent_floor)
2301 v_err_ratio=dsqrt(sum((v5sol-v4err)**2))/ &
2302 max(dsqrt(sum(v5sol**2)),trace_rk45_tangent_floor)
2303 tan_err_ratio=max(u_err_ratio,v_err_ratio)
2304 if (trace_rk45_stats_enabled) &
2305 call trace_rk45_stats_note_tangent_error(pos_err_ratio, &
2306 u_err_ratio,v_err_ratio)
2308 tan_ok=(tan_err_ratio<=trace_rk45_tangent_rtol)
2309 if ((pos_ok .and. tan_ok) .or. h<=hfloor*(one+epsilon(one)))
then
2310 if (state%accumulate_twist .and. &
2313 call trace_twist_density_at_point(xold,igrid1,threshold,tw1, &
2316 call trace_twist_density_at_point(x3,igrid3,threshold,tw3, &
2319 call trace_twist_density_at_point(x4,igrid4,threshold,tw4, &
2322 call trace_twist_density_at_point(x6,igrid6,threshold,tw6, &
2325 twist_increment=h*(c1*tw1+c3*tw3+c4*tw4+c6*tw6)
2326 state%twist=state%twist+twist_increment
2328 state%twist_status=twist_status
2332 call trace_normalize_position(state%x)
2335 state%length=state%length+h
2336 state%nstep=state%nstep+1
2337 call trace_locate_point_with_hint(state%x,igrid6,state%igrid,status)
2339 control_ratio=max(pos_err_ratio, &
2340 tan_err_ratio/trace_rk45_tangent_rtol)
2341 if (control_ratio>zero)
then
2342 grow=trace_rk45_safety*(one/control_ratio)**0.2d0
2343 grow=max(trace_rk45_min_shrink,min(trace_rk45_max_grow,grow))
2345 grow=trace_rk45_max_grow
2347 state%rk45_h=min(hmax,max(hfloor,h*grow))
2348 if (trace_rk45_stats_enabled) &
2349 call trace_rk45_stats_note_attempt(.true.,.false.,h)
2354 if (.not.pos_ok)
then
2355 grow=trace_rk45_safety*(tol/max(err,smalldouble))**0.25d0
2356 if (trace_rk45_stats_enabled) &
2357 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
2358 trace_rk45_reject_error)
2360 grow=trace_rk45_safety*(trace_rk45_tangent_rtol/ &
2361 max(tan_err_ratio,smalldouble))**0.25d0
2362 if (trace_rk45_stats_enabled) &
2363 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
2364 trace_rk45_reject_tangent_error)
2366 grow=max(trace_rk45_min_shrink,min(one,grow))
2367 h=max(hfloor,h*grow)
2370 call trace_tangent_rk45_cartesian_finish_boundary(state,xold,uold, &
2371 vold,xold+hsigned*kx1,hsigned,threshold,kx1,ku1,kv1,status, &
2374 end subroutine trace_tangent_rk45_cartesian_step
2376 subroutine trace_tangent_rhs_cartesian_located(x,u,v,igrid_hint, &
2377 threshold,kx,ku,kv,igrid,status)
2378 double precision,
intent(in) :: x(
ndim),u(
ndim),v(
ndim),threshold
2379 integer,
intent(in) :: igrid_hint
2380 double precision,
intent(out) :: kx(
ndim),ku(
ndim),kv(
ndim)
2381 integer,
intent(out) :: igrid,status
2388 if (.not.trace_cartesian_like_geometry())
return
2390 call trace_locate_point_with_hint(x,igrid_hint,igrid,status)
2392 call trace_tangent_rhs(x,u,v,igrid,threshold,kx,ku,kv,status)
2393 end subroutine trace_tangent_rhs_cartesian_located
2395 subroutine trace_tangent_rk45_cartesian_finish_boundary(state,xold,uold, &
2396 vold,xstage,hsigned,threshold,kx1,ku1,kv1,status,finished)
2397 type(trace_tangent_state),
intent(inout) :: state
2398 double precision,
intent(in) :: xold(
ndim),uold(
ndim),vold(
ndim)
2399 double precision,
intent(in) :: xstage(
ndim),hsigned,threshold
2400 double precision,
intent(in) :: kx1(
ndim),ku1(
ndim),kv1(
ndim)
2401 integer,
intent(out) :: status
2402 logical,
intent(out) :: finished
2404 double precision :: xhit(
ndim),utrial(
ndim),vtrial(
ndim)
2405 double precision :: xtrial(
ndim),partial_length,h_partial
2409 call trace_intersect_domain(xold,xstage,xhit,hit_ok,state%face_id)
2410 if (.not.hit_ok)
return
2412 partial_length=dsqrt(sum((xhit-xold)**2))
2413 if (partial_length>100.d0*epsilon(one)*max(one,abs(hsigned)))
then
2414 h_partial=sign(partial_length,hsigned)
2415 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold,state%igrid, &
2416 h_partial,threshold,kx1,ku1,kv1,xtrial,utrial,vtrial,status)
2418 call trace_tangent_accumulate_twist(state,xhit,partial_length, &
2422 state%length=state%length+partial_length
2423 state%nstep=state%nstep+1
2429 call trace_normalize_position(state%x)
2431 call trace_normalize_position(state%endpoint)
2433 state%active=.false.
2434 state%complete=.true.
2436 call trace_tangent_state_finalize_boundary(state,threshold)
2437 call trace_rk45_stats_note_attempt(.true.,.true.,partial_length)
2440 end subroutine trace_tangent_rk45_cartesian_finish_boundary
2442 subroutine trace_tangent_trace_states_grouped_rk45_spherical(states, &
2443 nstate,dL,max_steps,threshold)
2444 integer,
intent(in) :: nstate,max_steps
2445 type(trace_tangent_state),
intent(inout) :: states(nstate)
2446 double precision,
intent(in) :: dl,threshold
2448 logical,
allocatable :: processed(:)
2449 integer :: istate,jstate,target_grid
2450 logical :: any_active
2452 allocate(processed(nstate))
2456 if (states(istate)%active)
then
2461 if (.not.any_active)
exit
2465 if (.not.states(istate)%active .or. processed(istate)) cycle
2466 target_grid=states(istate)%igrid
2469 if (.not.states(jstate)%active .or. processed(jstate)) cycle
2470 if (states(jstate)%igrid/=target_grid) cycle
2471 call trace_tangent_state_advance_in_grid_rk45_spherical( &
2472 states(jstate),target_grid,dl,max_steps,threshold)
2473 processed(jstate)=.true.
2478 deallocate(processed)
2479 end subroutine trace_tangent_trace_states_grouped_rk45_spherical
2481 subroutine trace_tangent_state_advance_in_grid_rk45_spherical(state, &
2482 igrid,dL,max_steps,threshold)
2483 type(trace_tangent_state),
intent(inout) :: state
2484 integer,
intent(in) :: igrid,max_steps
2485 double precision,
intent(in) :: dl,threshold
2489 if (.not.state%active)
return
2491 do while(state%active .and. state%igrid==igrid .and. &
2492 state%nstep<max_steps)
2493 call trace_tangent_rk45_spherical_step(state,dl,threshold,status)
2496 state%active=.false.
2497 state%complete=.true.
2502 if (state%active .and. state%nstep>=max_steps)
then
2504 state%active=.false.
2505 state%complete=.true.
2507 if ((.not.state%active) .and. trace_spherical_profile_enabled .and. &
2508 geo_coordinate==geo_spherical)
then
2509 call trace_spherical_profile_note_trace_steps(state%nstep)
2511 end subroutine trace_tangent_state_advance_in_grid_rk45_spherical
2513 subroutine trace_tangent_rk45_spherical_step(state,dL,threshold,status)
2514 type(trace_tangent_state),
intent(inout) :: state
2515 double precision,
intent(in) :: dl,threshold
2516 integer,
intent(out) :: status
2518 double precision,
parameter :: b21=1.d0/5.d0
2519 double precision,
parameter :: b31=3.d0/40.d0,b32=9.d0/40.d0
2520 double precision,
parameter :: b41=3.d0/10.d0,b42=-9.d0/10.d0, &
2522 double precision,
parameter :: b51=-11.d0/54.d0,b52=5.d0/2.d0, &
2523 b53=-70.d0/27.d0,b54=35.d0/27.d0
2524 double precision,
parameter :: b61=1631.d0/55296.d0, &
2525 b62=175.d0/512.d0,b63=575.d0/13824.d0, &
2526 b64=44275.d0/110592.d0,b65=253.d0/4096.d0
2527 double precision,
parameter :: c1=37.d0/378.d0,c3=250.d0/621.d0, &
2528 c4=125.d0/594.d0,c6=512.d0/1771.d0
2529 double precision,
parameter :: cs1=2825.d0/27648.d0, &
2530 cs3=18575.d0/48384.d0,cs4=13525.d0/55296.d0, &
2531 cs5=277.d0/14336.d0,cs6=one/4.d0
2534 double precision :: pold(
ndim),qold(
ndim)
2536 double precision :: kx5(
ndim),kx6(
ndim)
2538 double precision :: ku5(
ndim),ku6(
ndim)
2540 double precision :: kv5(
ndim),kv6(
ndim)
2542 double precision :: kp5(
ndim),kp6(
ndim)
2544 double precision :: kq5(
ndim),kq6(
ndim)
2550 double precision :: x5sol(
ndim),x4err(
ndim)
2551 double precision :: u5sol(
ndim),v5sol(
ndim)
2552 double precision :: u4err(
ndim),v4err(
ndim)
2553 double precision :: p5sol(
ndim),q5sol(
ndim)
2554 double precision :: p4err(
ndim),q4err(
ndim)
2555 double precision :: h,hmax,hfloor,hcell,tol,err,grow,hsigned
2556 double precision :: pos_err_ratio,u_err_ratio,v_err_ratio
2557 double precision :: p_err_ratio,q_err_ratio
2558 double precision :: tan_err_ratio,control_ratio
2559 double precision :: tw1,tw3,tw4,tw6,twist_increment
2560 double precision :: r_metric,sin_theta_metric
2561 double precision :: domain_min(
ndim),domain_max(
ndim)
2562 type(trace_sph_interp_ctx) :: ctx1,ctx2,ctx3,ctx4,ctx5,ctx6
2563 integer :: igrid1,igrid2,igrid3,igrid4,igrid5,igrid6
2564 integer :: iter,point_domain,ctx_status,reject_reason,twist_status
2565 logical :: boundary_finished,pos_ok,tan_ok
2568 if (geo_coordinate/=geo_spherical)
then
2582 call trace_spherical_interp_ctx_build_cached(xold,state%igrid, &
2583 state%sph_cache,ctx1,ctx_status)
2588 hmax=abs(trace_spherical_effective_step_ctx(dl,ctx1))
2590 if (hmax<=zero)
then
2597 hfloor=max(trace_step_min,100.d0*epsilon(one)*max(one,hmax))
2599 ^
d&domain_min(^
d)=xprobmin^
d;
2600 ^
d&domain_max(^
d)=xprobmax^
d;
2603 h=max(hfloor,min(h,hmax))
2605 if (state%direction<0) hsigned=-h
2607 if (state%has_extra)
then
2608 call trace_tangent_rhs(xold,uold,vold,ctx1%igrid,threshold,kx1, &
2609 ku1,kv1,status,pold,qold,kp1,kq1,sph_ctx=ctx1)
2611 call trace_tangent_rhs(xold,uold,vold,ctx1%igrid,threshold,kx1, &
2612 ku1,kv1,status,sph_ctx=ctx1)
2617 x2=xold+hsigned*b21*kx1
2618 u2=uold+hsigned*b21*ku1
2619 v2=vold+hsigned*b21*kv1
2620 if (state%has_extra)
then
2621 p2=pold+hsigned*b21*kp1
2622 q2=qold+hsigned*b21*kq1
2624 call trace_spherical_interp_ctx_build_cached(x2,igrid1, &
2625 state%sph_cache,ctx2,ctx_status)
2627 call trace_tangent_rk45_spherical_finish_boundary(state,xold,uold, &
2628 vold,x2,hsigned*merge(0.2d0,one,trace_periodic_phi()),threshold,kx1,ku1,kv1,status, &
2629 boundary_finished,pold,qold,kp1,kq1)
2630 if (boundary_finished)
return
2631 reject_reason=trace_rk45_reject_stage_failure
2634 reject_reason=trace_rk45_reject_stage_outside
2635 call trace_rk45_stats_note_attempt(.false.,.false.,h,reject_reason)
2636 if (h<=hfloor*(one+epsilon(one)))
exit
2637 h=max(hfloor,half*h)
2640 if (state%has_extra)
then
2641 call trace_tangent_rhs(x2,u2,v2,ctx2%igrid,threshold,kx2,ku2, &
2642 kv2,status,p2,q2,kp2,kq2,sph_ctx=ctx2)
2644 call trace_tangent_rhs(x2,u2,v2,ctx2%igrid,threshold,kx2,ku2, &
2645 kv2,status,sph_ctx=ctx2)
2650 x3=xold+hsigned*(b31*kx1+b32*kx2)
2651 u3=uold+hsigned*(b31*ku1+b32*ku2)
2652 v3=vold+hsigned*(b31*kv1+b32*kv2)
2653 if (state%has_extra)
then
2654 p3=pold+hsigned*(b31*kp1+b32*kp2)
2655 q3=qold+hsigned*(b31*kq1+b32*kq2)
2657 call trace_spherical_interp_ctx_build_cached(x3,igrid2, &
2658 state%sph_cache,ctx3,ctx_status)
2660 call trace_tangent_rk45_spherical_finish_boundary(state,xold,uold, &
2661 vold,x3,hsigned*merge(0.3d0,one,trace_periodic_phi()),threshold,kx1,ku1,kv1,status, &
2662 boundary_finished,pold,qold,kp1,kq1)
2663 if (boundary_finished)
return
2664 reject_reason=trace_rk45_reject_stage_failure
2667 reject_reason=trace_rk45_reject_stage_outside
2668 call trace_rk45_stats_note_attempt(.false.,.false.,h,reject_reason)
2669 if (h<=hfloor*(one+epsilon(one)))
exit
2670 h=max(hfloor,half*h)
2673 if (state%has_extra)
then
2674 call trace_tangent_rhs(x3,u3,v3,ctx3%igrid,threshold,kx3,ku3, &
2675 kv3,status,p3,q3,kp3,kq3,sph_ctx=ctx3)
2677 call trace_tangent_rhs(x3,u3,v3,ctx3%igrid,threshold,kx3,ku3, &
2678 kv3,status,sph_ctx=ctx3)
2683 x4=xold+hsigned*(b41*kx1+b42*kx2+b43*kx3)
2684 u4=uold+hsigned*(b41*ku1+b42*ku2+b43*ku3)
2685 v4=vold+hsigned*(b41*kv1+b42*kv2+b43*kv3)
2686 if (state%has_extra)
then
2687 p4=pold+hsigned*(b41*kp1+b42*kp2+b43*kp3)
2688 q4=qold+hsigned*(b41*kq1+b42*kq2+b43*kq3)
2690 call trace_spherical_interp_ctx_build_cached(x4,igrid3, &
2691 state%sph_cache,ctx4,ctx_status)
2693 call trace_tangent_rk45_spherical_finish_boundary(state,xold,uold, &
2694 vold,x4,hsigned*merge(0.6d0,one,trace_periodic_phi()),threshold,kx1,ku1,kv1,status, &
2695 boundary_finished,pold,qold,kp1,kq1)
2696 if (boundary_finished)
return
2697 reject_reason=trace_rk45_reject_stage_failure
2700 reject_reason=trace_rk45_reject_stage_outside
2701 call trace_rk45_stats_note_attempt(.false.,.false.,h,reject_reason)
2702 if (h<=hfloor*(one+epsilon(one)))
exit
2703 h=max(hfloor,half*h)
2706 if (state%has_extra)
then
2707 call trace_tangent_rhs(x4,u4,v4,ctx4%igrid,threshold,kx4,ku4, &
2708 kv4,status,p4,q4,kp4,kq4,sph_ctx=ctx4)
2710 call trace_tangent_rhs(x4,u4,v4,ctx4%igrid,threshold,kx4,ku4, &
2711 kv4,status,sph_ctx=ctx4)
2716 x5s=xold+hsigned*(b51*kx1+b52*kx2+b53*kx3+b54*kx4)
2717 u5s=uold+hsigned*(b51*ku1+b52*ku2+b53*ku3+b54*ku4)
2718 v5s=vold+hsigned*(b51*kv1+b52*kv2+b53*kv3+b54*kv4)
2719 if (state%has_extra)
then
2720 p5s=pold+hsigned*(b51*kp1+b52*kp2+b53*kp3+b54*kp4)
2721 q5s=qold+hsigned*(b51*kq1+b52*kq2+b53*kq3+b54*kq4)
2723 call trace_spherical_interp_ctx_build_cached(x5s,igrid4, &
2724 state%sph_cache,ctx5,ctx_status)
2726 call trace_tangent_rk45_spherical_finish_boundary(state,xold,uold, &
2727 vold,x5s,hsigned,threshold,kx1,ku1,kv1,status, &
2728 boundary_finished,pold,qold,kp1,kq1)
2729 if (boundary_finished)
return
2730 reject_reason=trace_rk45_reject_stage_failure
2733 reject_reason=trace_rk45_reject_stage_outside
2734 call trace_rk45_stats_note_attempt(.false.,.false.,h,reject_reason)
2735 if (h<=hfloor*(one+epsilon(one)))
exit
2736 h=max(hfloor,half*h)
2739 if (state%has_extra)
then
2740 call trace_tangent_rhs(x5s,u5s,v5s,ctx5%igrid,threshold,kx5,ku5, &
2741 kv5,status,p5s,q5s,kp5,kq5,sph_ctx=ctx5)
2743 call trace_tangent_rhs(x5s,u5s,v5s,ctx5%igrid,threshold,kx5,ku5, &
2744 kv5,status,sph_ctx=ctx5)
2749 x6=xold+hsigned*(b61*kx1+b62*kx2+b63*kx3+b64*kx4+b65*kx5)
2750 u6=uold+hsigned*(b61*ku1+b62*ku2+b63*ku3+b64*ku4+b65*ku5)
2751 v6=vold+hsigned*(b61*kv1+b62*kv2+b63*kv3+b64*kv4+b65*kv5)
2752 if (state%has_extra)
then
2753 p6=pold+hsigned*(b61*kp1+b62*kp2+b63*kp3+b64*kp4+b65*kp5)
2754 q6=qold+hsigned*(b61*kq1+b62*kq2+b63*kq3+b64*kq4+b65*kq5)
2756 call trace_spherical_interp_ctx_build_cached(x6,igrid5, &
2757 state%sph_cache,ctx6,ctx_status)
2759 call trace_tangent_rk45_spherical_finish_boundary(state,xold,uold, &
2760 vold,x6,hsigned*merge(0.875d0,one,trace_periodic_phi()),threshold,kx1,ku1,kv1,status, &
2761 boundary_finished,pold,qold,kp1,kq1)
2762 if (boundary_finished)
return
2763 reject_reason=trace_rk45_reject_stage_failure
2766 reject_reason=trace_rk45_reject_stage_outside
2767 call trace_rk45_stats_note_attempt(.false.,.false.,h,reject_reason)
2768 if (h<=hfloor*(one+epsilon(one)))
exit
2769 h=max(hfloor,half*h)
2772 if (state%has_extra)
then
2773 call trace_tangent_rhs(x6,u6,v6,ctx6%igrid,threshold,kx6,ku6, &
2774 kv6,status,p6,q6,kp6,kq6,sph_ctx=ctx6)
2776 call trace_tangent_rhs(x6,u6,v6,ctx6%igrid,threshold,kx6,ku6, &
2777 kv6,status,sph_ctx=ctx6)
2782 x5sol=xold+hsigned*(c1*kx1+c3*kx3+c4*kx4+c6*kx6)
2783 u5sol=uold+hsigned*(c1*ku1+c3*ku3+c4*ku4+c6*ku6)
2784 v5sol=vold+hsigned*(c1*kv1+c3*kv3+c4*kv4+c6*kv6)
2785 x4err=xold+hsigned*(cs1*kx1+cs3*kx3+cs4*kx4+ &
2787 u4err=uold+hsigned*(cs1*ku1+cs3*ku3+cs4*ku4+ &
2789 v4err=vold+hsigned*(cs1*kv1+cs3*kv3+cs4*kv4+ &
2791 if (state%has_extra)
then
2792 p5sol=pold+hsigned*(c1*kp1+c3*kp3+c4*kp4+c6*kp6)
2793 q5sol=qold+hsigned*(c1*kq1+c3*kq3+c4*kq4+c6*kq6)
2794 p4err=pold+hsigned*(cs1*kp1+cs3*kp3+cs4*kp4+ &
2796 q4err=qold+hsigned*(cs1*kq1+cs3*kq3+cs4*kq4+ &
2801 {
if (trace_coordinate_in_domain(x5sol(^db),^db)) point_domain=point_domain+1\}
2802 if (point_domain/=
ndim)
then
2803 call trace_tangent_rk45_spherical_finish_boundary(state,xold,uold, &
2804 vold,x5sol,hsigned,threshold,kx1,ku1,kv1,status, &
2805 boundary_finished,pold,qold,kp1,kq1)
2806 if (boundary_finished)
return
2807 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
2808 trace_rk45_reject_boundary)
2815 r_metric=max(abs(xold(1)),smalldouble)
2816 sin_theta_metric=max(abs(dsin(xold(2))),smalldouble)
2817 err=dsqrt((x5sol(1)-x4err(1))**2+ &
2818 (r_metric*(x5sol(2)-x4err(2)))**2+ &
2819 (r_metric*sin_theta_metric*(x5sol(3)-x4err(3)))**2)
2821 if (hcell<=zero) hcell=hmax
2822 tol=trace_rk45_atol+trace_rk45_rtol*max(h,hcell)
2824 pos_err_ratio=err/tol
2828 u_err_ratio=dsqrt(sum((u5sol-u4err)**2))/ &
2829 max(dsqrt(sum(u5sol**2)),trace_rk45_tangent_floor)
2830 v_err_ratio=dsqrt(sum((v5sol-v4err)**2))/ &
2831 max(dsqrt(sum(v5sol**2)),trace_rk45_tangent_floor)
2832 if (state%has_extra)
then
2833 p_err_ratio=dsqrt(sum((p5sol-p4err)**2))/ &
2834 max(dsqrt(sum(p5sol**2)),trace_rk45_tangent_floor)
2835 q_err_ratio=dsqrt(sum((q5sol-q4err)**2))/ &
2836 max(dsqrt(sum(q5sol**2)),trace_rk45_tangent_floor)
2837 u_err_ratio=max(u_err_ratio,p_err_ratio)
2838 v_err_ratio=max(v_err_ratio,q_err_ratio)
2840 tan_err_ratio=max(u_err_ratio,v_err_ratio)
2841 call trace_rk45_stats_note_tangent_error(pos_err_ratio, &
2842 u_err_ratio,v_err_ratio)
2844 tan_ok=(tan_err_ratio<=trace_rk45_tangent_rtol)
2845 if ((pos_ok .and. tan_ok) .or. h<=hfloor*(one+epsilon(one)))
then
2846 if (state%accumulate_twist .and. &
2849 call trace_twist_density_at_point(xold,ctx1%igrid,threshold,tw1, &
2850 twist_status,sph_cache=ctx1)
2852 call trace_twist_density_at_point(x3,ctx3%igrid,threshold, &
2853 tw3,twist_status,sph_cache=ctx3)
2855 call trace_twist_density_at_point(x4,ctx4%igrid,threshold, &
2856 tw4,twist_status,sph_cache=ctx4)
2858 call trace_twist_density_at_point(x6,ctx6%igrid,threshold, &
2859 tw6,twist_status,sph_cache=ctx6)
2861 twist_increment=h*(c1*tw1+c3*tw3+c4*tw4+c6*tw6)
2862 state%twist=state%twist+twist_increment
2864 state%twist_status=twist_status
2868 call trace_normalize_position(state%x)
2871 if (state%has_extra)
then
2875 state%length=state%length+h
2876 state%nstep=state%nstep+1
2877 call trace_locate_point_with_hint(state%x,igrid6,state%igrid,status)
2879 state%sph_cache%valid=.false.
2880 if (trace_spherical_profile_enabled) &
2881 call trace_spherical_profile_add_count(trace_profile_steps,1_8)
2882 control_ratio=max(pos_err_ratio, &
2883 tan_err_ratio/trace_rk45_tangent_rtol)
2884 if (control_ratio>zero)
then
2885 grow=trace_rk45_safety*(one/control_ratio)**0.2d0
2886 grow=max(trace_rk45_min_shrink,min(trace_rk45_max_grow,grow))
2888 grow=trace_rk45_max_grow
2890 state%rk45_h=min(hmax,max(hfloor,h*grow))
2891 call trace_rk45_stats_note_attempt(.true.,.false.,h)
2896 if (.not.pos_ok)
then
2897 grow=trace_rk45_safety*(tol/max(err,smalldouble))**0.25d0
2898 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
2899 trace_rk45_reject_error)
2901 grow=trace_rk45_safety*(trace_rk45_tangent_rtol/ &
2902 max(tan_err_ratio,smalldouble))**0.25d0
2903 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
2904 trace_rk45_reject_tangent_error)
2906 grow=max(trace_rk45_min_shrink,min(one,grow))
2907 h=max(hfloor,h*grow)
2910 call trace_tangent_rk45_spherical_finish_boundary(state,xold,uold, &
2911 vold,xold+hsigned*kx1,hsigned,threshold,kx1,ku1,kv1,status, &
2912 boundary_finished,pold,qold,kp1,kq1)
2914 end subroutine trace_tangent_rk45_spherical_step
2916 subroutine trace_tangent_rk45_spherical_finish_boundary(state,xold,uold, &
2917 vold,xstage,hsigned,threshold,kx1,ku1,kv1,status,finished, &
2919 type(trace_tangent_state),
intent(inout) :: state
2920 double precision,
intent(in) :: xold(
ndim),uold(
ndim),vold(
ndim)
2921 double precision,
intent(in) :: xstage(
ndim),hsigned,threshold
2922 double precision,
intent(in) :: kx1(
ndim),ku1(
ndim),kv1(
ndim)
2923 integer,
intent(out) :: status
2924 logical,
intent(out) :: finished
2925 double precision,
intent(in),
optional :: pold(
ndim),qold(
ndim)
2926 double precision,
intent(in),
optional :: kp1(
ndim),kq1(
ndim)
2928 double precision :: xhit(
ndim),utrial(
ndim),vtrial(
ndim)
2929 double precision :: ptrial(
ndim),qtrial(
ndim)
2930 double precision :: xtrial(
ndim),partial_length,h_partial,alpha_hit
2934 call trace_intersect_domain(xold,xstage,xhit,hit_ok,state%face_id, &
2936 if (.not.hit_ok)
return
2938 partial_length=trace_segment_length(xold,xhit,hsigned,alpha_hit)
2939 if (partial_length>100.d0*epsilon(one)*max(one,abs(hsigned)))
then
2940 h_partial=sign(partial_length,hsigned)
2941 if (state%has_extra)
then
2942 if (.not.(
present(pold) .and.
present(qold) .and.
present(kp1) &
2943 .and.
present(kq1)))
then
2947 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold,state%igrid, &
2948 h_partial,threshold,kx1,ku1,kv1,xtrial,utrial,vtrial,status, &
2949 pold,qold,kp1,kq1,ptrial,qtrial,sph_cache=state%sph_cache)
2951 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold,state%igrid, &
2952 h_partial,threshold,kx1,ku1,kv1,xtrial,utrial,vtrial,status, &
2953 sph_cache=state%sph_cache)
2956 call trace_tangent_accumulate_twist(state,xhit,partial_length, &
2960 if (state%has_extra)
then
2964 state%length=state%length+partial_length
2965 state%nstep=state%nstep+1
2966 if (trace_spherical_profile_enabled) &
2967 call trace_spherical_profile_add_count(trace_profile_steps,1_8)
2971 if (state%has_extra)
then
2972 if (.not.(
present(pold) .and.
present(qold)))
then
2981 call trace_normalize_position(state%x)
2983 call trace_normalize_position(state%endpoint)
2985 state%active=.false.
2986 state%complete=.true.
2988 state%sph_cache%valid=.false.
2989 if (trace_spherical_profile_enabled)
then
2990 call trace_spherical_profile_add_count(trace_profile_boundary_events,1_8)
2992 call trace_tangent_state_finalize_boundary(state,threshold)
2993 call trace_rk45_stats_note_attempt(.true.,.true.,partial_length)
2996 end subroutine trace_tangent_rk45_spherical_finish_boundary
2998 subroutine trace_tangent_state_advance_in_grid(state,igrid,dL,max_steps, &
2999 threshold,short_boundary)
3000 type(trace_tangent_state),
intent(inout) :: state
3001 integer,
intent(in) :: igrid,max_steps
3002 double precision,
intent(in) :: dl,threshold
3003 logical,
intent(in),
optional :: short_boundary
3005 integer,
parameter :: max_bisect=50
3006 double precision :: h,h_partial,partial_length,alpha_hit
3007 double precision :: h_abs_low,h_abs_high,h_abs_mid,h_abs_final,hsign
3009 double precision :: ptrial(
ndim),qtrial(
ndim)
3011 double precision :: pold(
ndim),qold(
ndim)
3015 double precision :: dxb^
d
3016 type(trace_sph_interp_ctx) :: ctx_old
3017 integer :: igrid_old,igrid_trial,point_domain,iter
3018 integer :: ctx_status,trial_status
3019 logical :: hit_ok,use_short_boundary
3021 if (.not.state%active)
return
3022 use_short_boundary=.false.
3023 if (
present(short_boundary)) use_short_boundary=short_boundary
3025 do while(state%active .and. state%igrid==igrid .and. &
3026 state%nstep<max_steps)
3034 if (geo_coordinate==geo_spherical)
then
3035 call trace_spherical_interp_ctx_build_cached(xold,state%igrid, &
3036 state%sph_cache,ctx_old,ctx_status)
3039 h=trace_spherical_effective_step_ctx(dl,ctx_old)
3041 h=trace_effective_step(xold,dl,state%igrid,dxb^
d)
3043 if (state%direction<0) h=-h
3045 if (state%has_extra)
then
3047 call trace_tangent_rhs(xold,uold,vold,state%igrid,threshold,kx1, &
3048 ku1,kv1,state%status,pold,qold,kp1,kq1,sph_ctx=ctx_old)
3050 call trace_tangent_rhs(xold,uold,vold,state%igrid,threshold,kx1, &
3051 ku1,kv1,state%status,pold,qold,kp1,kq1)
3055 call trace_tangent_rhs(xold,uold,vold,state%igrid,threshold,kx1, &
3056 ku1,kv1,state%status,sph_ctx=ctx_old)
3058 call trace_tangent_rhs(xold,uold,vold,state%igrid,threshold,kx1, &
3059 ku1,kv1,state%status)
3063 state%active=.false.
3064 state%complete=.true.
3065 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3068 if (use_short_boundary)
then
3072 if (state%has_extra)
then
3073 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold,state%igrid, &
3074 h,threshold,kx1,ku1,kv1,xtrial,utrial,vtrial,state%status, &
3075 pold,qold,kp1,kq1,ptrial,qtrial,sph_cache=state%sph_cache, &
3078 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold,state%igrid, &
3079 h,threshold,kx1,ku1,kv1,xtrial,utrial,vtrial,state%status, &
3080 sph_cache=state%sph_cache,clamp_stage=.true.)
3083 state%active=.false.
3084 state%complete=.true.
3085 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3090 {
if (trace_coordinate_in_domain(xtrial(^db),^db)) point_domain=point_domain+1\}
3091 if (point_domain==
ndim)
then
3092 igrid_old=state%igrid
3093 call trace_locate_point_with_hint(xtrial,state%igrid,igrid_trial, &
3096 state%active=.false.
3097 state%complete=.true.
3098 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3101 call trace_tangent_accumulate_twist(state,xtrial,abs(h),threshold)
3103 call trace_normalize_position(state%x)
3106 if (state%has_extra)
then
3110 state%igrid=igrid_trial
3111 state%length=state%length+abs(h)
3112 state%nstep=state%nstep+1
3113 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_step(abs(h),.false., &
3114 igrid_trial/=igrid_old)
3115 if (trace_spherical_profile_enabled .and. &
3116 geo_coordinate==geo_spherical)
then
3117 call trace_spherical_profile_add_count(trace_profile_steps,1_8)
3128 do iter=1,max_bisect
3129 h_abs_mid=half*(h_abs_low+h_abs_high)
3130 if (h_abs_high-h_abs_low<=100.d0*epsilon(one)*max(one,abs(h))) &
3133 if (state%has_extra)
then
3134 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold, &
3135 state%igrid,hsign*h_abs_mid,threshold,kx1,ku1,kv1, &
3136 xtrial,utrial,vtrial,trial_status,pold,qold,kp1,kq1, &
3137 ptrial,qtrial,sph_cache=state%sph_cache, &
3140 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold, &
3141 state%igrid,hsign*h_abs_mid,threshold,kx1,ku1,kv1, &
3142 xtrial,utrial,vtrial,trial_status, &
3143 sph_cache=state%sph_cache,clamp_stage=.true.)
3146 h_abs_high=h_abs_mid
3150 {
if (trace_coordinate_in_domain(xtrial(^db),^db)) point_domain=point_domain+1\}
3151 if (point_domain==
ndim)
then
3156 if (state%has_extra)
then
3161 h_abs_high=h_abs_mid
3166 call trace_intersect_domain(xlow,xhigh,xhit,hit_ok,state%face_id, &
3169 h_abs_final=h_abs_low+max(zero,min(one,alpha_hit))* &
3170 (h_abs_high-h_abs_low)
3173 h_abs_final=h_abs_low
3174 call trace_boundary_face_at_point(xhit,state%face_id,hit_ok)
3176 if (.not.hit_ok)
then
3178 state%active=.false.
3179 state%complete=.true.
3180 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3184 partial_length=h_abs_final
3185 if (partial_length>100.d0*epsilon(one)*max(one,abs(h)))
then
3187 if (state%has_extra)
then
3188 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold, &
3189 state%igrid,hsign*h_abs_final,threshold,kx1,ku1,kv1, &
3190 xtrial,utrial,vtrial,trial_status,pold,qold,kp1,kq1, &
3191 ptrial,qtrial,sph_cache=state%sph_cache, &
3194 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold, &
3195 state%igrid,hsign*h_abs_final,threshold,kx1,ku1,kv1, &
3196 xtrial,utrial,vtrial,trial_status, &
3197 sph_cache=state%sph_cache,clamp_stage=.true.)
3200 state%status=trial_status
3201 state%active=.false.
3202 state%complete=.true.
3203 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3206 call trace_tangent_accumulate_twist(state,xhit,partial_length, &
3210 if (state%has_extra)
then
3214 state%length=state%length+partial_length
3215 state%nstep=state%nstep+1
3216 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_step(partial_length,.true.,.false.)
3217 if (trace_spherical_profile_enabled .and. &
3218 geo_coordinate==geo_spherical)
then
3219 call trace_spherical_profile_add_count(trace_profile_steps,1_8)
3224 if (state%has_extra)
then
3230 call trace_normalize_position(state%x)
3232 call trace_normalize_position(state%endpoint)
3234 state%active=.false.
3235 if (trace_spherical_profile_enabled .and. &
3236 geo_coordinate==geo_spherical)
then
3237 call trace_spherical_profile_add_count( &
3238 trace_profile_boundary_events,1_8)
3240 call trace_tangent_state_finalize_boundary(state,threshold)
3241 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3249 {
if (trace_coordinate_in_domain(xprobe(^db),^db)) point_domain=point_domain+1\}
3250 if (point_domain/=
ndim)
then
3251 call trace_intersect_domain(xold,xprobe,xhit,hit_ok,state%face_id, &
3253 if (.not.hit_ok)
then
3254 call trace_boundary_face_at_point(xold,state%face_id,hit_ok)
3256 state%active=.false.
3258 call trace_normalize_position(state%x)
3261 if (state%has_extra)
then
3266 call trace_normalize_position(state%endpoint)
3267 if (hit_ok)
call trace_tangent_state_finalize_boundary(state, &
3269 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3272 partial_length=trace_segment_length(xold,xhit,h,alpha_hit)
3273 if (partial_length<=100.d0*epsilon(one)*max(one,abs(h)))
then
3275 call trace_normalize_position(state%x)
3278 if (state%has_extra)
then
3283 call trace_normalize_position(state%endpoint)
3285 state%active=.false.
3286 call trace_tangent_state_finalize_boundary(state,threshold)
3287 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3290 h_partial=sign(partial_length,h)
3291 if (state%has_extra)
then
3292 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold,state%igrid, &
3293 h_partial,threshold,kx1,ku1,kv1,xtrial,utrial,vtrial, &
3294 state%status,pold,qold,kp1,kq1,ptrial,qtrial, &
3295 sph_cache=state%sph_cache)
3297 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold,state%igrid, &
3298 h_partial,threshold,kx1,ku1,kv1,xtrial,utrial,vtrial, &
3299 state%status,sph_cache=state%sph_cache)
3302 state%active=.false.
3303 state%complete=.true.
3304 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3307 call trace_tangent_accumulate_twist(state,xhit,partial_length, &
3310 call trace_normalize_position(state%x)
3313 if (state%has_extra)
then
3317 state%length=state%length+partial_length
3319 call trace_normalize_position(state%endpoint)
3321 state%active=.false.
3322 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_step(partial_length,.true.,.false.)
3323 call trace_tangent_state_finalize_boundary(state,threshold)
3324 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3328 if (state%has_extra)
then
3329 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold,state%igrid,h, &
3330 threshold,kx1,ku1,kv1,xtrial,utrial,vtrial,state%status, &
3331 pold,qold,kp1,kq1,ptrial,qtrial,sph_cache=state%sph_cache)
3333 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold,state%igrid,h, &
3334 threshold,kx1,ku1,kv1,xtrial,utrial,vtrial,state%status, &
3335 sph_cache=state%sph_cache)
3338 state%active=.false.
3339 state%complete=.true.
3340 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3345 {
if (trace_coordinate_in_domain(xtrial(^db),^db)) point_domain=point_domain+1\}
3346 if (point_domain==
ndim)
then
3347 igrid_old=state%igrid
3348 call trace_locate_point_with_hint(xtrial,state%igrid,igrid_trial, &
3351 state%active=.false.
3352 state%complete=.true.
3353 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3356 call trace_tangent_accumulate_twist(state,xtrial,abs(h),threshold)
3358 call trace_normalize_position(state%x)
3361 if (state%has_extra)
then
3365 state%igrid=igrid_trial
3366 state%length=state%length+abs(h)
3367 state%nstep=state%nstep+1
3368 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_step(abs(h),.false., &
3369 igrid_trial/=igrid_old)
3370 if (trace_spherical_profile_enabled .and. &
3371 geo_coordinate==geo_spherical)
then
3372 call trace_spherical_profile_add_count(trace_profile_steps,1_8)
3375 call trace_intersect_domain(xold,xtrial,xhit,hit_ok,state%face_id, &
3377 if (.not.hit_ok)
then
3378 call trace_boundary_face_at_point(xold,state%face_id,hit_ok)
3380 state%active=.false.
3382 call trace_normalize_position(state%x)
3385 if (state%has_extra)
then
3390 call trace_normalize_position(state%endpoint)
3391 if (hit_ok)
call trace_tangent_state_finalize_boundary(state, &
3393 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3396 partial_length=trace_segment_length(xold,xhit,h,alpha_hit)
3397 if (partial_length<=100.d0*epsilon(one)*max(one,abs(h)))
then
3399 call trace_normalize_position(state%x)
3402 if (state%has_extra)
then
3407 call trace_normalize_position(state%endpoint)
3409 state%active=.false.
3410 call trace_tangent_state_finalize_boundary(state,threshold)
3411 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3414 h_partial=sign(partial_length,h)
3415 if (state%has_extra)
then
3416 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold,state%igrid, &
3417 h_partial,threshold,kx1,ku1,kv1,xtrial,utrial,vtrial, &
3418 state%status,pold,qold,kp1,kq1,ptrial,qtrial, &
3419 sph_cache=state%sph_cache)
3421 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold,state%igrid, &
3422 h_partial,threshold,kx1,ku1,kv1,xtrial,utrial,vtrial, &
3423 state%status,sph_cache=state%sph_cache)
3426 state%active=.false.
3427 state%complete=.true.
3428 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3431 call trace_tangent_accumulate_twist(state,xhit,partial_length, &
3434 call trace_normalize_position(state%x)
3437 if (state%has_extra)
then
3441 state%length=state%length+partial_length
3443 call trace_normalize_position(state%endpoint)
3445 state%active=.false.
3446 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_step(partial_length,.true.,.false.)
3447 if (trace_spherical_profile_enabled .and. &
3448 geo_coordinate==geo_spherical)
then
3449 call trace_spherical_profile_add_count(trace_profile_boundary_events, &
3452 call trace_tangent_state_finalize_boundary(state,threshold)
3453 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3458 if (state%active .and. state%nstep>=max_steps)
then
3460 state%active=.false.
3461 state%complete=.true.
3462 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3464 if ((.not.state%active) .and. trace_spherical_profile_enabled .and. &
3465 geo_coordinate==geo_spherical)
then
3466 call trace_spherical_profile_note_trace_steps(state%nstep)
3468 end subroutine trace_tangent_state_advance_in_grid
3470 subroutine trace_tangent_state_finalize_boundary(state,threshold)
3471 type(trace_tangent_state),
intent(inout) :: state
3472 double precision,
intent(in) :: threshold
3475 if (trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical) &
3476 call trace_spherical_profile_add_count( &
3477 trace_profile_endpoint_finalizations,1_8)
3479 call trace_endpoint_b_bhat(state%endpoint,state%face_id,state%igrid, &
3480 threshold,state%endpoint_B,state%endpoint_bhat,state%status)
3483 call trace_project_to_perp_bhat(state%u,state%endpoint_bhat, &
3485 call trace_project_to_perp_bhat(state%v,state%endpoint_bhat, &
3487 if (state%has_extra)
then
3488 call trace_project_to_perp_bhat(state%p,state%endpoint_bhat, &
3490 call trace_project_to_perp_bhat(state%q,state%endpoint_bhat, &
3493 state%complete=.true.
3494 end subroutine trace_tangent_state_finalize_boundary
3496 subroutine trace_qperp_prepare_seed_result(seed,field_min,result,igrid, &
3498 double precision,
intent(in) :: seed(
ndim),field_min
3500 integer,
intent(out) :: igrid,status
3502 double precision :: b3(3),bseed_norm
3505 call trace_init_qperp_result(seed,result)
3510 {
if (trace_coordinate_in_domain(seed(^db),^db)) indomain=indomain+1\}
3511 if (indomain/=
ndim)
then
3513 result%status=status
3517 call trace_debug_locate_point(seed,igrid,status)
3519 result%status=status
3523 call sample_b_at_point(seed,igrid,field_min,b3,status)
3525 result%status=status
3528 result%B_seed=b3(1:
ndim)
3529 bseed_norm=dsqrt(sum(result%B_seed**2))
3530 if (bseed_norm<=zero .or. bseed_norm<field_min)
then
3532 result%status=status
3536 result%bhat_seed=result%B_seed/bseed_norm
3537 call trace_make_perp_basis(b3/bseed_norm,result%u0,result%v0,status)
3539 end subroutine trace_qperp_prepare_seed_result
3541 subroutine trace_qperp_compute_scalars(result,field_min)
3543 double precision,
intent(in) :: field_min
3545 double precision :: bseed_norm,bf_norm,bb_norm,dot_f,dot_b,qtmp
3547 bseed_norm=dsqrt(sum(result%B_seed**2))
3548 bf_norm=dsqrt(sum(result%forward_B**2))
3549 bb_norm=dsqrt(sum(result%backward_B**2))
3550 if (bseed_norm<=zero .or. bf_norm<=zero .or. bb_norm<=zero .or. &
3551 bseed_norm<field_min .or. bf_norm<field_min .or. &
3552 bb_norm<field_min)
then
3557 dot_f=sum(result%u_forward_perp*result%v_forward_perp)
3558 dot_b=sum(result%u_backward_perp*result%v_backward_perp)
3559 result%N2=sum(result%u_forward_perp**2)* &
3560 sum(result%v_backward_perp**2)+ &
3561 sum(result%u_backward_perp**2)* &
3562 sum(result%v_forward_perp**2)-2.d0*dot_f*dot_b
3563 result%bfactor=abs(bf_norm*bb_norm)/(bseed_norm**2)
3564 qtmp=result%N2*result%bfactor
3565 if (qtmp>zero .and. ieee_is_finite(qtmp))
then
3566 qtmp=max(qtmp,trace_q_min)
3568 result%logqperp=dlog10(qtmp)
3572 result%logqperp0=result%logqperp
3573 result%valid_qperp0=.true.
3576 result%N2=trace_debug_nan()
3577 result%bfactor=trace_debug_nan()
3578 result%qperp=trace_debug_nan()
3579 result%logqperp=trace_debug_nan()
3581 result%valid=.false.
3582 result%qperp0=trace_debug_nan()
3583 result%logqperp0=trace_debug_nan()
3584 result%valid_qperp0=.false.
3587 call trace_qperp_compute_q0_scalars(result,field_min)
3588 end subroutine trace_qperp_compute_scalars
3590 subroutine trace_qperp_compute_q0_scalars(result,field_min)
3592 double precision,
intent(in) :: field_min
3594 double precision :: bseed_norm,bnf,bnb,n2bnd,qtmp
3595 double precision :: uf_face(
ndim),vf_face(
ndim)
3596 double precision :: ub_face(
ndim),vb_face(
ndim)
3597 integer :: status_f,status_b
3599 result%q0=trace_debug_nan()
3600 result%logq0=trace_debug_nan()
3601 result%N2_qperp0=trace_debug_nan()
3602 result%bfactor_qperp0=trace_debug_nan()
3603 result%forward_Bn_q0=trace_debug_nan()
3604 result%backward_Bn_q0=trace_debug_nan()
3605 result%valid_q0=.false.
3608 result%status_q0=result%forward_status
3612 result%status_q0=result%backward_status
3616 bseed_norm=dsqrt(sum(result%B_seed**2))
3617 if (bseed_norm<=zero .or. bseed_norm<field_min)
then
3622 call trace_qperp_project_to_boundary_face(result%u_forward_perp, &
3623 result%forward_B,result%forward_face,uf_face,bnf,status_f)
3624 call trace_qperp_project_to_boundary_face(result%v_forward_perp, &
3625 result%forward_B,result%forward_face,vf_face,bnf,status_f)
3626 call trace_qperp_project_to_boundary_face(result%u_backward_perp, &
3627 result%backward_B,result%backward_face,ub_face,bnb,status_b)
3628 call trace_qperp_project_to_boundary_face(result%v_backward_perp, &
3629 result%backward_B,result%backward_face,vb_face,bnb,status_b)
3631 result%status_q0=status_f
3635 result%status_q0=status_b
3638 if (abs(bnf)<field_min .or. abs(bnb)<field_min)
then
3643 n2bnd=sum(uf_face**2)*sum(vb_face**2)+ &
3644 sum(ub_face**2)*sum(vf_face**2)- &
3645 2.d0*sum(uf_face*vf_face)*sum(ub_face*vb_face)
3646 result%N2_qperp0=abs(n2bnd)
3647 result%bfactor_qperp0=abs(bnf*bnb)/(bseed_norm**2)
3648 result%forward_Bn_q0=bnf
3649 result%backward_Bn_q0=bnb
3650 qtmp=result%N2_qperp0*result%bfactor_qperp0
3651 if (qtmp>zero .and. ieee_is_finite(qtmp))
then
3652 qtmp=max(qtmp,trace_q_min)
3654 result%logq0=dlog10(qtmp)
3655 result%valid_q0=.true.
3658 result%q0=trace_debug_nan()
3659 result%logq0=trace_debug_nan()
3660 result%valid_q0=.false.
3663 end subroutine trace_qperp_compute_q0_scalars
3665 subroutine trace_qperp_project_to_boundary_face(vec,B,face_id,vec_face, &
3667 double precision,
intent(in) :: vec(
ndim),b(
ndim)
3668 integer,
intent(in) :: face_id
3669 double precision,
intent(out) :: vec_face(
ndim),bn
3670 integer,
intent(out) :: status
3672 double precision :: normal(
ndim),vecn
3678 call trace_face_normal(face_id,normal,ok)
3685 vecn=sum(vec*normal)
3686 vec_face=vec-vecn/bn*b
3688 end subroutine trace_qperp_project_to_boundary_face
3690 subroutine trace_qperp_finalize_from_states(forward_state,backward_state, &
3692 type(trace_tangent_state),
intent(in) :: forward_state,backward_state
3694 double precision,
intent(in) :: field_min
3696 result%forward_endpoint=forward_state%endpoint
3697 result%forward_B=forward_state%endpoint_B
3698 result%forward_bhat=forward_state%endpoint_bhat
3699 result%forward_length=forward_state%length
3700 result%forward_nstep=forward_state%nstep
3701 result%forward_face=forward_state%face_id
3702 result%forward_status=forward_state%status
3703 result%u_forward_perp=forward_state%u_perp
3704 result%v_forward_perp=forward_state%v_perp
3706 result%backward_endpoint=backward_state%endpoint
3707 result%backward_B=backward_state%endpoint_B
3708 result%backward_bhat=backward_state%endpoint_bhat
3709 result%backward_length=backward_state%length
3710 result%backward_nstep=backward_state%nstep
3711 result%backward_face=backward_state%face_id
3712 result%backward_status=backward_state%status
3713 result%u_backward_perp=backward_state%u_perp
3714 result%v_backward_perp=backward_state%v_perp
3717 result%status=forward_state%status
3721 result%status=backward_state%status
3725 call trace_qperp_compute_scalars(result,field_min)
3726 end subroutine trace_qperp_finalize_from_states
3728 subroutine trace_q0_finalize_from_states(forward_state,backward_state, &
3730 type(trace_tangent_state),
intent(in) :: forward_state,backward_state
3732 double precision,
intent(in) :: field_min
3734 result%forward_endpoint=forward_state%endpoint
3735 result%forward_B=forward_state%endpoint_B
3736 result%forward_bhat=forward_state%endpoint_bhat
3737 result%forward_length=forward_state%length
3738 result%forward_nstep=forward_state%nstep
3739 result%forward_face=forward_state%face_id
3740 result%forward_status=forward_state%status
3741 result%u_forward_perp=forward_state%u_perp
3742 result%v_forward_perp=forward_state%v_perp
3744 result%backward_endpoint=backward_state%endpoint
3745 result%backward_B=backward_state%endpoint_B
3746 result%backward_bhat=backward_state%endpoint_bhat
3747 result%backward_length=backward_state%length
3748 result%backward_nstep=backward_state%nstep
3749 result%backward_face=backward_state%face_id
3750 result%backward_status=backward_state%status
3751 result%u_backward_perp=backward_state%u_perp
3752 result%v_backward_perp=backward_state%v_perp
3755 result%status=forward_state%status
3756 result%status_q0=forward_state%status
3760 result%status=backward_state%status
3761 result%status_q0=backward_state%status
3766 call trace_qperp_compute_q0_scalars(result,field_min)
3767 end subroutine trace_q0_finalize_from_states
3769 subroutine trace_spherical_rmin_q_prepare_seed_result(seed,field_min, &
3770 result,igrid,status)
3771 double precision,
intent(in) :: seed(
ndim),field_min
3773 integer,
intent(out) :: igrid,status
3775 double precision :: bcart(3),bhat_cart(3),er(3),etheta(3),ephi(3)
3776 double precision :: radial_tol
3779 call trace_init_qperp_result(seed,result)
3783 if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
then
3785 result%status=status
3786 result%status_q0=status
3791 {
if (trace_coordinate_in_domain(seed(^db),^db)) indomain=indomain+1\}
3792 if (indomain/=
ndim)
then
3794 result%status=status
3795 result%status_q0=status
3799 call trace_debug_locate_point(seed,igrid,status)
3801 result%status=status
3802 result%status_q0=status
3807 call trace_spherical_sample_b_bhat_cart(seed,igrid,field_min,bcart, &
3810 result%status=status
3811 result%status_q0=status
3814 call trace_spherical_basis(seed,er,etheta,ephi,status)
3816 result%status=status
3817 result%status_q0=status
3820 result%B_seed=bcart(1:
ndim)
3821 result%bhat_seed=bhat_cart(1:
ndim)
3822 radial_tol=100.d0*epsilon(one)*max(one,abs(xprobmin1),abs(xprobmax1))
3825 if (abs(seed(1)-xprobmin1)<=radial_tol .or. &
3826 abs(seed(1)-xprobmax1)<=radial_tol)
then
3827 result%u0=etheta(1:
ndim)
3828 result%v0=ephi(1:
ndim)
3830 call trace_make_perp_basis(bhat_cart,result%u0,result%v0,status)
3832 result%status=status
3833 result%status_q0=status
3838 end subroutine trace_spherical_rmin_q_prepare_seed_result
3840 subroutine trace_spherical_rmin_q_finalize_from_states(forward_state, &
3841 backward_state,result,field_min)
3842 type(trace_tangent_state),
intent(in) :: forward_state,backward_state
3844 double precision,
intent(in) :: field_min
3846 call trace_spherical_radial_q_finalize_from_states(forward_state, &
3847 backward_state,result,field_min)
3849 end subroutine trace_spherical_rmin_q_finalize_from_states
3851 subroutine trace_spherical_radial_q_finalize_from_states(forward_state, &
3852 backward_state,result,field_min)
3853 type(trace_tangent_state),
intent(in) :: forward_state,backward_state
3855 double precision,
intent(in) :: field_min
3857 double precision :: bnf,bnb,frob2,qtmp,logqtmp,bfactor
3858 double precision :: af(2,2),ab(2,2)
3859 integer :: status_f,status_b,status_q
3862 result%forward_endpoint=forward_state%endpoint
3863 result%forward_B=forward_state%endpoint_B
3864 result%forward_bhat=forward_state%endpoint_bhat
3865 result%forward_length=forward_state%length
3866 result%forward_nstep=forward_state%nstep
3867 result%forward_face=forward_state%face_id
3868 result%forward_status=forward_state%status
3869 result%u_forward_perp=forward_state%u
3870 result%v_forward_perp=forward_state%v
3872 result%backward_endpoint=backward_state%endpoint
3873 result%backward_B=backward_state%endpoint_B
3874 result%backward_bhat=backward_state%endpoint_bhat
3875 result%backward_length=backward_state%length
3876 result%backward_nstep=backward_state%nstep
3877 result%backward_face=backward_state%face_id
3878 result%backward_status=backward_state%status
3879 result%u_backward_perp=backward_state%u
3880 result%v_backward_perp=backward_state%v
3882 result%q0=trace_debug_nan()
3883 result%logq0=trace_debug_nan()
3884 result%N2_qperp0=trace_debug_nan()
3885 result%bfactor_qperp0=trace_debug_nan()
3886 result%forward_Bn_q0=trace_debug_nan()
3887 result%backward_Bn_q0=trace_debug_nan()
3888 result%valid_q0=.false.
3891 result%status_q0=forward_state%status
3892 result%status=forward_state%status
3896 result%status_q0=backward_state%status
3897 result%status=backward_state%status
3902 if (.not.trace_spherical_radial_q_face_pair_admitted( &
3903 forward_state%face_id,backward_state%face_id))
then
3908 if (dsqrt(sum(result%B_seed**2))<=zero .or. &
3909 dsqrt(sum(result%B_seed**2))<field_min)
then
3914 call trace_spherical_radial_endpoint_matrix(forward_state,af,bnf,status_f)
3915 result%forward_Bn_q0=bnf
3917 result%status_q0=status_f
3921 call trace_spherical_radial_endpoint_matrix(backward_state,ab,bnb,status_b)
3922 result%backward_Bn_q0=bnb
3924 result%status_q0=status_b
3928 if (abs(bnf)<1.
d-10 .or. abs(bnb)<1.
d-10)
then
3933 call trace_spherical_q_from_endpoint_matrices(af,ab,qtmp,logqtmp, &
3934 frob2,bfactor,valid_q,status_q)
3935 result%N2_qperp0=frob2
3936 result%bfactor_qperp0=bfactor
3937 if (.not.valid_q)
then
3938 result%status_q0=status_q
3943 result%logq0=logqtmp
3944 result%valid_q0=.true.
3946 end subroutine trace_spherical_radial_q_finalize_from_states
3948 logical function trace_spherical_radial_q_face_pair_admitted(face_forward, &
3949 face_backward)
result(is_admitted)
3950 integer,
intent(in) :: face_forward,face_backward
3953 select case (face_forward)
3961 end function trace_spherical_radial_q_face_pair_admitted
3963 subroutine trace_spherical_radial_endpoint_matrix(state,Amat,Bn,status)
3964 type(trace_tangent_state),
intent(in) :: state
3965 double precision,
intent(out) :: amat(2,2),bn
3966 integer,
intent(out) :: status
3968 double precision :: u_face(
ndim),v_face(
ndim)
3969 double precision :: er(3),etheta(3),ephi(3)
3970 double precision :: bn_u,bn_v
3971 integer :: status_u,status_v,basis_status
3977 call trace_spherical_radial_project_to_surface(state%u,state%endpoint_B, &
3978 state%endpoint,state%face_id,u_face,bn_u,status_u)
3984 call trace_spherical_radial_project_to_surface(state%v,state%endpoint_B, &
3985 state%endpoint,state%face_id,v_face,bn_v,status_v)
3994 call trace_spherical_basis(state%endpoint,er,etheta,ephi,basis_status)
3999 amat(1,1)=sum(u_face*etheta(1:
ndim))
4000 amat(2,1)=sum(u_face*ephi(1:
ndim))
4001 amat(1,2)=sum(v_face*etheta(1:
ndim))
4002 amat(2,2)=sum(v_face*ephi(1:
ndim))
4005 end subroutine trace_spherical_radial_endpoint_matrix
4007 subroutine trace_spherical_radial_project_to_surface(vec,B,x,face_id, &
4009 double precision,
intent(in) :: vec(
ndim),b(
ndim),x(
ndim)
4010 integer,
intent(in) :: face_id
4011 double precision,
intent(out) :: vec_face(
ndim),bn
4012 integer,
intent(out) :: status
4014 double precision :: er(3),etheta(3),ephi(3),normal(
ndim),vecn
4015 double precision :: bhat(
ndim),bnorm
4020 if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
return
4023 call trace_spherical_basis(x,er,etheta,ephi,status)
4025 select case (face_id)
4034 bnorm=dsqrt(sum(b**2))
4035 if (bnorm<=smalldouble)
then
4041 if (abs(bn)<=smalldouble)
then
4045 vecn=sum(vec*normal)
4046 vec_face=vec-vecn/bn*bhat
4049 end subroutine trace_spherical_radial_project_to_surface
4051 subroutine trace_spherical_qperp_prepare_seed_result(seed,field_min, &
4052 result,igrid,status)
4053 double precision,
intent(in) :: seed(
ndim),field_min
4055 integer,
intent(out) :: igrid,status
4057 double precision :: bcart(3),bhat_cart(3)
4060 call trace_init_qperp_result(seed,result)
4064 if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
then
4066 result%status=status
4071 {
if (trace_coordinate_in_domain(seed(^db),^db)) indomain=indomain+1\}
4072 if (indomain/=
ndim)
then
4074 result%status=status
4078 call trace_debug_locate_point(seed,igrid,status)
4080 result%status=status
4085 call trace_spherical_sample_b_bhat_cart(seed,igrid,field_min,bcart, &
4088 result%status=status
4091 result%B_seed=bcart(1:
ndim)
4092 result%bhat_seed=bhat_cart(1:
ndim)
4093 call trace_make_perp_basis(bhat_cart,result%u0,result%v0,status)
4096 end subroutine trace_spherical_qperp_prepare_seed_result
4098 subroutine trace_spherical_qperp_finalize_from_states(forward_state, &
4099 backward_state,result,field_min)
4100 type(trace_tangent_state),
intent(in) :: forward_state,backward_state
4102 double precision,
intent(in) :: field_min
4104 result%forward_endpoint=forward_state%endpoint
4105 result%forward_B=forward_state%endpoint_B
4106 result%forward_bhat=forward_state%endpoint_bhat
4107 result%forward_length=forward_state%length
4108 result%forward_nstep=forward_state%nstep
4109 result%forward_face=forward_state%face_id
4110 result%forward_status=forward_state%status
4111 result%u_forward_perp=forward_state%u_perp
4112 result%v_forward_perp=forward_state%v_perp
4114 result%backward_endpoint=backward_state%endpoint
4115 result%backward_B=backward_state%endpoint_B
4116 result%backward_bhat=backward_state%endpoint_bhat
4117 result%backward_length=backward_state%length
4118 result%backward_nstep=backward_state%nstep
4119 result%backward_face=backward_state%face_id
4120 result%backward_status=backward_state%status
4121 result%u_backward_perp=backward_state%u_perp
4122 result%v_backward_perp=backward_state%v_perp
4125 result%status=forward_state%status
4126 result%status_qperp0=forward_state%status
4130 result%status=backward_state%status
4131 result%status_qperp0=backward_state%status
4135 call trace_spherical_qperp_compute_from_states(result,field_min)
4136 end subroutine trace_spherical_qperp_finalize_from_states
4138 subroutine trace_spherical_qperp_compute_from_states(result,field_min)
4140 double precision,
intent(in) :: field_min
4143 double precision :: forward_bhat3(3),backward_bhat3(3)
4144 double precision :: af(2,2),ab(2,2)
4145 double precision :: bseed_norm,bf_norm,bb_norm,frob2,qtmp,logqtmp,bfactor
4146 integer :: status_f,status_b,status_q
4149 result%qperp=trace_debug_nan()
4150 result%logqperp=trace_debug_nan()
4151 result%N2=trace_debug_nan()
4152 result%bfactor=trace_debug_nan()
4153 result%qperp0=trace_debug_nan()
4154 result%logqperp0=trace_debug_nan()
4155 result%N2_qperp0=trace_debug_nan()
4156 result%bfactor_qperp0=trace_debug_nan()
4157 result%valid=.false.
4158 result%valid_qperp0=.false.
4166 bseed_norm=dsqrt(sum(result%B_seed**2))
4167 bf_norm=dsqrt(sum(result%forward_B**2))
4168 bb_norm=dsqrt(sum(result%backward_B**2))
4169 if (bseed_norm<=zero .or. bf_norm<=zero .or. bb_norm<=zero .or. &
4170 bseed_norm<field_min .or. bf_norm<field_min .or. &
4171 bb_norm<field_min)
then
4179 forward_bhat3(1:
ndim)=result%forward_bhat
4180 backward_bhat3(1:
ndim)=result%backward_bhat
4181 call trace_make_perp_basis(forward_bhat3,f1,f2,status_f)
4182 call trace_make_perp_basis(backward_bhat3,b1,b2,status_b)
4184 result%status=status_f
4185 result%status_qperp0=status_f
4189 result%status=status_b
4190 result%status_qperp0=status_b
4194 af(1,1)=sum(result%u_forward_perp*f1)
4195 af(2,1)=sum(result%u_forward_perp*f2)
4196 af(1,2)=sum(result%v_forward_perp*f1)
4197 af(2,2)=sum(result%v_forward_perp*f2)
4198 ab(1,1)=sum(result%u_backward_perp*b1)
4199 ab(2,1)=sum(result%u_backward_perp*b2)
4200 ab(1,2)=sum(result%v_backward_perp*b1)
4201 ab(2,2)=sum(result%v_backward_perp*b2)
4203 call trace_spherical_q_from_endpoint_matrices(af,ab,qtmp,logqtmp, &
4204 frob2,bfactor,valid_q,status_q)
4206 result%bfactor=bfactor
4207 result%N2_qperp0=frob2
4208 result%bfactor_qperp0=bfactor
4209 if (.not.valid_q)
then
4210 result%status=status_q
4211 result%status_qperp0=status_q
4216 result%logqperp=logqtmp
4220 result%logqperp0=result%logqperp
4221 result%valid_qperp0=.true.
4223 end subroutine trace_spherical_qperp_compute_from_states
4225 subroutine trace_spherical_q_from_endpoint_matrices(Af,Ab,qval,logq, &
4226 frob2,bfactor,valid,status)
4227 double precision,
intent(in) :: af(2,2),ab(2,2)
4228 double precision,
intent(out) :: qval,logq,frob2,bfactor
4229 logical,
intent(out) :: valid
4230 integer,
intent(out) :: status
4232 double precision :: dmat(2,2),detab,detd,q_tol,det_tol
4234 qval=trace_debug_nan()
4235 logq=trace_debug_nan()
4236 frob2=trace_debug_nan()
4237 bfactor=trace_debug_nan()
4241 detab=ab(1,1)*ab(2,2)-ab(1,2)*ab(2,1)
4243 if (.not.ieee_is_finite(detab) .or. abs(detab)<=det_tol)
then
4248 dmat(1,1)=(af(1,1)*ab(2,2)-af(1,2)*ab(2,1))/detab
4249 dmat(1,2)=(-af(1,1)*ab(1,2)+af(1,2)*ab(1,1))/detab
4250 dmat(2,1)=(af(2,1)*ab(2,2)-af(2,2)*ab(2,1))/detab
4251 dmat(2,2)=(-af(2,1)*ab(1,2)+af(2,2)*ab(1,1))/detab
4252 detd=dmat(1,1)*dmat(2,2)-dmat(1,2)*dmat(2,1)
4255 if (.not.ieee_is_finite(detd) .or. abs(detd)<=det_tol)
then
4260 qval=frob2/abs(detd)
4262 if (qval>zero .and. ieee_is_finite(qval))
then
4263 if (qval<trace_q_min-q_tol)
then
4267 qval=max(qval,trace_q_min)
4272 qval=trace_debug_nan()
4273 logq=trace_debug_nan()
4278 end subroutine trace_spherical_q_from_endpoint_matrices
4280 subroutine trace_spherical_basis(x,er,etheta,ephi,status)
4281 double precision,
intent(in) :: x(
ndim)
4282 double precision,
intent(out) :: er(3),etheta(3),ephi(3)
4283 integer,
intent(out) :: status
4285 double precision :: theta,phi,sint,cost,sinp,cosp
4291 if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
return
4294 if (.not.trace_spherical_metric_ok(x))
then
4304 er=(/ sint*cosp,sint*sinp,cost /)
4305 etheta=(/ cost*cosp,cost*sinp,-sint /)
4306 ephi=(/ -sinp,cosp,zero /)
4309 end subroutine trace_spherical_basis
4311 subroutine trace_spherical_coord_to_cart(x,xcart,status)
4312 double precision,
intent(in) :: x(
ndim)
4313 double precision,
intent(out) :: xcart(3)
4314 integer,
intent(out) :: status
4316 double precision :: r,theta,phi,sint
4320 if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
return
4323 if (.not.trace_spherical_metric_ok(x))
then
4331 xcart(1)=r*sint*dcos(phi)
4332 xcart(2)=r*sint*dsin(phi)
4333 xcart(3)=r*dcos(theta)
4336 end subroutine trace_spherical_coord_to_cart
4338 subroutine trace_cart_to_spherical_coord(xcart,x,status)
4339 double precision,
intent(in) :: xcart(3)
4340 double precision,
intent(out) :: x(
ndim)
4341 integer,
intent(out) :: status
4343 double precision :: r,rho,phi,twopi
4347 if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
return
4350 r=dsqrt(sum(xcart**2))
4351 if (r<=100.d0*epsilon(one))
then
4355 rho=dsqrt(xcart(1)**2+xcart(2)**2)
4356 phi=datan2(xcart(2),xcart(1))
4357 twopi=2.d0*dacos(-one)
4358 if (phi<xprobmin3 .and. phi+twopi<xprobmax3) phi=phi+twopi
4359 if (phi>=xprobmax3 .and. phi-twopi>=xprobmin3) phi=phi-twopi
4361 x(2)=datan2(rho,xcart(3))
4363 call trace_normalize_position(x)
4366 end subroutine trace_cart_to_spherical_coord
4368 subroutine trace_spherical_interp_ctx_build(x_input,igrid_input,ctx,status)
4369 double precision,
intent(in) :: x_input(
ndim)
4370 integer,
intent(in) :: igrid_input
4371 type(trace_sph_interp_ctx),
intent(out) :: ctx
4372 integer,
intent(out) :: status
4374 double precision :: xd^
d,dxc^
d
4375 double precision :: t0
4376 integer :: ixi^
l,ixbl^
d
4378 double precision :: x(
ndim)
4379 integer :: igrid,locate_status
4382 call trace_normalize_position(x)
4384 if (trace_periodic_phi())
then
4385 call trace_locate_point_with_hint(x,igrid_input,igrid,locate_status)
4387 status=locate_status
4391 if (trace_spherical_profile_enabled)
then
4392 call trace_spherical_profile_add_count(trace_profile_context_requests, &
4394 call trace_spherical_profile_add_count( &
4395 trace_profile_full_context_builds,1_8)
4396 t0=trace_spherical_profile_time()
4416 ctx%bcorner_valid=.false.
4418 ctx%slopes_valid=.false.
4420 if (
ndim/=3 .or. geo_coordinate/=geo_spherical .or. igrid<0)
then
4421 if (trace_spherical_profile_enabled)
then
4422 call trace_spherical_profile_add_count(trace_profile_context_failures, &
4424 call trace_spherical_profile_add_time(trace_profile_time_context, &
4425 trace_spherical_profile_time()-t0)
4432 if (.not.trace_spherical_metric_ok(x))
then
4434 if (trace_spherical_profile_enabled)
then
4435 call trace_spherical_profile_add_count(trace_profile_context_failures, &
4437 call trace_spherical_profile_add_time(trace_profile_time_context, &
4438 trace_spherical_profile_time()-t0)
4444 call trace_interp_weights_block(x,igrid,ixi^
l,ixbl^
d,xd^
d,dxc^
d,status)
4446 if (trace_spherical_profile_enabled)
then
4447 call trace_spherical_profile_add_count(trace_profile_context_failures, &
4449 call trace_spherical_profile_add_time(trace_profile_time_context, &
4450 trace_spherical_profile_time()-t0)
4455 call trace_spherical_interp_ctx_fill(x,igrid,ixbl^
d,xd^
d,dxc^
d,ctx, &
4458 call trace_spherical_interp_ctx_load_bcorners(ctx,status)
4460 if (trace_spherical_profile_enabled)
then
4462 call trace_spherical_profile_add_count(trace_profile_context_failures, &
4465 call trace_spherical_profile_add_time(trace_profile_time_context, &
4466 trace_spherical_profile_time()-t0)
4469 end subroutine trace_spherical_interp_ctx_build
4471 subroutine trace_spherical_interp_ctx_build_cached(x_input,igrid_input,cache,ctx,status)
4472 double precision,
intent(in) :: x_input(
ndim)
4473 integer,
intent(in) :: igrid_input
4474 type(trace_sph_interp_ctx),
intent(inout) :: cache
4475 type(trace_sph_interp_ctx),
intent(out) :: ctx
4476 integer,
intent(out) :: status
4478 double precision :: xd^
d,dxc^
d
4479 double precision :: t0
4480 integer :: ixi^
l,ixbl^
d
4481 logical :: same_cell
4483 double precision :: x(
ndim)
4484 integer :: igrid,locate_status
4487 call trace_normalize_position(x)
4489 if (trace_periodic_phi())
then
4490 call trace_locate_point_with_hint(x,igrid_input,igrid,locate_status)
4492 status=locate_status
4496 if (trace_spherical_profile_enabled)
then
4497 call trace_spherical_profile_add_count(trace_profile_context_requests, &
4499 t0=trace_spherical_profile_time()
4503 if (
ndim/=3 .or. geo_coordinate/=geo_spherical .or. igrid<0)
then
4504 if (trace_spherical_profile_enabled)
then
4505 call trace_spherical_profile_add_count(trace_profile_context_failures, &
4507 call trace_spherical_profile_add_time(trace_profile_time_context, &
4508 trace_spherical_profile_time()-t0)
4510 call trace_spherical_interp_ctx_build(x,igrid,ctx,status)
4515 if (cache%valid .and. cache%igrid==igrid)
then
4517 call trace_interp_weights_block_near(x,igrid,ixi^
l,cache%ixbl, &
4518 ixbl^
d,xd^
d,dxc^
d,status)
4520 call trace_spherical_interp_ctx_fill(x,igrid,ixbl^
d,xd^
d,dxc^
d, &
4523 same_cell=(ixbl1==cache%ixbl(1) .and. ixbl2==cache%ixbl(2) .and. &
4524 ixbl3==cache%ixbl(3))
4525 if (same_cell .and. cache%bcorner_valid)
then
4526 ctx%bcorner_valid=.true.
4527 ctx%bcorner=cache%bcorner
4528 ctx%slopes_valid=cache%slopes_valid
4529 ctx%slopes=cache%slopes
4530 if (trace_spherical_profile_enabled)
then
4531 call trace_spherical_profile_add_count( &
4532 trace_profile_b_corner_hits,1_8)
4535 call trace_spherical_interp_ctx_load_bcorners(ctx,status)
4540 if (trace_spherical_profile_enabled)
then
4542 call trace_spherical_profile_add_count( &
4543 trace_profile_same_cell_hits,1_8)
4545 call trace_spherical_profile_add_count( &
4546 trace_profile_same_grid_hits,1_8)
4548 call trace_spherical_profile_add_time(trace_profile_time_context, &
4549 trace_spherical_profile_time()-t0)
4551 else if (trace_spherical_profile_enabled)
then
4552 call trace_spherical_profile_add_count(trace_profile_context_failures, &
4554 call trace_spherical_profile_add_time(trace_profile_time_context, &
4555 trace_spherical_profile_time()-t0)
4559 else if (cache%valid .and. trace_spherical_profile_enabled)
then
4560 call trace_spherical_profile_add_count(trace_profile_cache_invalidations, &
4564 if (trace_spherical_profile_enabled)
then
4565 call trace_spherical_profile_add_time(trace_profile_time_context, &
4566 trace_spherical_profile_time()-t0)
4568 call trace_spherical_interp_ctx_build(x,igrid,ctx,status)
4571 end subroutine trace_spherical_interp_ctx_build_cached
4573 subroutine trace_spherical_interp_ctx_fill(x,igrid,ixbl^D,xd^D,dxc^D,ctx, &
4575 double precision,
intent(in) :: x(
ndim)
4576 integer,
intent(in) :: igrid,ixbl^
d
4577 double precision,
intent(in) :: xd^
d,dxc^
d
4578 type(trace_sph_interp_ctx),
intent(out) :: ctx
4579 integer,
intent(out) :: status
4581 if (trace_spherical_profile_enabled)
then
4582 call trace_spherical_profile_add_count(trace_profile_hlocal_evals,1_8)
4602 ctx%bcorner_valid=.false.
4604 ctx%slopes_valid=.false.
4606 if (
ndim/=3 .or. geo_coordinate/=geo_spherical .or. igrid<0)
return
4611 ctx%ixbl=(/ixbl1,ixbl2,ixbl3/)
4612 ctx%xd=(/xd1,xd2,xd3/)
4613 ctx%dxc=(/dxc1,dxc2,dxc3/)
4621 ctx%dxloc(1)=min(abs(ps(igrid)%dx(ixbl1,ixbl2,ixbl3,1)), &
4622 abs(ps(igrid)%dx(ixbl1+1,ixbl2,ixbl3,1)))
4623 ctx%dxloc(2)=min(abs(ps(igrid)%dx(ixbl1,ixbl2,ixbl3,2)), &
4624 abs(ps(igrid)%dx(ixbl1,ixbl2+1,ixbl3,2)))
4625 ctx%dxloc(3)=min(abs(ps(igrid)%dx(ixbl1,ixbl2,ixbl3,3)), &
4626 abs(ps(igrid)%dx(ixbl1,ixbl2,ixbl3+1,3)))
4627 ctx%dxloc=max(ctx%dxloc,smalldouble)
4632 ctx%sin_theta=dsin(ctx%theta)
4633 ctx%cos_theta=dcos(ctx%theta)
4634 ctx%sin_phi=dsin(ctx%phi)
4635 ctx%cos_phi=dcos(ctx%phi)
4636 ctx%rsin_theta=ctx%r*ctx%sin_theta
4637 if (ctx%r<=smalldouble .or. abs(ctx%sin_theta)<=smalldouble)
then
4642 ctx%h_local=trace_spherical_cell_scale_from_widths(ctx%r, &
4643 ctx%sin_theta,ctx%dxloc)
4644 ctx%h_local=max(ctx%h_local,smalldouble)
4648 end subroutine trace_spherical_interp_ctx_fill
4650 subroutine trace_spherical_interp_ctx_load_bcorners(ctx,status)
4651 type(trace_sph_interp_ctx),
intent(inout) :: ctx
4652 integer,
intent(out) :: status
4654 integer :: i1,i2,i3,igrid,ix1,ix2,ix3
4657 if (.not.ctx%valid)
return
4658 if (ctx%bcorner_valid)
then
4659 if (trace_spherical_profile_enabled)
then
4660 call trace_spherical_profile_add_count(trace_profile_b_corner_hits, &
4666 if (.not.
b0field .and. .not.
allocated(iw_mag))
return
4677 if (
allocated(iw_mag))
then
4678 ctx%bcorner(i1,i2,i3,1:3)= &
4679 ps(igrid)%w(ix1,ix2,ix3,iw_mag(1:3))
4682 ctx%bcorner(i1,i2,i3,1:3)= &
4683 ctx%bcorner(i1,i2,i3,1:3) &
4684 +ps(igrid)%B0(ix1,ix2,ix3,1:3,0)
4689 ctx%bcorner_valid=.true.
4690 if (trace_periodic_phi())
call trace_spherical_corner_slopes(ctx)
4691 if (trace_spherical_profile_enabled)
then
4692 call trace_spherical_profile_add_count(trace_profile_b_corner_loads, &
4697 end subroutine trace_spherical_interp_ctx_load_bcorners
4699 subroutine trace_spherical_corner_slopes(ctx)
4705 type(trace_sph_interp_ctx),
intent(inout) :: ctx
4706 integer :: i1,i2,i3,j,ig,idx(3),im(3),ip(3),stat
4707 double precision :: bm(3),bp(3),bmid(3),hm,hp
4710 if (any(ctx%ixbl-1<(/ixglo1,ixglo2,ixglo3/)) .or. &
4711 any(ctx%ixbl+2>(/ixghi1,ixghi2,ixghi3/)))
return
4715 idx=ctx%ixbl+(/i1,i2,i3/)
4716 bmid=ctx%bcorner(i1,i2,i3,:)
4719 im(j)=im(j)-1; ip(j)=ip(j)+1
4720 hm=ps(ig)%x(idx(1),idx(2),idx(3),j) &
4721 -ps(ig)%x(im(1),im(2),im(3),j)
4722 hp=ps(ig)%x(ip(1),ip(2),ip(3),j) &
4723 -ps(ig)%x(idx(1),idx(2),idx(3),j)
4724 if (min(hm,hp)<=smalldouble)
return
4725 call trace_total_b_at_cell(ig,im(1),im(2),im(3),bm,stat)
4727 call trace_total_b_at_cell(ig,ip(1),ip(2),ip(3),bp,stat)
4729 ctx%slopes(i1,i2,i3,:,j)= &
4730 (hp*(bmid-bm)/hm+hm*(bp-bmid)/hp)/(hm+hp)
4735 ctx%slopes_valid=.true.
4737 end subroutine trace_spherical_corner_slopes
4739 double precision function trace_spherical_effective_step_ctx(ds,ctx) &
4741 double precision,
intent(in) :: ds
4742 type(trace_sph_interp_ctx),
intent(in) :: ctx
4744 double precision :: step_cap,t0
4746 if (trace_spherical_profile_enabled) t0=trace_spherical_profile_time()
4749 if (.not.ctx%valid)
then
4750 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4751 trace_profile_time_step,trace_spherical_profile_time()-t0)
4755 if (ctx%h_local<=zero)
then
4756 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4757 trace_profile_time_step,trace_spherical_profile_time()-t0)
4760 select case (trace_step_control_mode)
4761 case (trace_step_control_cell_fraction)
4762 ds_eff=min(step_cap,trace_step_fraction*ctx%h_local)
4763 if (trace_step_min>zero) ds_eff=max(ds_eff,min(trace_step_min,step_cap))
4765 ds_eff=min(step_cap,ctx%h_local)
4767 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4768 trace_profile_time_step,trace_spherical_profile_time()-t0)
4769 end function trace_spherical_effective_step_ctx
4771 subroutine trace_spherical_sample_bsph_ctx(ctx,threshold,Bsph,status)
4772 type(trace_sph_interp_ctx),
intent(in) :: ctx
4773 double precision,
intent(in) :: threshold
4774 double precision,
intent(out) :: bsph(3)
4775 integer,
intent(out) :: status
4777 double precision :: b2,weight
4778 double precision :: t0
4779 integer :: i1,i2,i3,j
4781 if (trace_spherical_profile_enabled)
then
4782 call trace_spherical_profile_add_count(trace_profile_b_samples,1_8)
4783 t0=trace_spherical_profile_time()
4788 if (.not.ctx%valid)
then
4789 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4790 trace_profile_time_b_interp,trace_spherical_profile_time()-t0)
4793 if (.not.ctx%bcorner_valid)
then
4794 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4795 trace_profile_time_b_interp,trace_spherical_profile_time()-t0)
4803 weight=ctx%w(i1,1)*ctx%w(i2,2)*ctx%w(i3,3)
4805 bsph(j)=bsph(j)+ctx%bcorner(i1,i2,i3,j)*weight
4811 if (b2<=zero .or. dsqrt(b2)<threshold)
then
4813 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4814 trace_profile_time_b_interp,trace_spherical_profile_time()-t0)
4818 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4819 trace_profile_time_b_interp,trace_spherical_profile_time()-t0)
4821 end subroutine trace_spherical_sample_bsph_ctx
4823 subroutine trace_spherical_sample_b_bhat_cart_ctx(ctx,threshold,Bcart, &
4825 type(trace_sph_interp_ctx),
intent(in) :: ctx
4826 double precision,
intent(in) :: threshold
4827 double precision,
intent(out) :: bcart(3),bhat_cart(3)
4828 integer,
intent(out) :: status
4830 double precision :: bsph(3),bnorm
4834 call trace_spherical_sample_bsph_ctx(ctx,threshold,bsph,status)
4837 bcart(1)=bsph(1)*ctx%sin_theta*ctx%cos_phi &
4838 +bsph(2)*ctx%cos_theta*ctx%cos_phi &
4839 -bsph(3)*ctx%sin_phi
4840 bcart(2)=bsph(1)*ctx%sin_theta*ctx%sin_phi &
4841 +bsph(2)*ctx%cos_theta*ctx%sin_phi &
4842 +bsph(3)*ctx%cos_phi
4843 bcart(3)=bsph(1)*ctx%cos_theta-bsph(2)*ctx%sin_theta
4844 bnorm=dsqrt(sum(bcart**2))
4845 if (bnorm<=zero .or. bnorm<threshold)
then
4849 bhat_cart=bcart/bnorm
4851 end subroutine trace_spherical_sample_b_bhat_cart_ctx
4853 subroutine trace_spherical_sample_cached_curlb_ctx(ctx,curlB,status)
4854 type(trace_sph_interp_ctx),
intent(in) :: ctx
4855 double precision,
intent(out) :: curlb(3)
4856 integer,
intent(out) :: status
4858 double precision :: weight
4859 double precision :: t0
4860 integer :: i1,i2,i3,j,igrid,ix1,ix2,ix3
4862 if (trace_spherical_profile_enabled)
then
4863 call trace_spherical_profile_add_count(trace_profile_curl_samples,1_8)
4864 t0=trace_spherical_profile_time()
4869 if (.not.ctx%valid)
then
4870 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4871 trace_profile_time_curl_interp,trace_spherical_profile_time()-t0)
4874 if (.not.trace_spherical_curl_cache_ready)
then
4875 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4876 trace_profile_time_curl_interp,trace_spherical_profile_time()-t0)
4879 if (.not.
allocated(trace_spherical_curl_cache))
then
4880 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4881 trace_profile_time_curl_interp,trace_spherical_profile_time()-t0)
4885 if (igrid>
size(trace_spherical_curl_cache))
then
4886 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4887 trace_profile_time_curl_interp,trace_spherical_profile_time()-t0)
4890 if (.not.trace_spherical_curl_cache(igrid)%ready)
then
4891 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4892 trace_profile_time_curl_interp,trace_spherical_profile_time()-t0)
4895 if (.not.
allocated(trace_spherical_curl_cache(igrid)%current))
then
4896 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4897 trace_profile_time_curl_interp,trace_spherical_profile_time()-t0)
4908 weight=ctx%w(i1,1)*ctx%w(i2,2)*ctx%w(i3,3)
4910 curlb(j)=curlb(j)+ &
4911 trace_spherical_curl_cache(igrid)%current(ix1,ix2,ix3,j) &
4918 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4919 trace_profile_time_curl_interp,trace_spherical_profile_time()-t0)
4921 end subroutine trace_spherical_sample_cached_curlb_ctx
4923 subroutine trace_spherical_sample_bhat_gradbhat_covariant_ctx(ctx, &
4924 threshold,bhat_cart,grad_bhat_cart,status)
4925 type(trace_sph_interp_ctx),
intent(in) :: ctx
4926 double precision,
intent(in) :: threshold
4927 double precision,
intent(out) :: bhat_cart(3),grad_bhat_cart(3,3)
4928 integer,
intent(out) :: status
4930 double precision :: dw(0:1,3),weight,bnorm,projected
4931 double precision :: bsph(3),bhat_sph(3),dbdq(3,3),dbhatdq(3,3)
4932 double precision :: a_local(3,3),e(3,3)
4933 double precision :: t0
4934 integer :: i1,i2,i3,j
4936 if (trace_spherical_profile_enabled)
then
4937 call trace_spherical_profile_add_count(trace_profile_grad_samples,1_8)
4938 t0=trace_spherical_profile_time()
4944 if (.not.ctx%valid)
then
4945 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4946 trace_profile_time_grad_bhat,trace_spherical_profile_time()-t0)
4949 if (.not.ctx%bcorner_valid)
then
4951 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4952 trace_profile_time_grad_bhat,trace_spherical_profile_time()-t0)
4957 dw(0,1)=-one/ctx%dxc(1)
4958 dw(1,1)= one/ctx%dxc(1)
4959 dw(0,2)=-one/ctx%dxc(2)
4960 dw(1,2)= one/ctx%dxc(2)
4961 dw(0,3)=-one/ctx%dxc(3)
4962 dw(1,3)= one/ctx%dxc(3)
4969 weight=ctx%w(i1,1)*ctx%w(i2,2)*ctx%w(i3,3)
4970 bsph(1:3)=bsph(1:3)+ctx%bcorner(i1,i2,i3,1:3)*weight
4971 dbdq(1:3,1)=dbdq(1:3,1)+ctx%bcorner(i1,i2,i3,1:3)* &
4972 dw(i1,1)*ctx%w(i2,2)*ctx%w(i3,3)
4973 dbdq(1:3,2)=dbdq(1:3,2)+ctx%bcorner(i1,i2,i3,1:3)* &
4974 ctx%w(i1,1)*dw(i2,2)*ctx%w(i3,3)
4975 dbdq(1:3,3)=dbdq(1:3,3)+ctx%bcorner(i1,i2,i3,1:3)* &
4976 ctx%w(i1,1)*ctx%w(i2,2)*dw(i3,3)
4981 if (ctx%slopes_valid)
then
4986 weight=ctx%w(i1,1)*ctx%w(i2,2)*ctx%w(i3,3)
4987 dbdq=dbdq+weight*ctx%slopes(i1,i2,i3,:,:)
4993 bnorm=dsqrt(sum(bsph**2))
4994 if (bnorm<=zero .or. bnorm<threshold)
then
4996 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4997 trace_profile_time_grad_bhat,trace_spherical_profile_time()-t0)
5003 projected=sum(bhat_sph*dbdq(1:3,j))
5004 dbhatdq(1:3,j)=(dbdq(1:3,j)-bhat_sph(1:3)*projected)/bnorm
5007 e(1:3,1)=(/ctx%sin_theta*ctx%cos_phi, &
5008 ctx%sin_theta*ctx%sin_phi,ctx%cos_theta/)
5009 e(1:3,2)=(/ctx%cos_theta*ctx%cos_phi, &
5010 ctx%cos_theta*ctx%sin_phi,-ctx%sin_theta/)
5011 e(1:3,3)=(/-ctx%sin_phi,ctx%cos_phi,zero/)
5012 bhat_cart=bhat_sph(1)*e(1:3,1)+bhat_sph(2)*e(1:3,2) &
5013 +bhat_sph(3)*e(1:3,3)
5015 a_local(1:3,1)=dbhatdq(1:3,1)
5016 a_local(1,2)=(dbhatdq(1,2)-bhat_sph(2))/ctx%r
5017 a_local(2,2)=(dbhatdq(2,2)+bhat_sph(1))/ctx%r
5018 a_local(3,2)= dbhatdq(3,2)/ctx%r
5019 a_local(1,3)=(dbhatdq(1,3)-ctx%sin_theta*bhat_sph(3))/ctx%rsin_theta
5020 a_local(2,3)=(dbhatdq(2,3)-ctx%cos_theta*bhat_sph(3))/ctx%rsin_theta
5021 a_local(3,3)=(dbhatdq(3,3)+ctx%sin_theta*bhat_sph(1) &
5022 +ctx%cos_theta*bhat_sph(2))/ctx%rsin_theta
5024 grad_bhat_cart=matmul(e,matmul(a_local,transpose(e)))
5026 if (trace_spherical_profile_enabled)
then
5027 call trace_spherical_profile_add_count(trace_profile_grad_success,1_8)
5028 call trace_spherical_profile_add_time(trace_profile_time_grad_bhat, &
5029 trace_spherical_profile_time()-t0)
5032 end subroutine trace_spherical_sample_bhat_gradbhat_covariant_ctx
5034 subroutine get_k_spherical_ctx(ctx,K,ftype,b_min,field_ok)
5035 type(trace_sph_interp_ctx),
intent(in) :: ctx
5036 double precision,
intent(out) :: k(
ndim)
5037 character(len=std_len),
intent(in) :: ftype
5038 double precision,
intent(in),
optional :: b_min
5039 logical,
intent(out),
optional :: field_ok
5041 double precision :: b(3),ftotal,field_min
5042 logical :: valid_field
5047 if (ftype/=
'Bfield')
then
5048 if (
present(field_ok)) field_ok=.false.
5051 call trace_spherical_sample_bsph_ctx(ctx,zero,b,status)
5053 if (
present(field_ok)) field_ok=.false.
5056 ftotal=dsqrt(sum(b**2))
5057 field_min=smalldouble
5058 if (
present(b_min)) field_min=max(b_min,zero)
5059 valid_field=ftotal>zero .and. ftotal>=field_min
5060 if (
present(field_ok)) field_ok=valid_field
5061 if (.not.valid_field)
return
5065 k(2)=b(2)/(ctx%r*ftotal)
5066 k(3)=b(3)/(ctx%rsin_theta*ftotal)
5068 end subroutine get_k_spherical_ctx
5070 subroutine trace_spherical_sample_b_bhat_cart(x,igrid,threshold,Bcart, &
5072 double precision,
intent(in) :: x(
ndim),threshold
5073 integer,
intent(in) :: igrid
5074 double precision,
intent(out) :: bcart(3),bhat_cart(3)
5075 integer,
intent(out) :: status
5077 type(trace_sph_interp_ctx) :: ctx
5082 if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
return
5085 call trace_spherical_interp_ctx_build(x,igrid,ctx,status)
5087 call trace_spherical_sample_b_bhat_cart_ctx(ctx,threshold,bcart, &
5090 end subroutine trace_spherical_sample_b_bhat_cart
5092 subroutine trace_spherical_sample_bhat_gradbhat_covariant(x,igrid, &
5093 threshold,bhat_cart,grad_bhat_cart,status)
5094 double precision,
intent(in) :: x(
ndim),threshold
5095 integer,
intent(in) :: igrid
5096 double precision,
intent(out) :: bhat_cart(3),grad_bhat_cart(3,3)
5097 integer,
intent(out) :: status
5099 type(trace_sph_interp_ctx) :: ctx
5104 if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
return
5107 call trace_spherical_interp_ctx_build(x,igrid,ctx,status)
5109 call trace_spherical_sample_bhat_gradbhat_covariant_ctx(ctx,threshold, &
5110 bhat_cart,grad_bhat_cart,status)
5112 end subroutine trace_spherical_sample_bhat_gradbhat_covariant
5114 subroutine trace_spherical_sample_bhat_gradbhat_cartfd(x,igrid,threshold, &
5115 bhat,grad_bhat,status)
5116 double precision,
intent(in) :: x(
ndim),threshold
5117 integer,
intent(in) :: igrid
5118 double precision,
intent(out) :: bhat(3),grad_bhat(3,3)
5119 integer,
intent(out) :: status
5121 double precision :: xcart(3),xplus_cart(3),xminus_cart(3)
5122 double precision :: xplus(
ndim),xminus(
ndim),bplus(3),bminus(3)
5123 double precision :: btmp(3),eps
5124 integer :: j,igrid_plus,igrid_minus,status_plus,status_minus
5129 if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
return
5132 call trace_spherical_sample_b_bhat_cart(x,igrid,threshold,btmp,bhat, &
5135 call trace_spherical_coord_to_cart(x,xcart,status)
5138 eps=max(1.
d-8*max(one,abs(x(1))), &
5139 0.01d0*trace_spherical_physical_cell_scale(x,igrid))
5143 xplus_cart(j)=xplus_cart(j)+eps
5144 xminus_cart(j)=xminus_cart(j)-eps
5147 call trace_cart_to_spherical_coord(xplus_cart,xplus,status_plus)
5149 call trace_locate_point_with_hint(xplus,igrid,igrid_plus,status_plus)
5152 call trace_spherical_sample_b_bhat_cart(xplus,igrid_plus,threshold, &
5153 btmp,bplus,status_plus)
5157 call trace_cart_to_spherical_coord(xminus_cart,xminus,status_minus)
5159 call trace_locate_point_with_hint(xminus,igrid,igrid_minus, &
5163 call trace_spherical_sample_b_bhat_cart(xminus,igrid_minus,threshold, &
5164 btmp,bminus,status_minus)
5169 grad_bhat(:,j)=(bplus-bminus)/(2.d0*eps)
5171 grad_bhat(:,j)=(bplus-bhat)/eps
5173 grad_bhat(:,j)=(bhat-bminus)/eps
5181 end subroutine trace_spherical_sample_bhat_gradbhat_cartfd
5183 subroutine trace_spherical_bhat_cart_to_rhs(x,bhat_cart,kx,status)
5184 double precision,
intent(in) :: x(
ndim),bhat_cart(3)
5185 double precision,
intent(out) :: kx(
ndim)
5186 integer,
intent(out) :: status
5188 double precision :: er(3),etheta(3),ephi(3),r,sint
5192 if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
return
5195 call trace_spherical_basis(x,er,etheta,ephi,status)
5199 if (r<=smalldouble .or. abs(sint)<=smalldouble)
then
5203 kx(1)=sum(bhat_cart*er)
5204 kx(2)=sum(bhat_cart*etheta)/r
5205 kx(3)=sum(bhat_cart*ephi)/(r*sint)
5208 end subroutine trace_spherical_bhat_cart_to_rhs
5210 subroutine trace_spherical_endpoint_b_bhat(x,face_id,igrid,threshold,B, &
5212 double precision,
intent(in) :: x(
ndim),threshold
5213 integer,
intent(in) :: face_id,igrid
5214 double precision,
intent(out) :: b(
ndim),bhat(
ndim)
5215 integer,
intent(out) :: status
5217 double precision :: xprobe(
ndim),bcart(3),bhat_cart(3)
5218 integer :: normal_dim,sample_igrid
5223 if (
ndim/=3 .or. geo_coordinate/=geo_spherical .or. igrid<0)
then
5227 if (.not.trace_face_is_boundary(face_id))
return
5230 select case(face_id)
5248 call trace_spherical_face_probe_coord(face_id,igrid, &
5249 xprobe(normal_dim),status)
5251 xprobe(1)=max(xprobmin1,min(xprobe(1), &
5252 xprobmax1-100.d0*epsilon(one)*max(one,abs(xprobmax1))))
5253 xprobe(2)=max(xprobmin2,min(xprobe(2), &
5254 xprobmax2-100.d0*epsilon(one)*max(one,abs(xprobmax2))))
5255 if (trace_periodic_phi())
then
5256 call trace_normalize_position(xprobe)
5258 xprobe(3)=max(xprobmin3,min(xprobe(3), &
5259 xprobmax3-100.d0*epsilon(one)*max(one,abs(xprobmax3))))
5261 call trace_debug_locate_point(xprobe,sample_igrid,status)
5263 call trace_spherical_sample_b_bhat_cart(xprobe,sample_igrid,threshold, &
5264 bcart,bhat_cart,status)
5267 bhat=bhat_cart(1:
ndim)
5270 end subroutine trace_spherical_endpoint_b_bhat
5272 subroutine trace_spherical_face_probe_coord(face_id,igrid,xprobe,status)
5273 integer,
intent(in) :: face_id,igrid
5274 double precision,
intent(out) :: xprobe
5275 integer,
intent(out) :: status
5277 integer :: i1,i2,i3,normal_dim,side
5279 if (trace_spherical_profile_enabled)
then
5280 call trace_spherical_profile_add_count(trace_profile_face_probes,1_8)
5285 if (
ndim/=3 .or. geo_coordinate/=geo_spherical .or. igrid<0)
then
5294 select case(face_id)
5323 xprobe=ps(igrid)%x(i1,i2,i3,normal_dim)
5325 if (xprobe<xprobmin1 .and. normal_dim==1)
return
5326 if (xprobe<xprobmin2 .and. normal_dim==2)
return
5327 if (xprobe<xprobmin3 .and. normal_dim==3)
return
5329 if (xprobe>xprobmax1 .and. normal_dim==1)
return
5330 if (xprobe>xprobmax2 .and. normal_dim==2)
return
5331 if (xprobe>xprobmax3 .and. normal_dim==3)
return
5335 end subroutine trace_spherical_face_probe_coord
5337 double precision function trace_spherical_physical_cell_scale(x,igrid) &
5339 double precision,
intent(in) :: x(
ndim)
5340 integer,
intent(in) :: igrid
5342 double precision :: r,sint,dxloc(
ndim)
5346 if (
ndim/=3 .or. geo_coordinate/=geo_spherical .or. igrid<0)
return
5349 call trace_spherical_local_cell_widths(x,igrid,dxloc,status)
5351 r=max(abs(x(1)),smalldouble)
5352 sint=max(abs(dsin(x(2))),smalldouble)
5353 cell_scale=trace_spherical_cell_scale_from_widths(r,sint,dxloc)
5355 end function trace_spherical_physical_cell_scale
5357 double precision function trace_spherical_cell_scale_from_widths(r,sint, &
5358 dxloc)
result(cell_scale)
5359 double precision,
intent(in) :: r,sint,dxloc(
ndim)
5363 cell_scale=min(abs(dxloc(1)),abs(r)*abs(dxloc(2)))
5364 cell_scale=min(cell_scale,abs(r)*max(abs(sint),smalldouble)* &
5366 cell_scale=max(cell_scale,smalldouble)
5368 end function trace_spherical_cell_scale_from_widths
5371 double precision,
intent(out) :: hmin
5372 integer,
intent(out) :: status
5374 double precision :: dxloc(
ndim),hcell,r,sint
5375 integer :: iigrid,igrid,ix1,ix2,ix3
5379 if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
return
5385 do ix3=ixmlo3,ixmhi3
5386 do ix2=ixmlo2,ixmhi2
5387 do ix1=ixmlo1,ixmhi1
5388 r=ps(igrid)%x(ix1,ix2,ix3,1)
5389 sint=dsin(ps(igrid)%x(ix1,ix2,ix3,2))
5390 if (r<=smalldouble .or. abs(sint)<=smalldouble) cycle
5391 dxloc(1)=abs(ps(igrid)%dx(ix1,ix2,ix3,1))
5392 dxloc(2)=abs(ps(igrid)%dx(ix1,ix2,ix3,2))
5393 dxloc(3)=abs(ps(igrid)%dx(ix1,ix2,ix3,3))
5394 hcell=trace_spherical_cell_scale_from_widths(r,sint,dxloc)
5395 hmin=min(hmin,hcell)
5405 double precision,
intent(out) :: hmin
5406 integer,
intent(out) :: status
5408 double precision :: hlocal,hcell
5409 integer :: iigrid,igrid,ix1,ix2,ix3
5414 if (
ndim/=3 .or. .not.trace_cartesian_like_geometry())
return
5420 do ix3=ixmlo3,ixmhi3
5421 do ix2=ixmlo2,ixmhi2
5422 do ix1=ixmlo1,ixmhi1
5423 hcell=min(abs(ps(igrid)%dx(ix1,ix2,ix3,1)), &
5424 abs(ps(igrid)%dx(ix1,ix2,ix3,2)))
5425 hcell=min(hcell,abs(ps(igrid)%dx(ix1,ix2,ix3,3)))
5426 if (hcell>zero) hlocal=min(hlocal,hcell)
5432 call mpi_allreduce(hlocal,hmin,1,mpi_double_precision,mpi_min, &
5441 logical function trace_cartesian_like_geometry()
result(is_cart_like)
5442 is_cart_like=.false.
5445 select case (geo_coordinate)
5446 case (geo_cartesian,geo_cartesian_stretched)
5450 end function trace_cartesian_like_geometry
5452 logical function trace_rk45_position_integrator()
result(is_rk45)
5456 select case (trace_integrator_mode)
5457 case (trace_integrator_rk45_cartesian)
5458 is_rk45=trace_cartesian_like_geometry()
5459 case (trace_integrator_rk45_spherical)
5460 is_rk45=geo_coordinate==geo_spherical
5463 end function trace_rk45_position_integrator
5465 subroutine trace_interp_weights_block(x,igrid,ixI^L,ixbl^D,xd^D,dxc^D, &
5467 double precision,
intent(in) :: x(
ndim)
5468 integer,
intent(in) :: igrid,ixi^
l
5469 integer,
intent(out) :: ixbl^
d,status
5470 double precision,
intent(out) :: xd^
d,dxc^
d
5479 call trace_interp_index_3d(x(1),igrid,1,ixi^
l,ixbl1,xd1,dxc1,status)
5481 call trace_interp_index_3d(x(2),igrid,2,ixi^
l,ixbl2,xd2,dxc2,status)
5483 call trace_interp_index_3d(x(3),igrid,3,ixi^
l,ixbl3,xd3,dxc3,status)
5485 end subroutine trace_interp_weights_block
5487 subroutine trace_interp_weights_block_near(x,igrid,ixI^L,ixstart,ixbl^D, &
5489 double precision,
intent(in) :: x(
ndim)
5490 integer,
intent(in) :: igrid,ixi^
l
5491 integer,
intent(in) :: ixstart(3)
5492 integer,
intent(out) :: ixbl^
d,status
5493 double precision,
intent(out) :: xd^
d,dxc^
d
5502 call trace_interp_index_3d_near(x(1),igrid,1,ixi^
l,ixstart(1), &
5503 ixbl1,xd1,dxc1,status)
5505 call trace_interp_index_3d_near(x(2),igrid,2,ixi^
l,ixstart(2), &
5506 ixbl2,xd2,dxc2,status)
5508 call trace_interp_index_3d_near(x(3),igrid,3,ixi^
l,ixstart(3), &
5509 ixbl3,xd3,dxc3,status)
5511 end subroutine trace_interp_weights_block_near
5513 subroutine trace_interp_index_3d(xval,igrid,idim,ixI^L,ixlo,frac,dxc, &
5515 double precision,
intent(in) :: xval
5516 integer,
intent(in) :: igrid,idim,ixi^
l
5517 integer,
intent(out) :: ixlo,status
5518 double precision,
intent(out) :: frac,dxc
5520 double precision :: xlo,xhi,tol
5532 do i=iximin1,iximax1-1
5533 xlo=ps(igrid)%x(i,iximin2,iximin3,1)
5534 xhi=ps(igrid)%x(i+1,iximin2,iximin3,1)
5536 tol=100.d0*epsilon(one)*max(one,max(abs(xlo),abs(xhi)))
5537 if (abs(dxc)<=smalldouble) cycle
5538 if (xval>=min(xlo,xhi)-tol .and. &
5539 xval<=max(xlo,xhi)+tol)
then
5541 frac=max(zero,min(one,(xval-xlo)/dxc))
5547 do i=iximin2,iximax2-1
5548 xlo=ps(igrid)%x(iximin1,i,iximin3,2)
5549 xhi=ps(igrid)%x(iximin1,i+1,iximin3,2)
5551 tol=100.d0*epsilon(one)*max(one,max(abs(xlo),abs(xhi)))
5552 if (abs(dxc)<=smalldouble) cycle
5553 if (xval>=min(xlo,xhi)-tol .and. &
5554 xval<=max(xlo,xhi)+tol)
then
5556 frac=max(zero,min(one,(xval-xlo)/dxc))
5562 do i=iximin3,iximax3-1
5563 xlo=ps(igrid)%x(iximin1,iximin2,i,3)
5564 xhi=ps(igrid)%x(iximin1,iximin2,i+1,3)
5566 tol=100.d0*epsilon(one)*max(one,max(abs(xlo),abs(xhi)))
5567 if (abs(dxc)<=smalldouble) cycle
5568 if (xval>=min(xlo,xhi)-tol .and. &
5569 xval<=max(xlo,xhi)+tol)
then
5571 frac=max(zero,min(one,(xval-xlo)/dxc))
5578 end subroutine trace_interp_index_3d
5580 subroutine trace_interp_index_3d_near(xval,igrid,idim,ixI^L,ixstart, &
5581 ixlo,frac,dxc,status)
5582 double precision,
intent(in) :: xval
5583 integer,
intent(in) :: igrid,idim,ixi^
l,ixstart
5584 integer,
intent(out) :: ixlo,status
5585 double precision,
intent(out) :: frac,dxc
5587 double precision :: xlo,xhi,tol
5588 integer :: i,ilo,ihi,idir
5611 i=max(ilo,min(ixstart,ihi))
5615 xlo=ps(igrid)%x(i,iximin2,iximin3,1)
5616 xhi=ps(igrid)%x(i+1,iximin2,iximin3,1)
5618 xlo=ps(igrid)%x(iximin1,i,iximin3,2)
5619 xhi=ps(igrid)%x(iximin1,i+1,iximin3,2)
5621 xlo=ps(igrid)%x(iximin1,iximin2,i,3)
5622 xhi=ps(igrid)%x(iximin1,iximin2,i+1,3)
5625 tol=100.d0*epsilon(one)*max(one,max(abs(xlo),abs(xhi)))
5626 if (abs(dxc)>smalldouble .and. &
5627 xval>=min(xlo,xhi)-tol .and. &
5628 xval<=max(xlo,xhi)+tol)
then
5630 frac=max(zero,min(one,(xval-xlo)/dxc))
5635 if (abs(dxc)<=smalldouble)
then
5637 else if (xval<min(xlo,xhi)-tol)
then
5644 if (i<ilo .or. i>ihi)
exit
5647 end subroutine trace_interp_index_3d_near
5649 subroutine trace_spherical_local_cell_widths(x,igrid,dxloc,status)
5650 double precision,
intent(in) :: x(
ndim)
5651 integer,
intent(in) :: igrid
5652 double precision,
intent(out) :: dxloc(
ndim)
5653 integer,
intent(out) :: status
5655 type(trace_sph_interp_ctx) :: ctx
5659 if (
ndim/=3 .or. geo_coordinate/=geo_spherical .or. igrid<0)
return
5662 call trace_spherical_interp_ctx_build(x,igrid,ctx,status)
5664 dxloc(1:3)=ctx%dxloc(1:3)
5666 end subroutine trace_spherical_local_cell_widths
5668 subroutine trace_debug_locate_point(x_input,igrid,status)
5671 double precision,
intent(in) :: x_input(
ndim)
5672 integer,
intent(out) :: igrid,status
5674 double precision :: x3d(3)
5675 integer :: indomain,ipe,j
5677 double precision :: x(
ndim)
5680 call trace_normalize_position(x)
5684 {
if (trace_coordinate_in_domain(x(^db),^db)) indomain=indomain+1\}
5685 if (indomain/=
ndim)
then
5695 if (igrid<0 .or. ipe/=
mype)
then
5698 end subroutine trace_debug_locate_point
5700 subroutine trace_locate_point_with_hint(x_input,igrid_hint,igrid,status)
5701 double precision,
intent(in) :: x_input(
ndim)
5702 integer,
intent(in) :: igrid_hint
5703 integer,
intent(out) :: igrid,status
5705 double precision :: xbmin^
d,xbmax^
d
5708 double precision :: x(
ndim)
5711 call trace_normalize_position(x)
5714 if (igrid_hint>=0)
then
5718 {
if (x(^db)>xbmin^db .and. x(^db)<xbmax^db) inblock=inblock+1\}
5719 if (inblock==
ndim)
then
5725 call trace_debug_locate_point(x,igrid,status)
5726 end subroutine trace_locate_point_with_hint
5728 subroutine trace_tangent_rhs(x,u,v,igrid,threshold,kx,ku,kv,status, &
5730 double precision,
intent(in) :: x(
ndim),u(
ndim),v(
ndim),threshold
5731 integer,
intent(in) :: igrid
5732 double precision,
intent(out) :: kx(
ndim),ku(
ndim),kv(
ndim)
5733 integer,
intent(out) :: status
5734 double precision,
intent(in),
optional :: p(
ndim),q(
ndim)
5735 double precision,
intent(out),
optional :: kp(
ndim),kq(
ndim)
5736 type(trace_sph_interp_ctx),
intent(in),
optional :: sph_ctx
5738 double precision :: bhat(3),grad_bhat(3,3)
5739 double precision :: u3(3),v3(3),p3(3),q3(3)
5740 double precision :: ku3(3),kv3(3),kp3(3),kq3(3)
5746 if (
present(kp)) kp=zero
5747 if (
present(kq)) kq=zero
5750 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_rhs()
5753 if (geo_coordinate==geo_spherical)
then
5755 if (
present(sph_ctx))
then
5756 use_ctx=sph_ctx%valid .and. sph_ctx%igrid==igrid .and. &
5757 maxval(abs(sph_ctx%x(1:3)-x(1:3))) <= &
5758 100.d0*epsilon(one)*max(one,maxval(abs(x(1:3))))
5761 call trace_spherical_sample_bhat_gradbhat_covariant_ctx(sph_ctx, &
5762 threshold,bhat,grad_bhat,status)
5764 call trace_spherical_sample_bhat_gradbhat_covariant(x,igrid, &
5765 threshold,bhat,grad_bhat,status)
5768 if (trace_spherical_profile_enabled)
then
5769 call trace_spherical_profile_add_count(trace_profile_grad_fallbacks, &
5772 call trace_spherical_sample_bhat_gradbhat_cartfd(x,igrid,threshold, &
5773 bhat,grad_bhat,status)
5776 call trace_spherical_bhat_cart_to_rhs(x,bhat,kx,status)
5779 call sample_bhat_gradbhat_at_point(x,igrid,threshold,bhat,grad_bhat,status)
5789 ku3=matmul(grad_bhat,u3)
5790 kv3=matmul(grad_bhat,v3)
5793 if (
present(p) .and.
present(q) .and.
present(kp) .and. &
5799 kp3=matmul(grad_bhat,p3)
5800 kq3=matmul(grad_bhat,q3)
5805 end subroutine trace_tangent_rhs
5807 subroutine trace_advance_tangent_state_rk2(x,u,v,igrid,h,threshold,status)
5808 double precision,
intent(inout) :: x(
ndim),u(
ndim),v(
ndim)
5809 integer,
intent(inout) :: igrid
5810 double precision,
intent(in) :: h,threshold
5811 integer,
intent(out) :: status
5814 integer :: igrid_mid,igrid_new
5816 call trace_tangent_rk2_trial(x,u,v,igrid,h,threshold,xnew,unew,vnew, &
5820 call trace_debug_locate_point(xnew,igrid_new,status)
5827 end subroutine trace_advance_tangent_state_rk2
5829 subroutine trace_tangent_rk2_trial(x,u,v,igrid,h,threshold,xnew,unew, &
5831 double precision,
intent(in) :: x(
ndim),u(
ndim),v(
ndim),h,threshold
5832 integer,
intent(in) :: igrid
5833 double precision,
intent(out) :: xnew(
ndim),unew(
ndim),vnew(
ndim)
5834 integer,
intent(out) :: status
5838 call trace_tangent_rhs(x,u,v,igrid,threshold,kx1,ku1,kv1,status)
5841 call trace_tangent_rk2_trial_from_rhs(x,u,v,igrid,h,threshold, &
5842 kx1,ku1,kv1,xnew,unew,vnew,status)
5843 end subroutine trace_tangent_rk2_trial
5845 subroutine trace_tangent_rk2_trial_from_rhs(x,u,v,igrid,h,threshold, &
5846 kx1,ku1,kv1,xnew,unew,vnew,status,p,q,kp1,kq1,pnew,qnew, &
5847 sph_cache,clamp_stage)
5848 double precision,
intent(in) :: x(
ndim),u(
ndim),v(
ndim),h,threshold
5849 double precision,
intent(in) :: kx1(
ndim),ku1(
ndim),kv1(
ndim)
5850 integer,
intent(in) :: igrid
5851 double precision,
intent(out) :: xnew(
ndim),unew(
ndim),vnew(
ndim)
5852 integer,
intent(out) :: status
5853 double precision,
intent(in),
optional :: p(
ndim),q(
ndim)
5854 double precision,
intent(in),
optional :: kp1(
ndim),kq1(
ndim)
5855 double precision,
intent(out),
optional :: pnew(
ndim),qnew(
ndim)
5856 type(trace_sph_interp_ctx),
intent(inout),
optional :: sph_cache
5857 logical,
intent(in),
optional :: clamp_stage
5860 double precision :: xmid(
ndim),xmid_sample(
ndim)
5862 type(trace_sph_interp_ctx) :: ctx_mid
5863 integer :: igrid_mid
5864 integer :: ctx_status
5865 logical :: use_clamped_stage
5870 use_clamped_stage=.false.
5871 if (
present(clamp_stage)) use_clamped_stage=clamp_stage
5873 if (use_clamped_stage)
then
5874 call trace_clamp_sample_position(xmid_sample)
5876 call trace_locate_point_with_hint(xmid_sample,igrid,igrid_mid,status)
5879 if (geo_coordinate==geo_spherical)
then
5880 if (
present(sph_cache))
then
5881 call trace_spherical_interp_ctx_build_cached(xmid_sample,igrid_mid, &
5882 sph_cache,ctx_mid,ctx_status)
5884 call trace_spherical_interp_ctx_build(xmid_sample,igrid_mid,ctx_mid, &
5889 if (
present(p) .and.
present(q) .and.
present(kp1) .and. &
5890 present(kq1) .and.
present(pnew) .and.
present(qnew))
then
5894 call trace_tangent_rhs(xmid_sample,umid,vmid,igrid_mid,threshold,kx2,ku2, &
5895 kv2,status,pmid,qmid,kp2,kq2,sph_ctx=ctx_mid)
5897 call trace_tangent_rhs(xmid_sample,umid,vmid,igrid_mid,threshold,kx2,ku2, &
5898 kv2,status,pmid,qmid,kp2,kq2)
5902 call trace_tangent_rhs(xmid_sample,umid,vmid,igrid_mid,threshold,kx2,ku2, &
5903 kv2,status,sph_ctx=ctx_mid)
5905 call trace_tangent_rhs(xmid_sample,umid,vmid,igrid_mid,threshold,kx2,ku2, &
5914 if (
present(pnew) .and.
present(qnew))
then
5918 end subroutine trace_tangent_rk2_trial_from_rhs
5920 subroutine trace_project_to_perp_bhat(vec,bhat,vec_perp)
5921 double precision,
intent(in) :: vec(
ndim),bhat(
ndim)
5922 double precision,
intent(out) :: vec_perp(
ndim)
5924 vec_perp=vec-sum(vec*bhat)*bhat
5925 end subroutine trace_project_to_perp_bhat
5927 subroutine trace_endpoint_b_bhat(x,face_id,igrid,threshold,B,bhat,status)
5928 double precision,
intent(in) :: x(
ndim),threshold
5929 integer,
intent(in) :: face_id,igrid
5930 double precision,
intent(out) :: b(
ndim),bhat(
ndim)
5931 integer,
intent(out) :: status
5933 double precision :: b3(3),bhat3(3)
5934 integer :: sample_igrid
5938 if (geo_coordinate==geo_spherical)
then
5939 call trace_spherical_endpoint_b_bhat(x,face_id,igrid,threshold,b,bhat, &
5943 call trace_locate_face_limit_grid(x,face_id,igrid,sample_igrid,status)
5945 call trace_sample_b_on_domain_face_limit(x,face_id,sample_igrid,threshold, &
5951 end subroutine trace_endpoint_b_bhat
5953 subroutine trace_locate_face_limit_grid(x,face_id,igrid_in,igrid_out, &
5955 double precision,
intent(in) :: x(
ndim)
5956 integer,
intent(in) :: face_id,igrid_in
5957 integer,
intent(out) :: igrid_out,status
5959 double precision :: xprobe(
ndim),xface
5961 integer :: normal_dim,side
5965 if (
ndim/=3 .or. .not.trace_cartesian_like_geometry() .or. &
5970 if (.not.trace_face_is_boundary(face_id))
return
5973 select case(face_id)
6004 select case(normal_dim)
6007 xprobe(normal_dim)=ps(igrid_in)%x(ixomin1,ixomin2,ixomin3,1)
6009 xprobe(normal_dim)=ps(igrid_in)%x(ixomax1,ixomin2,ixomin3,1)
6013 xprobe(normal_dim)=ps(igrid_in)%x(ixomin1,ixomin2,ixomin3,2)
6015 xprobe(normal_dim)=ps(igrid_in)%x(ixomin1,ixomax2,ixomin3,2)
6019 xprobe(normal_dim)=ps(igrid_in)%x(ixomin1,ixomin2,ixomin3,3)
6021 xprobe(normal_dim)=ps(igrid_in)%x(ixomin1,ixomin2,ixomax3,3)
6024 call trace_debug_locate_point(xprobe,igrid_out,status)
6026 end subroutine trace_locate_face_limit_grid
6028 subroutine trace_sample_b_on_domain_face_limit(xhit,face_id,igrid, &
6029 threshold,B,bhat,status)
6033 double precision,
intent(in) :: xhit(
ndim),threshold
6034 integer,
intent(in) :: face_id,igrid
6035 double precision,
intent(out) :: b(3),bhat(3)
6036 integer,
intent(out) :: status
6038 double precision :: bnear(3),binner(3)
6039 double precision :: xface,xnear,xinner
6040 double precision :: xnear_pt(
ndim),xinner_pt(
ndim)
6041 double precision :: bnorm
6043 integer :: normal_dim,side
6044 integer :: igrid_near,igrid_inner
6049 if (
ndim/=3 .or. .not.trace_cartesian_like_geometry() .or. igrid<0)
then
6053 if (.not.trace_face_is_boundary(face_id))
return
6056 select case(face_id)
6086 select case(normal_dim)
6089 xnear=ps(igrid)%x(ixomin1,ixomin2,ixomin3,1)
6090 xinner=ps(igrid)%x(ixomin1+1,ixomin2,ixomin3,1)
6092 xnear=ps(igrid)%x(ixomax1,ixomin2,ixomin3,1)
6093 xinner=ps(igrid)%x(ixomax1-1,ixomin2,ixomin3,1)
6097 xnear=ps(igrid)%x(ixomin1,ixomin2,ixomin3,2)
6098 xinner=ps(igrid)%x(ixomin1,ixomin2+1,ixomin3,2)
6100 xnear=ps(igrid)%x(ixomin1,ixomax2,ixomin3,2)
6101 xinner=ps(igrid)%x(ixomin1,ixomax2-1,ixomin3,2)
6105 xnear=ps(igrid)%x(ixomin1,ixomin2,ixomin3,3)
6106 xinner=ps(igrid)%x(ixomin1,ixomin2,ixomin3+1,3)
6108 xnear=ps(igrid)%x(ixomin1,ixomin2,ixomax3,3)
6109 xinner=ps(igrid)%x(ixomin1,ixomin2,ixomax3-1,3)
6114 xnear_pt(normal_dim)=xnear
6115 xinner_pt(normal_dim)=xinner
6117 call trace_debug_locate_point(xnear_pt,igrid_near,status)
6119 call sample_b_at_point(xnear_pt,igrid_near,threshold,bnear,status)
6121 call trace_debug_locate_point(xinner_pt,igrid_inner,status)
6123 call sample_b_at_point(xinner_pt,igrid_inner,threshold,binner,status)
6126 b=bnear+(bnear-binner)/(xnear-xinner)*(xface-xnear)
6127 bnorm=dsqrt(sum(b**2))
6128 if (bnorm<=zero .or. bnorm<threshold)
then
6135 end subroutine trace_sample_b_on_domain_face_limit
6137 subroutine trace_face_normal(face_id,normal,ok)
6138 integer,
intent(in) :: face_id
6139 double precision,
intent(out) :: normal(
ndim)
6140 logical,
intent(out) :: ok
6144 select case(face_id)
6174 end subroutine trace_face_normal
6176 subroutine trace_project_to_boundary_face(vec,bhat,face_id,vec_face)
6177 double precision,
intent(in) :: vec(
ndim),bhat(
ndim)
6178 integer,
intent(in) :: face_id
6179 double precision,
intent(out) :: vec_face(
ndim)
6181 double precision :: normal(
ndim),bn
6185 call trace_face_normal(face_id,normal,ok)
6188 if (abs(bn)<=smalldouble)
return
6189 vec_face=vec-sum(vec*normal)/bn*bhat
6190 end subroutine trace_project_to_boundary_face
6192 subroutine trace_make_perp_basis(bhat,u0,v0,status)
6193 double precision,
intent(in) :: bhat(3)
6194 double precision,
intent(out) :: u0(
ndim),v0(
ndim)
6195 integer,
intent(out) :: status
6197 double precision :: ref(3),u3(3),v3(3),b3(3),unorm,bnorm
6209 bnorm=dsqrt(sum(b3**2))
6210 if (bnorm<=zero)
then
6217 if (abs(b3(2))<abs(b3(iref))) iref=2
6218 if (abs(b3(3))<abs(b3(iref))) iref=3
6222 u3=ref-sum(ref*b3)*b3
6223 unorm=dsqrt(sum(u3**2))
6224 if (unorm<=smalldouble)
then
6230 v3(1)=b3(2)*u3(3)-b3(3)*u3(2)
6231 v3(2)=b3(3)*u3(1)-b3(1)*u3(3)
6232 v3(3)=b3(1)*u3(2)-b3(2)*u3(1)
6233 v3=v3/dsqrt(sum(v3**2))
6237 end subroutine trace_make_perp_basis
6239 double precision function trace_debug_nan()
6240 trace_debug_nan=ieee_value(0.d0,ieee_quiet_nan)
6241 end function trace_debug_nan
6243 subroutine trace_summary_seed(seed,dL,max_steps,result,b_min)
6244 double precision,
intent(in) :: seed(
ndim),dl
6245 integer,
intent(in) :: max_steps
6247 double precision,
intent(in),
optional :: b_min
6249 double precision :: field_min
6250 integer :: common_status,igrid
6252 call trace_summary_validate(dl,max_steps,common_status)
6254 call trace_summary_init_result(seed,result,common_status)
6258 field_min=smalldouble
6259 if (
present(b_min)) field_min=max(b_min,zero)
6261 call trace_summary_locate_seed(seed,result,igrid)
6263 call trace_summary_trace_seed(igrid,dl,max_steps,field_min,result)
6264 end subroutine trace_summary_seed
6266 subroutine trace_summary_twist_seed(seed,dL,max_steps,result,b_min)
6267 double precision,
intent(in) :: seed(
ndim),dl
6268 integer,
intent(in) :: max_steps
6270 double precision,
intent(in),
optional :: b_min
6272 double precision :: field_min
6273 integer :: common_status,igrid
6275 call trace_summary_validate(dl,max_steps,common_status)
6280 call trace_summary_init_twist_result(seed,result,common_status)
6284 field_min=smalldouble
6285 if (
present(b_min)) field_min=max(b_min,zero)
6287 call trace_summary_locate_seed(seed,result%line,igrid)
6288 result%forward_twist=zero
6289 result%backward_twist=zero
6290 result%total_twist=zero
6291 result%valid_twist=.false.
6292 result%status_twist=result%line%forward_status
6294 call trace_summary_trace_twist_seed(igrid,dl,max_steps,field_min,result)
6295 end subroutine trace_summary_twist_seed
6297 subroutine trace_summary_mapping_seed(seed,dL,max_steps,result,b_min, &
6299 double precision,
intent(in) :: seed(
ndim),dl
6300 integer,
intent(in) :: max_steps
6302 double precision,
intent(in),
optional :: b_min
6303 double precision,
intent(in),
optional :: source_normal(3)
6305 type(trace_summary_state) :: forward_state,backward_state
6307 double precision :: field_min,normal(3)
6308 integer :: common_status,igrid
6309 logical :: have_normal
6311 call trace_summary_validate(dl,max_steps,common_status)
6316 call trace_summary_init_mapping_result(seed,result,common_status)
6320 field_min=smalldouble
6321 if (
present(b_min)) field_min=max(b_min,zero)
6323 have_normal=
present(source_normal)
6324 if (have_normal) normal=source_normal
6326 call trace_summary_locate_seed(seed,located,igrid)
6327 call trace_summary_init_mapping_result(seed,result,located%forward_status)
6330 call trace_summary_init_state(seed,igrid,.true.,1,.false.,forward_state)
6331 call trace_summary_trace_state_to_end(forward_state,dl,max_steps,field_min)
6332 call trace_summary_init_state(seed,igrid,.false.,1,.false.,backward_state)
6333 call trace_summary_trace_state_to_end(backward_state,dl,max_steps,field_min)
6334 call trace_summary_fill_mapping(seed,igrid,forward_state,backward_state, &
6335 field_min,have_normal,normal,result)
6336 end subroutine trace_summary_mapping_seed
6338 subroutine trace_summary_multi(seeds,nseed,dL,max_steps,results,field_min)
6339 integer,
intent(in) :: nseed,max_steps
6340 double precision,
intent(in) :: seeds(nseed,
ndim),dl,field_min
6343 type(trace_summary_state),
allocatable :: states(:)
6344 double precision :: seed_local(
ndim)
6345 integer :: common_status,iseed,igrid,iforward,ibackward
6347 if (nseed<=0)
return
6349 call trace_summary_validate(dl,max_steps,common_status)
6352 seed_local=seeds(iseed,:)
6353 call trace_summary_init_result(seed_local,results(iseed),common_status)
6358 allocate(states(2*nseed))
6360 seed_local=seeds(iseed,:)
6361 call trace_summary_locate_seed(seed_local,results(iseed),igrid)
6364 call trace_summary_init_state(seed_local,igrid,.true.,iseed,.false., &
6366 call trace_summary_init_state(seed_local,igrid,.false.,iseed,.false., &
6369 states(iforward)%status=results(iseed)%forward_status
6370 states(iforward)%active=.false.
6371 states(ibackward)%status=results(iseed)%backward_status
6372 states(ibackward)%active=.false.
6376 call trace_summary_trace_states_grouped(states,2*nseed,dl,max_steps, &
6382 results(iseed)%forward_footpoint=states(iforward)%footpoint
6383 results(iseed)%forward_length=states(iforward)%length
6384 results(iseed)%forward_nstep=states(iforward)%nstep
6385 results(iseed)%forward_status=states(iforward)%status
6386 results(iseed)%backward_footpoint=states(ibackward)%footpoint
6387 results(iseed)%backward_length=states(ibackward)%length
6388 results(iseed)%backward_nstep=states(ibackward)%nstep
6389 results(iseed)%backward_status=states(ibackward)%status
6390 results(iseed)%total_length=results(iseed)%forward_length &
6391 +results(iseed)%backward_length
6394 end subroutine trace_summary_multi
6396 subroutine trace_summary_twist_multi(seeds,nseed,dL,max_steps,results, &
6398 integer,
intent(in) :: nseed,max_steps
6399 double precision,
intent(in) :: seeds(nseed,
ndim),dl,field_min
6402 type(trace_summary_state),
allocatable :: states(:)
6403 double precision :: seed_local(
ndim)
6404 integer :: common_status,iseed,igrid,iforward,ibackward
6406 if (nseed<=0)
return
6408 call trace_summary_validate(dl,max_steps,common_status)
6414 seed_local=seeds(iseed,:)
6415 call trace_summary_init_twist_result(seed_local,results(iseed), &
6421 allocate(states(2*nseed))
6423 seed_local=seeds(iseed,:)
6424 call trace_summary_locate_seed(seed_local,results(iseed)%line,igrid)
6425 results(iseed)%forward_twist=zero
6426 results(iseed)%backward_twist=zero
6427 results(iseed)%total_twist=zero
6428 results(iseed)%valid_twist=.false.
6429 results(iseed)%status_twist=results(iseed)%line%forward_status
6432 call trace_summary_init_state(seed_local,igrid,.true.,iseed,.true., &
6434 call trace_summary_init_state(seed_local,igrid,.false.,iseed,.true., &
6437 states(iforward)%status=results(iseed)%line%forward_status
6438 states(iforward)%active=.false.
6439 states(ibackward)%status=results(iseed)%line%backward_status
6440 states(ibackward)%active=.false.
6444 call trace_summary_trace_states_grouped(states,2*nseed,dl,max_steps, &
6450 results(iseed)%line%forward_footpoint=states(iforward)%footpoint
6451 results(iseed)%line%forward_length=states(iforward)%length
6452 results(iseed)%line%forward_nstep=states(iforward)%nstep
6453 results(iseed)%line%forward_status=states(iforward)%status
6454 results(iseed)%line%backward_footpoint=states(ibackward)%footpoint
6455 results(iseed)%line%backward_length=states(ibackward)%length
6456 results(iseed)%line%backward_nstep=states(ibackward)%nstep
6457 results(iseed)%line%backward_status=states(ibackward)%status
6458 results(iseed)%line%total_length=results(iseed)%line%forward_length &
6459 +results(iseed)%line%backward_length
6460 results(iseed)%forward_twist=states(iforward)%twist
6461 results(iseed)%backward_twist=states(ibackward)%twist
6462 results(iseed)%total_twist=results(iseed)%forward_twist &
6463 +results(iseed)%backward_twist
6464 results(iseed)%status_twist=trace_summary_twist_status_from_states( &
6465 states(iforward),states(ibackward))
6466 results(iseed)%valid_twist=results(iseed)%status_twist &
6470 end subroutine trace_summary_twist_multi
6472 subroutine trace_summary_mapping_multi(seeds,nseed,dL,max_steps,results, &
6473 field_min,have_source_normal,source_normal)
6474 integer,
intent(in) :: nseed,max_steps
6475 double precision,
intent(in) :: seeds(nseed,
ndim),dl,field_min
6476 logical,
intent(in) :: have_source_normal
6477 double precision,
intent(in) :: source_normal(3)
6480 type(trace_summary_state),
allocatable :: states(:)
6481 integer,
allocatable :: source_igrids(:)
6483 double precision :: seed_local(
ndim)
6484 integer :: common_status,iseed,igrid,iforward,ibackward
6486 if (nseed<=0)
return
6488 call trace_summary_validate(dl,max_steps,common_status)
6494 seed_local=seeds(iseed,:)
6495 call trace_summary_init_mapping_result(seed_local,results(iseed), &
6501 allocate(states(2*nseed))
6502 allocate(source_igrids(nseed))
6505 seed_local=seeds(iseed,:)
6506 call trace_summary_locate_seed(seed_local,located,igrid)
6507 source_igrids(iseed)=igrid
6508 call trace_summary_init_mapping_result(seed_local,results(iseed), &
6509 located%forward_status)
6512 call trace_summary_init_state(seed_local,igrid,.true.,iseed,.false., &
6514 call trace_summary_init_state(seed_local,igrid,.false.,iseed,.false., &
6517 states(iforward)%status=located%forward_status
6518 states(iforward)%active=.false.
6519 states(ibackward)%status=located%backward_status
6520 states(ibackward)%active=.false.
6524 call trace_summary_trace_states_grouped(states,2*nseed,dl,max_steps, &
6530 if (source_igrids(iseed)>=0)
then
6531 call trace_summary_fill_mapping(results(iseed)%seed, &
6532 source_igrids(iseed),states(iforward),states(ibackward), &
6533 field_min,have_source_normal,source_normal,results(iseed))
6536 deallocate(source_igrids,states)
6537 end subroutine trace_summary_mapping_multi
6539 subroutine trace_summary_topology_multi(seeds,nseed,dL,max_steps,results, &
6540 field_min,need_twist,need_mapping,have_source_normal,source_normal)
6541 integer,
intent(in) :: nseed,max_steps
6542 double precision,
intent(in) :: seeds(nseed,
ndim),dl,field_min
6543 logical,
intent(in) :: need_twist,need_mapping,have_source_normal
6544 double precision,
intent(in) :: source_normal(3)
6547 type(trace_summary_state),
allocatable :: states(:)
6548 type(trace_summary_state),
allocatable :: map_states(:)
6549 integer,
allocatable :: source_igrids(:)
6552 double precision :: seed_local(
ndim)
6553 integer :: common_status,iseed,igrid,iforward,ibackward,idim
6555 if (nseed<=0)
return
6557 call trace_summary_validate(dl,max_steps,common_status)
6559 (need_twist .or. need_mapping) .and.
ndim/=3)
then
6565 seed_local(idim)=seeds(iseed,idim)
6567 call trace_summary_init_topology_result(seed_local,results(iseed), &
6568 common_status,need_twist,need_mapping)
6573 allocate(states(2*nseed))
6576 if (need_mapping .and. need_twist)
allocate(map_states(2*nseed))
6577 allocate(source_igrids(nseed))
6581 seed_local(idim)=seeds(iseed,idim)
6583 call trace_summary_locate_seed(seed_local,located,igrid)
6584 source_igrids(iseed)=igrid
6585 call trace_summary_init_topology_result(seed_local,results(iseed), &
6586 located%forward_status,need_twist,need_mapping)
6589 call trace_summary_init_state(seed_local,igrid,.true.,iseed, &
6590 need_twist,states(iforward))
6591 call trace_summary_init_state(seed_local,igrid,.false.,iseed, &
6592 need_twist,states(ibackward))
6593 if (
allocated(map_states))
then
6594 call trace_summary_init_state(seed_local,igrid,.true.,iseed, &
6595 .false.,map_states(iforward))
6596 call trace_summary_init_state(seed_local,igrid,.false.,iseed, &
6597 .false.,map_states(ibackward))
6600 states(iforward)%status=located%forward_status
6601 states(iforward)%active=.false.
6602 states(ibackward)%status=located%backward_status
6603 states(ibackward)%active=.false.
6604 if (
allocated(map_states))
then
6605 map_states(iforward)%status=located%forward_status
6606 map_states(iforward)%active=.false.
6607 map_states(ibackward)%status=located%backward_status
6608 map_states(ibackward)%active=.false.
6613 call trace_summary_trace_states_grouped(states,2*nseed,dl,max_steps, &
6615 if (
allocated(map_states))
then
6616 call trace_summary_trace_states_grouped(map_states,2*nseed,dl, &
6617 max_steps,field_min)
6623 results(iseed)%forward_endpoint=states(iforward)%footpoint
6624 results(iseed)%backward_endpoint=states(ibackward)%footpoint
6625 results(iseed)%length_forward=states(iforward)%length
6626 results(iseed)%length_backward=states(ibackward)%length
6627 results(iseed)%length_total=results(iseed)%length_forward &
6628 +results(iseed)%length_backward
6629 results(iseed)%forward_nstep=states(iforward)%nstep
6630 results(iseed)%backward_nstep=states(ibackward)%nstep
6631 results(iseed)%forward_face=states(iforward)%face
6632 results(iseed)%backward_face=states(ibackward)%face
6633 results(iseed)%forward_status=states(iforward)%status
6634 results(iseed)%backward_status=states(ibackward)%status
6635 if (need_twist)
then
6636 results(iseed)%twist_forward=states(iforward)%twist
6637 results(iseed)%twist_backward=states(ibackward)%twist
6638 results(iseed)%twist_total=results(iseed)%twist_forward &
6639 +results(iseed)%twist_backward
6640 results(iseed)%status_twist=trace_summary_twist_status_from_states( &
6641 states(iforward),states(ibackward))
6642 results(iseed)%valid_twist=results(iseed)%status_twist &
6649 results(iseed)%valid=.true.
6651 results(iseed)%valid=.false.
6653 results(iseed)%status=states(iforward)%status
6655 results(iseed)%status=states(ibackward)%status
6659 if (need_mapping .and. source_igrids(iseed)>=0)
then
6660 if (
allocated(map_states))
then
6661 call trace_summary_fill_mapping(results(iseed)%seed, &
6662 source_igrids(iseed),map_states(iforward), &
6663 map_states(ibackward),field_min,have_source_normal, &
6664 source_normal,mapping)
6666 call trace_summary_fill_mapping(results(iseed)%seed, &
6667 source_igrids(iseed),states(iforward),states(ibackward), &
6668 field_min,have_source_normal,source_normal,mapping)
6670 results(iseed)%source_B=mapping%source_B
6671 results(iseed)%forward_B=mapping%forward_B
6672 results(iseed)%backward_B=mapping%backward_B
6673 results(iseed)%source_Bn=mapping%source_Bn
6674 results(iseed)%forward_Bn=mapping%forward_Bn
6675 results(iseed)%backward_Bn=mapping%backward_Bn
6676 results(iseed)%map_forward_endpoint=mapping%forward_footpoint
6677 results(iseed)%map_backward_endpoint=mapping%backward_footpoint
6678 results(iseed)%map_forward_length=mapping%forward_length
6679 results(iseed)%map_backward_length=mapping%backward_length
6680 results(iseed)%map_forward_face=mapping%forward_face
6681 results(iseed)%map_backward_face=mapping%backward_face
6682 results(iseed)%map_forward_status=mapping%forward_status
6683 results(iseed)%map_backward_status=mapping%backward_status
6684 results(iseed)%forward_status=mapping%forward_status
6685 results(iseed)%backward_status=mapping%backward_status
6686 results(iseed)%valid=mapping%valid
6687 if (mapping%valid)
then
6690 results(iseed)%status=mapping%forward_status
6692 results(iseed)%status=mapping%backward_status
6696 if (
allocated(map_states))
deallocate(map_states)
6697 deallocate(source_igrids,states)
6698 end subroutine trace_summary_topology_multi
6700 subroutine trace_summary_validate(dL,max_steps,status)
6701 double precision,
intent(in) :: dl
6702 integer,
intent(in) :: max_steps
6703 integer,
intent(out) :: status
6708 else if (dl<=zero .or. max_steps<0)
then
6710 else if (.not.trace_is_supported_summary_geometry())
then
6713 end subroutine trace_summary_validate
6719 if (geo_coordinate==geo_spherical .and.
periodb(3))
then
6720 supported=abs((xprobmax3-xprobmin3)-2.d0*dpi)<= &
6721 1.
d-10*max(one,2.d0*dpi)
6726 logical function trace_periodic_phi()
result(periodic)
6729 periodic=geo_coordinate==geo_spherical .and.
periodb(3)
6731 end function trace_periodic_phi
6733 logical function trace_physical_dimension(idim)
result(physical)
6734 integer,
intent(in) :: idim
6736 if (idim==3) physical=.not.trace_periodic_phi()
6737 end function trace_physical_dimension
6739 subroutine trace_normalize_position(x)
6742 double precision,
intent(inout) :: x(
ndim)
6744 if (trace_periodic_phi() .and. ieee_is_finite(x(3)))
then
6745 x(3)=xprobmin3+modulo(x(3)-xprobmin3,xprobmax3-xprobmin3)
6746 if (x(3)>=xprobmax3) x(3)=xprobmin3
6749 end subroutine trace_normalize_position
6751 logical function trace_coordinate_in_domain(value,idim)
result(inside)
6752 double precision,
intent(in) :: value
6753 integer,
intent(in) :: idim
6754 double precision :: lo(
ndim),hi(
ndim)
6755 ^
d&lo(^
d)=xprobmin^
d;
6756 ^
d&hi(^
d)=xprobmax^
d;
6758 if (.not.ieee_is_finite(
value))
return
6759 inside=.not.trace_physical_dimension(idim)
6760 if (.not.inside) inside=
value>=lo(idim) .and.
value<hi(idim)
6761 end function trace_coordinate_in_domain
6763 subroutine trace_clamp_sample_position(x)
6764 double precision,
intent(inout) :: x(
ndim)
6765 double precision :: lo(
ndim),hi(
ndim)
6767 ^
d&lo(^
d)=xprobmin^
d;
6768 ^
d&hi(^
d)=xprobmax^
d;
6770 if (.not.trace_physical_dimension(idim)) cycle
6771 x(idim)=max(lo(idim),min(x(idim), &
6772 hi(idim)-100.d0*epsilon(one)*max(one,abs(hi(idim)))))
6774 call trace_normalize_position(x)
6775 end subroutine trace_clamp_sample_position
6777 logical function trace_is_supported_summary_geometry()
result(is_supported)
6778 is_supported=.false.
6781 select case (geo_coordinate)
6782 case (geo_cartesian,geo_cartesian_stretched)
6784 case (geo_spherical)
6788 end function trace_is_supported_summary_geometry
6790 subroutine trace_summary_init_result(seed,result,status)
6791 double precision,
intent(in) :: seed(
ndim)
6793 integer,
intent(in) :: status
6796 result%forward_footpoint=seed
6797 result%backward_footpoint=seed
6798 result%forward_length=zero
6799 result%backward_length=zero
6800 result%total_length=zero
6801 result%forward_nstep=0
6802 result%backward_nstep=0
6803 result%forward_status=status
6804 result%backward_status=status
6805 end subroutine trace_summary_init_result
6807 subroutine trace_summary_init_twist_result(seed,result,status)
6808 double precision,
intent(in) :: seed(
ndim)
6810 integer,
intent(in) :: status
6812 call trace_summary_init_result(seed,result%line,status)
6813 result%forward_twist=zero
6814 result%backward_twist=zero
6815 result%total_twist=zero
6816 result%valid_twist=.false.
6817 result%status_twist=status
6818 end subroutine trace_summary_init_twist_result
6820 subroutine trace_summary_init_mapping_result(seed,result,status)
6821 double precision,
intent(in) :: seed(
ndim)
6823 integer,
intent(in) :: status
6826 result%source_B=zero
6827 result%forward_footpoint=seed
6828 result%backward_footpoint=seed
6829 result%forward_B=zero
6830 result%backward_B=zero
6831 result%forward_length=zero
6832 result%backward_length=zero
6833 result%source_Bn=zero
6834 result%forward_Bn=zero
6835 result%backward_Bn=zero
6838 result%forward_status=status
6839 result%backward_status=status
6840 result%valid=.false.
6841 end subroutine trace_summary_init_mapping_result
6843 subroutine trace_summary_init_topology_result(seed,result,status, &
6844 need_twist,need_mapping)
6845 double precision,
intent(in) :: seed(
ndim)
6847 integer,
intent(in) :: status
6848 logical,
intent(in) :: need_twist,need_mapping
6851 result%length_forward=zero
6852 result%length_backward=zero
6853 result%length_total=zero
6854 result%twist_forward=zero
6855 result%twist_backward=zero
6856 result%twist_total=zero
6857 result%forward_endpoint=seed
6858 result%backward_endpoint=seed
6859 result%forward_nstep=0
6860 result%backward_nstep=0
6863 result%forward_status=status
6864 result%backward_status=status
6865 result%map_forward_endpoint=seed
6866 result%map_backward_endpoint=seed
6867 result%map_forward_length=zero
6868 result%map_backward_length=zero
6871 result%map_forward_status=status
6872 result%map_backward_status=status
6873 result%source_B=zero
6874 result%forward_B=zero
6875 result%backward_B=zero
6876 result%source_Bn=zero
6877 result%forward_Bn=zero
6878 result%backward_Bn=zero
6879 result%has_twist=need_twist
6880 result%has_mapping=need_mapping
6881 result%valid_twist=.false.
6882 result%valid=.false.
6883 result%status_twist=status
6884 result%status=status
6885 end subroutine trace_summary_init_topology_result
6887 subroutine trace_summary_locate_seed(seed,result,igrid)
6890 double precision,
intent(in) :: seed(
ndim)
6892 integer,
intent(out) :: igrid
6894 double precision :: x3d(3),domain_min(
ndim),domain_max(
ndim),tol
6895 integer :: indomain,ipe,j
6900 ^
d&domain_min(^
d)=xprobmin^
d;
6901 ^
d&domain_max(^
d)=xprobmax^
d;
6902 tol=100.d0*epsilon(one)*max(one,maxval(abs(domain_max-domain_min)))
6904 if (.not.trace_physical_dimension(j))
then
6905 if (ieee_is_finite(seed(j))) indomain=indomain+1
6908 if (seed(j)>=domain_min(j)-tol .and. &
6909 seed(j)<=domain_max(j)+tol) indomain=indomain+1
6911 if (indomain/=
ndim)
then
6919 x3d(j)=min(max(seed(j),domain_min(j)+tol),domain_max(j)-tol)
6920 if (.not.trace_physical_dimension(j)) x3d(j)=seed(j)
6922 call trace_normalize_position(x3d(1:
ndim))
6924 if (igrid<0 .or. ipe/=
mype)
then
6929 end subroutine trace_summary_locate_seed
6931 subroutine trace_summary_trace_seed(igrid,dL,max_steps,field_min,result)
6932 integer,
intent(in) :: igrid,max_steps
6933 double precision,
intent(in) :: dl,field_min
6936 type(trace_summary_state) :: forward_state,backward_state
6938 call trace_summary_init_state(result%seed,igrid,.true.,1,.false.,forward_state)
6939 call trace_summary_trace_state_to_end(forward_state,dl,max_steps,field_min)
6940 call trace_summary_init_state(result%seed,igrid,.false.,1,.false.,backward_state)
6941 call trace_summary_trace_state_to_end(backward_state,dl,max_steps,field_min)
6943 result%forward_footpoint=forward_state%footpoint
6944 result%forward_length=forward_state%length
6945 result%forward_nstep=forward_state%nstep
6946 result%forward_status=forward_state%status
6947 result%backward_footpoint=backward_state%footpoint
6948 result%backward_length=backward_state%length
6949 result%backward_nstep=backward_state%nstep
6950 result%backward_status=backward_state%status
6951 result%total_length=result%forward_length+result%backward_length
6952 end subroutine trace_summary_trace_seed
6954 subroutine trace_summary_trace_twist_seed(igrid,dL,max_steps,field_min, &
6956 integer,
intent(in) :: igrid,max_steps
6957 double precision,
intent(in) :: dl,field_min
6960 type(trace_summary_state) :: forward_state,backward_state
6962 call trace_summary_init_state(result%line%seed,igrid,.true.,1,.true., &
6964 call trace_summary_trace_state_to_end(forward_state,dl,max_steps,field_min)
6965 call trace_summary_init_state(result%line%seed,igrid,.false.,1,.true., &
6967 call trace_summary_trace_state_to_end(backward_state,dl,max_steps,field_min)
6969 result%line%forward_footpoint=forward_state%footpoint
6970 result%line%forward_length=forward_state%length
6971 result%line%forward_nstep=forward_state%nstep
6972 result%line%forward_status=forward_state%status
6973 result%line%backward_footpoint=backward_state%footpoint
6974 result%line%backward_length=backward_state%length
6975 result%line%backward_nstep=backward_state%nstep
6976 result%line%backward_status=backward_state%status
6977 result%line%total_length=result%line%forward_length &
6978 +result%line%backward_length
6979 result%forward_twist=forward_state%twist
6980 result%backward_twist=backward_state%twist
6981 result%total_twist=result%forward_twist+result%backward_twist
6982 result%status_twist=trace_summary_twist_status_from_states( &
6983 forward_state,backward_state)
6985 end subroutine trace_summary_trace_twist_seed
6987 subroutine trace_summary_init_state(xseed,igrid,forward,seed_id, &
6988 accumulate_twist,state)
6989 double precision,
intent(in) :: xseed(
ndim)
6990 integer,
intent(in) :: igrid,seed_id
6991 logical,
intent(in) :: forward,accumulate_twist
6992 type(trace_summary_state),
intent(out) :: state
6995 call trace_normalize_position(state%x)
6996 state%footpoint=state%x
7003 state%seed_id=seed_id
7005 state%forward=forward
7007 state%accumulate_twist=accumulate_twist
7009 state%sph_cache%valid=.false.
7010 if (trace_rk45_position_integrator())
then
7011 call trace_rk45_stats_note_direction()
7013 if (trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical) &
7014 call trace_spherical_profile_add_count(trace_profile_directions,1_8)
7015 end subroutine trace_summary_init_state
7017 subroutine trace_summary_trace_state_to_end(state,ds,max_nstep,threshold)
7018 type(trace_summary_state),
intent(inout) :: state
7019 double precision,
intent(in) :: ds,threshold
7020 integer,
intent(in) :: max_nstep
7022 do while(state%active .and. state%nstep<max_nstep)
7023 call trace_summary_advance_state(state,ds,threshold)
7026 if (state%active)
then
7028 state%active=.false.
7030 state%footpoint=state%x
7031 if (trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical) &
7032 call trace_spherical_profile_note_trace_steps(state%nstep)
7033 end subroutine trace_summary_trace_state_to_end
7035 subroutine trace_summary_trace_states_grouped(states,nstate,ds,max_nstep,threshold)
7036 integer,
intent(in) :: nstate,max_nstep
7037 type(trace_summary_state),
intent(inout) :: states(nstate)
7038 double precision,
intent(in) :: ds,threshold
7040 logical,
allocatable :: processed(:)
7041 integer :: istate,jstate,target_grid
7042 logical :: any_active
7044 allocate(processed(nstate))
7048 if (states(istate)%active)
then
7053 if (.not.any_active)
exit
7057 if (.not.states(istate)%active .or. processed(istate)) cycle
7058 target_grid=states(istate)%igrid
7060 if (.not.states(jstate)%active .or. processed(jstate)) cycle
7061 if (states(jstate)%igrid/=target_grid) cycle
7062 call trace_summary_advance_state_in_grid(states(jstate),target_grid, &
7063 ds,max_nstep,threshold)
7064 processed(jstate)=.true.
7068 deallocate(processed)
7069 end subroutine trace_summary_trace_states_grouped
7071 subroutine trace_summary_advance_state_in_grid(state,igrid,ds,max_nstep,threshold)
7072 type(trace_summary_state),
intent(inout) :: state
7073 integer,
intent(in) :: igrid,max_nstep
7074 double precision,
intent(in) :: ds,threshold
7076 do while(state%active .and. state%igrid==igrid .and. &
7077 state%nstep<max_nstep)
7078 call trace_summary_advance_state(state,ds,threshold)
7081 if (state%active .and. state%nstep>=max_nstep)
then
7083 state%active=.false.
7084 state%footpoint=state%x
7085 if (trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical) &
7086 call trace_spherical_profile_note_trace_steps(state%nstep)
7088 end subroutine trace_summary_advance_state_in_grid
7090 subroutine trace_summary_advance_state(state,ds,threshold)
7091 type(trace_summary_state),
intent(inout) :: state
7092 double precision,
intent(in) :: ds,threshold
7094 double precision :: xnext(
ndim),xhit(
ndim),ds_actual,segment_length
7095 double precision :: alpha_hit
7096 double precision :: xbmin^
d,xbmax^
d
7097 double precision :: domain_min(
ndim),domain_max(
ndim)
7098 double precision :: near_tol,best_dist,face_dist
7099 integer :: igrid_next,ipe_next,inblock,step_status,face_id
7100 integer :: idim,best_dim,best_side
7101 integer :: point_domain
7102 double precision :: rk45_twist_increment
7103 integer :: rk45_twist_status
7104 logical :: newpe,stop_trace,hit_ok
7105 logical :: rk45_step,rk45_twist_integrated
7107 if (.not.state%active)
return
7110 rk45_twist_increment=zero
7112 rk45_twist_integrated=.false.
7113 if (trace_integrator_mode==trace_integrator_rk45_cartesian .and. &
7114 trace_cartesian_like_geometry())
then
7116 call trace_summary_rk45_cartesian_step(state%x,state%igrid,ds, &
7117 state%forward,threshold,state%rk45_h,xnext,ds_actual, &
7118 step_status,state%accumulate_twist,rk45_twist_increment, &
7119 rk45_twist_status,rk45_twist_integrated)
7120 else if (trace_integrator_mode==trace_integrator_rk45_spherical .and. &
7121 geo_coordinate==geo_spherical)
then
7123 call trace_summary_rk45_spherical_step(state%x,state%igrid,ds, &
7124 state%forward,threshold,state%rk45_h,state%sph_cache,xnext, &
7125 ds_actual,step_status,state%accumulate_twist, &
7126 rk45_twist_increment,rk45_twist_status,rk45_twist_integrated)
7128 call trace_summary_rk2_step(state%x,state%igrid,ds,state%forward, &
7129 threshold,xnext,ds_actual,step_status,sph_cache=state%sph_cache)
7133 trace_rk45_position_integrator())
then
7134 call trace_boundary_face_at_point(state%x,state%face,hit_ok)
7135 if (.not.hit_ok)
then
7136 ^
d&domain_min(^
d)=xprobmin^
d;
7137 ^
d&domain_max(^
d)=xprobmax^
d;
7138 near_tol=max(100.d0*epsilon(one)* &
7139 max(one,maxval(abs(domain_max-domain_min))), &
7140 1.
d-5*max(one,abs(ds)))
7145 if (.not.trace_physical_dimension(idim)) cycle
7146 face_dist=abs(state%x(idim)-domain_min(idim))
7147 if (face_dist<best_dist)
then
7152 face_dist=abs(state%x(idim)-domain_max(idim))
7153 if (face_dist<best_dist)
then
7159 if (best_dim>0 .and. best_dist<=near_tol)
then
7160 if (best_side<0)
then
7161 state%x(best_dim)=domain_min(best_dim)
7163 state%x(best_dim)=domain_max(best_dim)
7165 state%footpoint=state%x
7166 state%face=trace_face_from_dim_side(best_dim,best_side)
7172 state%active=.false.
7176 state%status=step_status
7177 state%active=.false.
7182 {
if (trace_coordinate_in_domain(xnext(^db),^db)) point_domain=point_domain+1\}
7183 if (point_domain/=
ndim)
then
7184 call trace_intersect_domain(state%x,xnext,xhit,hit_ok,face_id, &
7187 if (trace_rk45_position_integrator() .and. &
7189 segment_length=abs(ds_actual)
7191 segment_length=trace_segment_length(state%x,xhit,ds_actual, &
7194 if (state%accumulate_twist .and. &
7196 if (rk45_step .and. rk45_twist_integrated)
then
7197 state%twist=state%twist+rk45_twist_increment
7199 state%twist_status=rk45_twist_status
7201 call trace_summary_accumulate_twist(state,xhit,segment_length, &
7202 threshold,step_status)
7204 state%twist_status=step_status
7208 state%length=state%length+segment_length
7210 state%nstep=state%nstep+1
7211 if (trace_spherical_profile_enabled .and. &
7212 geo_coordinate==geo_spherical)
then
7213 call trace_spherical_profile_add_count(trace_profile_steps,1_8)
7216 call trace_normalize_position(state%x)
7217 state%footpoint=state%x
7220 if (trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical) &
7221 call trace_spherical_profile_add_count(trace_profile_boundary_events, &
7224 state%active=.false.
7225 if (trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical) &
7226 call trace_spherical_profile_note_trace_steps(state%nstep)
7230 if (state%accumulate_twist .and. &
7232 if (rk45_step .and. rk45_twist_integrated)
then
7233 state%twist=state%twist+rk45_twist_increment
7235 state%twist_status=rk45_twist_status
7237 call trace_summary_accumulate_twist(state,xnext,ds_actual,threshold, &
7240 state%twist_status=step_status
7245 state%length=state%length+abs(ds_actual)
7247 state%length=state%length+trace_segment_length(state%x,xnext, &
7250 state%nstep=state%nstep+1
7251 if (trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical) &
7252 call trace_spherical_profile_add_count(trace_profile_steps,1_8)
7254 call trace_normalize_position(state%x)
7255 state%footpoint=state%x
7260 {
if (state%x(^db)>=xbmin^db .and. state%x(^db)<xbmax^db) inblock=inblock+1\}
7261 if (inblock==
ndim)
return
7263 igrid_next=state%igrid
7267 if (trace_periodic_phi())
then
7268 call trace_debug_locate_point(state%x,igrid_next,step_status)
7271 call find_next_grid(state%igrid,igrid_next,ipe_next,state%x,newpe,stop_trace)
7273 if (stop_trace)
then
7275 state%active=.false.
7276 if (trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical) &
7277 call trace_spherical_profile_add_count(trace_profile_boundary_events, &
7279 if (trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical) &
7280 call trace_spherical_profile_note_trace_steps(state%nstep)
7283 if (newpe .or. ipe_next/=
mype)
then
7284 if (trace_rk45_position_integrator())
then
7285 call trace_boundary_face_at_point(state%x,state%face,hit_ok)
7286 if (.not.hit_ok)
then
7287 ^
d&domain_min(^
d)=xprobmin^
d;
7288 ^
d&domain_max(^
d)=xprobmax^
d;
7289 near_tol=max(100.d0*epsilon(one)* &
7290 max(one,maxval(abs(domain_max-domain_min))), &
7291 1.
d-6*max(one,abs(ds_actual)))
7296 if (.not.trace_physical_dimension(idim)) cycle
7297 face_dist=abs(state%x(idim)-domain_min(idim))
7298 if (face_dist<best_dist)
then
7303 face_dist=abs(state%x(idim)-domain_max(idim))
7304 if (face_dist<best_dist)
then
7310 if (best_dim>0 .and. best_dist<=near_tol)
then
7311 if (best_side<0)
then
7312 state%x(best_dim)=domain_min(best_dim)
7314 state%x(best_dim)=domain_max(best_dim)
7316 state%footpoint=state%x
7317 state%face=trace_face_from_dim_side(best_dim,best_side)
7323 state%active=.false.
7328 state%active=.false.
7329 if (trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical) &
7330 call trace_spherical_profile_note_trace_steps(state%nstep)
7333 state%igrid=igrid_next
7334 end subroutine trace_summary_advance_state
7336 subroutine trace_summary_accumulate_twist(state,xend,segment_length, &
7338 type(trace_summary_state),
intent(inout) :: state
7339 double precision,
intent(in) :: xend(
ndim),segment_length,threshold
7340 integer,
intent(out) :: status
7342 double precision :: xmid(
ndim),b(3),curlb(3),b2,twist_density
7345 if (segment_length<=zero)
return
7347 xmid=half*(state%x+xend)
7348 call sample_b_curlb_at_point(xmid,state%igrid,threshold,b,curlb,status, &
7349 sph_cache=state%sph_cache)
7353 twist_density=sum(curlb*b)/(4.d0*dpi*b2)
7355 state%twist=state%twist+twist_density*segment_length
7356 end subroutine trace_summary_accumulate_twist
7358 subroutine trace_twist_density_at_point(x,igrid,threshold,twist_density, &
7360 double precision,
intent(in) :: x(
ndim),threshold
7361 integer,
intent(in) :: igrid
7362 double precision,
intent(out) :: twist_density
7363 integer,
intent(out) :: status
7364 type(trace_sph_interp_ctx),
intent(inout),
optional :: sph_cache
7366 double precision :: b(3),curlb(3),b2
7369 call sample_b_curlb_at_point(x,igrid,threshold,b,curlb,status, &
7370 sph_cache=sph_cache)
7378 twist_density=sum(curlb*b)/(4.d0*dpi*b2)
7379 end subroutine trace_twist_density_at_point
7381 subroutine trace_tangent_accumulate_twist(state,xend,segment_length, &
7383 type(trace_tangent_state),
intent(inout) :: state
7384 double precision,
intent(in) :: xend(
ndim),segment_length,threshold
7386 double precision :: xmid(
ndim),twist_density
7388 if (.not.state%accumulate_twist)
return
7390 if (segment_length<=zero)
return
7391 xmid=half*(state%x+xend)
7392 call trace_twist_density_at_point(xmid,state%igrid,threshold, &
7393 twist_density,state%twist_status,sph_cache=state%sph_cache)
7395 state%twist=state%twist+twist_density*segment_length
7396 end subroutine trace_tangent_accumulate_twist
7398 integer function trace_summary_twist_status_from_states(forward_state, &
7399 backward_state)
result(status_twist)
7400 type(trace_summary_state),
intent(in) :: forward_state,backward_state
7404 status_twist=forward_state%status
7406 status_twist=backward_state%status
7408 status_twist=forward_state%twist_status
7410 status_twist=backward_state%twist_status
7412 end function trace_summary_twist_status_from_states
7414 subroutine trace_tangent_fill_twist_result(seed,forward_state, &
7415 backward_state,result)
7416 double precision,
intent(in) :: seed(
ndim)
7417 type(trace_tangent_state),
intent(in) :: forward_state,backward_state
7420 result%line%seed=seed
7421 result%line%forward_footpoint=forward_state%endpoint
7422 result%line%backward_footpoint=backward_state%endpoint
7423 result%line%forward_length=forward_state%length
7424 result%line%backward_length=backward_state%length
7425 result%line%total_length=forward_state%length+backward_state%length
7426 result%line%forward_nstep=forward_state%nstep
7427 result%line%backward_nstep=backward_state%nstep
7428 result%line%forward_status=forward_state%status
7429 result%line%backward_status=backward_state%status
7430 result%forward_twist=forward_state%twist
7431 result%backward_twist=backward_state%twist
7432 result%total_twist=forward_state%twist+backward_state%twist
7435 result%status_twist=forward_state%status
7437 result%status_twist=backward_state%status
7439 result%status_twist=forward_state%twist_status
7441 result%status_twist=backward_state%twist_status
7444 end subroutine trace_tangent_fill_twist_result
7446 subroutine trace_total_b_at_cell(igrid,ix1,ix2,ix3,B,status)
7447 integer,
intent(in) :: igrid,ix1,ix2,ix3
7448 double precision,
intent(out) :: b(3)
7449 integer,
intent(out) :: status
7453 if (
ndim/=3 .or. igrid<0)
return
7456 if (.not.
b0field .and. .not.
allocated(iw_mag))
return
7457 if (
allocated(iw_mag))
then
7458 b(1:3)=ps(igrid)%w(ix1,ix2,ix3,iw_mag(1:3))
7461 b(1:3)=b(1:3)+ps(igrid)%B0(ix1,ix2,ix3,1:3,0)
7465 end subroutine trace_total_b_at_cell
7467 subroutine trace_bhat_at_cell(igrid,ix1,ix2,ix3,threshold,bhat,status)
7468 integer,
intent(in) :: igrid,ix1,ix2,ix3
7469 double precision,
intent(in) :: threshold
7470 double precision,
intent(out) :: bhat(3)
7471 integer,
intent(out) :: status
7473 double precision :: b(3),bnorm
7476 call trace_total_b_at_cell(igrid,ix1,ix2,ix3,b,status)
7479 bnorm=dsqrt(sum(b**2))
7480 if (bnorm<=zero .or. bnorm<threshold)
then
7485 end subroutine trace_bhat_at_cell
7487 subroutine sample_bhat_gradbhat_at_point(x,igrid,threshold,bhat, &
7490 double precision,
intent(in) :: x(
ndim),threshold
7491 integer,
intent(in) :: igrid
7492 double precision,
intent(out) :: bhat(3),grad_bhat(3,3)
7493 integer,
intent(out) :: status
7495 call sample_bhat_gradbhat_interpderiv_at_point(x,igrid,threshold,bhat, &
7497 end subroutine sample_bhat_gradbhat_at_point
7499 subroutine sample_bhat_gradbhat_cellfd_at_point(x,igrid,threshold,bhat, &
7502 double precision,
intent(in) :: x(
ndim),threshold
7503 integer,
intent(in) :: igrid
7504 double precision,
intent(out) :: bhat(3),grad_bhat(3,3)
7505 integer,
intent(out) :: status
7507 double precision :: dxb^
d,dxc^
d,xd^
d
7508 double precision :: bhat_cell(0:1^
d&,3)
7509 double precision :: grad_cell(0:1^
d&,3,3)
7510 double precision :: factor(0:1^
d&)
7511 double precision :: bhat_center(3),bhat_plus(3),bhat_minus(3)
7512 integer :: ixi^
l,ixbl^
d,ix^
d,j,k
7517 if (
ndim/=3 .or. igrid<0)
return
7522 ^
d&ixbl^
d=floor((x(^
d)-ps(igrid)%x(iximin^dd,^
d))/dxb^
d)+iximin^
d;
7523 ^
d&xd^
d=(x(^
d)-ps(igrid)%x(ixbl^dd,^
d))/dxb^
d;
7525 if (ixbl1-1<iximin1 .or. ixbl1+2>iximax1 .or. &
7526 ixbl2-1<iximin2 .or. ixbl2+2>iximax2 .or. &
7527 ixbl3-1<iximin3 .or. ixbl3+2>iximax3)
return
7532 call trace_bhat_at_cell(igrid,ixbl1+ix1,ixbl2+ix2, &
7533 ixbl3+ix3,threshold,bhat_center,status)
7535 bhat_cell(ix^
d,1:3)=bhat_center
7537 call trace_bhat_at_cell(igrid,ixbl1+ix1+1,ixbl2+ix2, &
7538 ixbl3+ix3,threshold,bhat_plus,status)
7540 call trace_bhat_at_cell(igrid,ixbl1+ix1-1,ixbl2+ix2, &
7541 ixbl3+ix3,threshold,bhat_minus,status)
7543 grad_cell(ix^
d,1:3,1)=(bhat_plus-bhat_minus)/(2.d0*dxb1)
7545 call trace_bhat_at_cell(igrid,ixbl1+ix1,ixbl2+ix2+1, &
7546 ixbl3+ix3,threshold,bhat_plus,status)
7548 call trace_bhat_at_cell(igrid,ixbl1+ix1,ixbl2+ix2-1, &
7549 ixbl3+ix3,threshold,bhat_minus,status)
7551 grad_cell(ix^
d,1:3,2)=(bhat_plus-bhat_minus)/(2.d0*dxb2)
7553 call trace_bhat_at_cell(igrid,ixbl1+ix1,ixbl2+ix2, &
7554 ixbl3+ix3+1,threshold,bhat_plus,status)
7556 call trace_bhat_at_cell(igrid,ixbl1+ix1,ixbl2+ix2, &
7557 ixbl3+ix3-1,threshold,bhat_minus,status)
7559 grad_cell(ix^
d,1:3,3)=(bhat_plus-bhat_minus)/(2.d0*dxb3)
7563 factor(ix^
d)={abs(1-ix^
d-xd^
d)*}
7567 bhat(j)=bhat(j)+bhat_cell(ix^
d,j)*factor(ix^
d)
7569 grad_bhat(j,k)=grad_bhat(j,k)+grad_cell(ix^
d,j,k)*factor(ix^
d)
7576 end subroutine sample_bhat_gradbhat_cellfd_at_point
7578 subroutine sample_bhat_gradbhat_xeps_at_point(x,eps,threshold,bhat, &
7581 double precision,
intent(in) :: x(
ndim),eps,threshold
7582 double precision,
intent(out) :: bhat(3),grad_bhat(3,3)
7583 integer,
intent(out) :: status
7585 double precision :: xp(
ndim),xm(
ndim)
7586 double precision :: b(3),bp(3),bm(3),bhat_p(3),bhat_m(3)
7587 double precision :: bnorm,bpnorm,bmnorm
7588 integer :: igrid,idir,point_domain
7602 call trace_debug_locate_point(x,igrid,status)
7604 call sample_b_at_point(x,igrid,threshold,b,status)
7606 bnorm=dsqrt(sum(b**2))
7607 if (bnorm<=zero .or. bnorm<threshold)
then
7616 xp(idir)=xp(idir)+eps
7617 xm(idir)=xm(idir)-eps
7620 {
if (trace_coordinate_in_domain(xp(^db),^db)) point_domain=point_domain+1\}
7621 if (point_domain/=
ndim)
then
7625 call trace_debug_locate_point(xp,igrid,status)
7627 call sample_b_at_point(xp,igrid,threshold,bp,status)
7629 bpnorm=dsqrt(sum(bp**2))
7630 if (bpnorm<=zero .or. bpnorm<threshold)
then
7637 {
if (trace_coordinate_in_domain(xm(^db),^db)) point_domain=point_domain+1\}
7638 if (point_domain/=
ndim)
then
7642 call trace_debug_locate_point(xm,igrid,status)
7644 call sample_b_at_point(xm,igrid,threshold,bm,status)
7646 bmnorm=dsqrt(sum(bm**2))
7647 if (bmnorm<=zero .or. bmnorm<threshold)
then
7653 grad_bhat(1:3,idir)=(bhat_p-bhat_m)/(2.d0*eps)
7657 end subroutine sample_bhat_gradbhat_xeps_at_point
7659 subroutine sample_bhat_gradbhat_interpderiv_at_point(x,igrid,threshold, &
7660 bhat,grad_bhat,status)
7662 double precision,
intent(in) :: x(
ndim),threshold
7663 integer,
intent(in) :: igrid
7664 double precision,
intent(out) :: bhat(3),grad_bhat(3,3)
7665 integer,
intent(out) :: status
7667 double precision :: dxb^
d,dxc^
d,xd^
d
7668 double precision :: field(0:1^
d&,3)
7669 double precision :: b(3),dbdx(3,3)
7670 double precision :: wx(0:1),wy(0:1),wz(0:1)
7671 double precision :: dwx(0:1),dwy(0:1),dwz(0:1)
7672 double precision :: weight,bnorm,projected
7673 integer :: ixi^
l,ixbl^
d,ix^
d,j
7678 if (
ndim/=3 .or. .not.trace_cartesian_like_geometry() .or. igrid<0)
then
7685 call trace_interp_weights_block(x,igrid,ixi^
l,ixbl^
d,xd^
d,dxc^
d, &
7689 if (ixbl1<iximin1 .or. ixbl1+1>iximax1 .or. &
7690 ixbl2<iximin2 .or. ixbl2+1>iximax2 .or. &
7691 ixbl3<iximin3 .or. ixbl3+1>iximax3)
return
7694 if (.not.
b0field .and. .not.
allocated(iw_mag))
return
7698 if (
allocated(iw_mag))
then
7699 field(ix^
d,1:3)=ps(igrid)%w(ixbl1+ix1,ixbl2+ix2, &
7700 ixbl3+ix3,iw_mag(1:3))
7703 field(ix^
d,1:3)=field(ix^
d,1:3) &
7704 +ps(igrid)%B0(ixbl1+ix1,ixbl2+ix2,ixbl3+ix3,1:3,0)
7724 weight=wx(ix1)*wy(ix2)*wz(ix3)
7725 b(1:3)=b(1:3)+field(ix^
d,1:3)*weight
7726 dbdx(1:3,1)=dbdx(1:3,1)+field(ix^
d,1:3)* &
7727 dwx(ix1)*wy(ix2)*wz(ix3)
7728 dbdx(1:3,2)=dbdx(1:3,2)+field(ix^
d,1:3)* &
7729 wx(ix1)*dwy(ix2)*wz(ix3)
7730 dbdx(1:3,3)=dbdx(1:3,3)+field(ix^
d,1:3)* &
7731 wx(ix1)*wy(ix2)*dwz(ix3)
7734 bnorm=dsqrt(sum(b**2))
7735 if (bnorm<=zero .or. bnorm<threshold)
then
7742 projected=sum(bhat*dbdx(1:3,j))
7743 grad_bhat(1:3,j)=(dbdx(1:3,j)-bhat(1:3)*projected)/bnorm
7748 end subroutine sample_bhat_gradbhat_interpderiv_at_point
7750 subroutine sample_b_curlb_at_point(x,igrid,threshold,B,curlB,status, &
7753 double precision,
intent(in) :: x(
ndim),threshold
7754 integer,
intent(in) :: igrid
7755 double precision,
intent(out) :: b(3),curlb(3)
7756 integer,
intent(out) :: status
7757 type(trace_sph_interp_ctx),
intent(inout),
optional :: sph_cache
7759 double precision :: dxb^
d,dxc^
d,xd^
d
7760 double precision :: field(0:1^
d&,3),current(0:1^D&,3)
7761 double precision :: factor(0:1^
d&),B2
7762 double precision :: dx1c,dx2c,dx3c
7763 integer :: ixi^
l,ixj^
l,ixbl^
d,ix^
d,j
7770 if (geo_coordinate==geo_spherical)
then
7771 if (
present(sph_cache))
then
7772 call sample_b_curlb_spherical_at_point(x,igrid,threshold,b,curlb, &
7773 status,sph_cache=sph_cache)
7775 call sample_b_curlb_spherical_at_point(x,igrid,threshold,b,curlb, &
7784 call trace_interp_weights_block(x,igrid,ixi^
l,ixbl^
d,xd^
d,dxc^
d, &
7788 if (ixbl1-1<iximin1 .or. ixbl1+2>iximax1 .or. &
7789 ixbl2-1<iximin2 .or. ixbl2+2>iximax2 .or. &
7790 ixbl3-1<iximin3 .or. ixbl3+2>iximax3)
return
7792 if (ixbl1<ixjmin1 .or. ixbl1+1>ixjmax1 .or. &
7793 ixbl2<ixjmin2 .or. ixbl2+1>ixjmax2 .or. &
7794 ixbl3<ixjmin3 .or. ixbl3+1>ixjmax3)
return
7797 if (.not.
b0field .and. .not.
allocated(iw_mag))
return
7802 if (
allocated(iw_mag))
then
7803 field(ix^
d,1:3)=ps(igrid)%w(ixbl1+ix1,ixbl2+ix2, &
7804 ixbl3+ix3,iw_mag(1:3))
7807 field(ix^
d,1:3)=field(ix^
d,1:3) &
7808 +ps(igrid)%B0(ixbl1+ix1,ixbl2+ix2,ixbl3+ix3,1:3,0)
7810 if (
allocated(iw_mag))
then
7811 dx1c=ps(igrid)%x(ixbl1+ix1+1,ixbl2+ix2,ixbl3+ix3,1) &
7812 -ps(igrid)%x(ixbl1+ix1-1,ixbl2+ix2,ixbl3+ix3,1)
7813 dx2c=ps(igrid)%x(ixbl1+ix1,ixbl2+ix2+1,ixbl3+ix3,2) &
7814 -ps(igrid)%x(ixbl1+ix1,ixbl2+ix2-1,ixbl3+ix3,2)
7815 dx3c=ps(igrid)%x(ixbl1+ix1,ixbl2+ix2,ixbl3+ix3+1,3) &
7816 -ps(igrid)%x(ixbl1+ix1,ixbl2+ix2,ixbl3+ix3-1,3)
7817 if (abs(dx1c)<=smalldouble .or. abs(dx2c)<=smalldouble .or. &
7818 abs(dx3c)<=smalldouble)
then
7822 current(ix^
d,1)=half*( &
7823 (ps(igrid)%w(ixbl1+ix1,ixbl2+ix2+1,ixbl3+ix3,iw_mag(3)) &
7824 -ps(igrid)%w(ixbl1+ix1,ixbl2+ix2-1,ixbl3+ix3,iw_mag(3)))/dx2c &
7825 -(ps(igrid)%w(ixbl1+ix1,ixbl2+ix2,ixbl3+ix3+1,iw_mag(2)) &
7826 -ps(igrid)%w(ixbl1+ix1,ixbl2+ix2,ixbl3+ix3-1,iw_mag(2)))/dx3c)
7827 current(ix^
d,2)=half*( &
7828 (ps(igrid)%w(ixbl1+ix1,ixbl2+ix2,ixbl3+ix3+1,iw_mag(1)) &
7829 -ps(igrid)%w(ixbl1+ix1,ixbl2+ix2,ixbl3+ix3-1,iw_mag(1)))/dx3c &
7830 -(ps(igrid)%w(ixbl1+ix1+1,ixbl2+ix2,ixbl3+ix3,iw_mag(3)) &
7831 -ps(igrid)%w(ixbl1+ix1-1,ixbl2+ix2,ixbl3+ix3,iw_mag(3)))/dx1c)
7832 current(ix^
d,3)=half*( &
7833 (ps(igrid)%w(ixbl1+ix1+1,ixbl2+ix2,ixbl3+ix3,iw_mag(2)) &
7834 -ps(igrid)%w(ixbl1+ix1-1,ixbl2+ix2,ixbl3+ix3,iw_mag(2)))/dx1c &
7835 -(ps(igrid)%w(ixbl1+ix1,ixbl2+ix2+1,ixbl3+ix3,iw_mag(1)) &
7836 -ps(igrid)%w(ixbl1+ix1,ixbl2+ix2-1,ixbl3+ix3,iw_mag(1)))/dx2c)
7839 current(ix^
d,1:3)=current(ix^
d,1:3) &
7840 +ps(igrid)%J0(ixbl^
d+ix^
d,1:3)
7845 factor(ix^
d)={abs(1-ix^
d-xd^
d)*}
7849 b(j)=b(j)+field(ix^
d,j)*factor(ix^
d)
7850 curlb(j)=curlb(j)+current(ix^
d,j)*factor(ix^
d)
7855 if (b2<=zero .or. dsqrt(b2)<threshold)
then
7861 end subroutine sample_b_curlb_at_point
7863 subroutine sample_b_curlb_spherical_at_point(x_input,igrid_input,threshold,B,curlB, &
7867 double precision,
intent(in) :: x_input(
ndim),threshold
7868 integer,
intent(in) :: igrid_input
7869 double precision,
intent(out) :: b(3),curlb(3)
7870 integer,
intent(out) :: status
7871 type(trace_sph_interp_ctx),
intent(inout),
optional :: sph_cache
7873 double precision :: dxb^
d,dxc^
d,xd^
d
7874 double precision :: bvec(ixg^t,1:3),current(ixg^t,1:3)
7875 double precision :: factor(0:1^
d&),B2
7876 type(trace_sph_interp_ctx) :: ctx
7877 integer :: ixi^
l,ixo^
l,ixa^
l,ixj^
l,ixbl^
d,ix^
d,j,idirmin
7879 double precision :: x(
ndim)
7880 integer :: igrid,locate_status
7883 call trace_normalize_position(x)
7885 if (trace_periodic_phi())
then
7886 call trace_locate_point_with_hint(x,igrid_input,igrid,locate_status)
7888 status=locate_status
7895 if (
ndim/=3 .or. geo_coordinate/=geo_spherical .or. igrid<0)
return
7898 if (
present(sph_cache))
then
7899 call trace_spherical_interp_ctx_build_cached(x,igrid,sph_cache,ctx, &
7902 call trace_spherical_interp_ctx_build(x,igrid,ctx,status)
7905 call trace_spherical_sample_bsph_ctx(ctx,threshold,b,status)
7907 if (trace_spherical_curl_cache_ready)
then
7908 call trace_spherical_sample_cached_curlb_ctx(ctx,curlb,status)
7911 if (b2<=zero .or. dsqrt(b2)<threshold)
then
7922 ^
d&dxc^
d=ctx%dxc(^
d);
7924 ^
d&ixbl^
d=ctx%ixbl(^
d);
7926 ^
d&ixomax^
d=ixbl^
d+1;
7930 if (iximin1>ixamin1 .or. iximax1<ixamax1 .or. &
7931 iximin2>ixamin2 .or. iximax2<ixamax2 .or. &
7932 iximin3>ixamin3 .or. iximax3<ixamax3)
return
7934 if (ixjmin1>ixomin1 .or. ixjmax1<ixomax1 .or. &
7935 ixjmin2>ixomin2 .or. ixjmax2<ixomax2 .or. &
7936 ixjmin3>ixomin3 .or. ixjmax3<ixomax3)
return
7939 if (.not.
b0field .and. .not.
allocated(iw_mag))
return
7943 if (
allocated(iw_mag))
then
7944 bvec(ixa^s,1:3)=ps(igrid)%w(ixa^s,iw_mag(1:3))
7950 current(ixo^s,1:3)=current(ixo^s,1:3)+ps(igrid)%J0(ixo^s,1:3)
7954 factor(ix^
d)={abs(1-ix^
d-xd^
d)*}
7958 curlb(j)=curlb(j)+current(ixbl^
d+ix^
d,j)*factor(ix^
d)
7963 if (b2<=zero .or. dsqrt(b2)<threshold)
then
7969 end subroutine sample_b_curlb_spherical_at_point
7971 subroutine sample_b_at_point(x,igrid,threshold,B,status)
7973 double precision,
intent(in) :: x(
ndim),threshold
7974 integer,
intent(in) :: igrid
7975 double precision,
intent(out) :: b(3)
7976 integer,
intent(out) :: status
7978 double precision :: dxb^
d,dxc^
d,xd^
d
7979 double precision :: field(0:1^
d&,3),factor(0:1^D&),B2
7980 double precision :: bcell(3)
7981 type(trace_sph_interp_ctx) :: ctx
7982 integer :: ixi^
l,ixbl^
d,ix^
d,j
7986 if (
ndim/=3 .or. igrid<0)
return
7990 if (geo_coordinate==geo_spherical)
then
7991 call trace_spherical_interp_ctx_build(x,igrid,ctx,status)
7993 call trace_spherical_sample_bsph_ctx(ctx,threshold,b,status)
7996 call trace_interp_weights_block(x,igrid,ixi^
l,ixbl^
d,xd^
d,dxc^
d, &
8001 if (ixbl1<iximin1 .or. ixbl1+1>iximax1 .or. &
8002 ixbl2<iximin2 .or. ixbl2+1>iximax2 .or. &
8003 ixbl3<iximin3 .or. ixbl3+1>iximax3)
return
8006 call trace_total_b_at_cell(igrid,ixbl1+ix1,ixbl2+ix2, &
8007 ixbl3+ix3,bcell,status)
8009 field(ix^
d,1:3)=bcell
8013 factor(ix^
d)={abs(1-ix^
d-xd^
d)*}
8017 b(j)=b(j)+field(ix^
d,j)*factor(ix^
d)
8022 if (b2<=zero .or. dsqrt(b2)<threshold)
then
8028 end subroutine sample_b_at_point
8030 subroutine trace_summary_fill_mapping(seed,source_igrid,forward_state, &
8031 backward_state,threshold,have_source_normal,source_normal,result)
8032 double precision,
intent(in) :: seed(
ndim),threshold,source_normal(3)
8033 integer,
intent(in) :: source_igrid
8034 logical,
intent(in) :: have_source_normal
8035 type(trace_summary_state),
intent(in) :: forward_state,backward_state
8042 result%forward_footpoint=forward_state%footpoint
8043 result%backward_footpoint=backward_state%footpoint
8044 result%forward_length=forward_state%length
8045 result%backward_length=backward_state%length
8046 result%forward_face=forward_state%face
8047 result%backward_face=backward_state%face
8048 result%forward_status=forward_state%status
8049 result%backward_status=backward_state%status
8051 call sample_b_at_point(seed,source_igrid,threshold,result%source_B,status)
8053 result%forward_status=status
8054 result%backward_status=status
8055 result%valid=.false.
8058 if (have_source_normal)
then
8059 result%source_Bn=sum(result%source_B*source_normal)
8063 call sample_b_at_point(forward_state%footpoint,forward_state%igrid, &
8064 threshold,result%forward_B,status)
8068 call sample_b_at_point(backward_state%footpoint,backward_state%igrid, &
8069 threshold,result%backward_B,status)
8073 result%forward_Bn=trace_face_bn(result%forward_face,result%forward_B)
8074 result%backward_Bn=trace_face_bn(result%backward_face,result%backward_B)
8077 trace_face_is_boundary(result%forward_face) .and. &
8078 trace_face_is_boundary(result%backward_face)
8079 end subroutine trace_summary_fill_mapping
8081 double precision function trace_face_bn(face_id,B)
result(Bn)
8082 integer,
intent(in) :: face_id
8083 double precision,
intent(in) :: b(3)
8086 select case(face_id)
8100 end function trace_face_bn
8102 logical function trace_face_is_boundary(face_id)
result(is_boundary)
8103 integer,
intent(in) :: face_id
8106 end function trace_face_is_boundary
8108 subroutine trace_boundary_face_at_point(x,face_id,on_boundary)
8109 double precision,
intent(in) :: x(
ndim)
8110 integer,
intent(out) :: face_id
8111 logical,
intent(out) :: on_boundary
8113 double precision :: domain_min(
ndim),domain_max(
ndim),tol
8114 integer :: idim,nface,candidate_face
8116 ^
d&domain_min(^
d)=xprobmin^
d;
8117 ^
d&domain_max(^
d)=xprobmax^
d;
8118 tol=100.d0*epsilon(one)*max(one,maxval(abs(domain_max-domain_min)))
8122 if (.not.trace_physical_dimension(idim)) cycle
8123 if (abs(x(idim)-domain_min(idim))<=tol)
then
8124 candidate_face=trace_face_from_dim_side(idim,-1)
8127 face_id=candidate_face
8128 else if (candidate_face/=face_id)
then
8132 if (abs(x(idim)-domain_max(idim))<=tol)
then
8133 candidate_face=trace_face_from_dim_side(idim,1)
8136 face_id=candidate_face
8137 else if (candidate_face/=face_id)
then
8143 end subroutine trace_boundary_face_at_point
8145 subroutine trace_intersect_domain(xinside,xoutside,xhit,hit_ok,face_id, &
8147 double precision,
intent(in) :: xinside(
ndim),xoutside(
ndim)
8148 double precision,
intent(out) :: xhit(
ndim)
8149 logical,
intent(out) :: hit_ok
8150 integer,
intent(out) :: face_id
8151 double precision,
intent(out),
optional :: alpha_out
8153 double precision :: alpha,alpha_hit,alpha_tol,delta
8154 double precision :: domain_min(
ndim),domain_max(
ndim)
8155 integer :: idim,hit_dim,hit_side,candidate_face
8157 ^
d&domain_min(^
d)=xprobmin^
d;
8158 ^
d&domain_max(^
d)=xprobmax^
d;
8160 alpha_tol=100.d0*epsilon(one)
8165 if (.not.trace_physical_dimension(idim)) cycle
8166 delta=xoutside(idim)-xinside(idim)
8167 if (xoutside(idim)<domain_min(idim) .and. abs(delta)>smalldouble)
then
8168 alpha=(domain_min(idim)-xinside(idim))/delta
8169 if (alpha>=zero .and. alpha<=one)
then
8170 candidate_face=trace_face_from_dim_side(idim,-1)
8171 if (alpha<alpha_hit-alpha_tol)
then
8175 face_id=candidate_face
8176 else if (abs(alpha-alpha_hit)<=alpha_tol .and. &
8177 candidate_face/=face_id)
then
8181 else if (xoutside(idim)>=domain_max(idim) .and. &
8182 abs(delta)>smalldouble)
then
8183 alpha=(domain_max(idim)-xinside(idim))/delta
8184 if (alpha>=zero .and. alpha<=one)
then
8185 candidate_face=trace_face_from_dim_side(idim,1)
8186 if (alpha<alpha_hit-alpha_tol)
then
8190 face_id=candidate_face
8191 else if (abs(alpha-alpha_hit)<=alpha_tol .and. &
8192 candidate_face/=face_id)
then
8201 if (
present(alpha_out)) alpha_out=zero
8202 if (.not.hit_ok)
return
8204 xhit=xinside+alpha_hit*(xoutside-xinside)
8206 if (.not.trace_physical_dimension(idim)) cycle
8207 xhit(idim)=min(max(xhit(idim),domain_min(idim)),domain_max(idim))
8209 if (hit_side<0)
then
8210 xhit(hit_dim)=domain_min(hit_dim)
8212 xhit(hit_dim)=domain_max(hit_dim)
8214 if (
present(alpha_out)) alpha_out=alpha_hit
8215 end subroutine trace_intersect_domain
8217 integer function trace_face_from_dim_side(idim,side)
result(face_id)
8218 integer,
intent(in) :: idim,side
8241 end function trace_face_from_dim_side
8243 subroutine trace_cartesian_local_cell_size(x,igrid,hcell,status)
8244 double precision,
intent(in) :: x(
ndim)
8245 integer,
intent(in) :: igrid
8246 double precision,
intent(out) :: hcell
8247 integer,
intent(out) :: status
8249 double precision :: dxc^
d,xd^
d
8250 integer :: ixi^
l,ixbl^
d
8254 if (.not.trace_cartesian_like_geometry() .or. igrid<0)
return
8258 call trace_interp_weights_block(x,igrid,ixi^
l,ixbl^
d,xd^
d,dxc^
d, &
8261 hcell=min(abs(dxc1),abs(dxc2))
8262 hcell=min(hcell,abs(dxc3))
8265 end subroutine trace_cartesian_local_cell_size
8267 subroutine trace_cartesian_rhs_bhat(x,igrid_hint,threshold,bhat,igrid, &
8269 double precision,
intent(in) :: x(
ndim),threshold
8270 integer,
intent(in) :: igrid_hint
8271 double precision,
intent(out) :: bhat(
ndim)
8272 integer,
intent(out) :: igrid,status
8274 double precision :: dxc^
d,xd^
d
8275 double precision :: field(0:1^
d&,3),factor(0:1^D&)
8276 double precision :: bcell(3),b(3),bnorm
8277 integer :: ixi^
l,ixbl^
d,ix^
d,j
8282 if (.not.trace_cartesian_like_geometry())
return
8285 call trace_locate_point_with_hint(x,igrid_hint,igrid,status)
8289 call trace_interp_weights_block(x,igrid,ixi^
l,ixbl^
d,xd^
d,dxc^
d, &
8295 call trace_total_b_at_cell(igrid,ixbl1+ix1,ixbl2+ix2, &
8296 ixbl3+ix3,bcell,status)
8298 field(ix^
d,1:3)=bcell
8302 factor(ix^
d)={abs(1-ix^
d-xd^
d)*}
8308 b(j)=b(j)+field(ix^
d,j)*factor(ix^
d)
8312 bnorm=dsqrt(sum(b**2))
8313 if (bnorm<=zero .or. bnorm<threshold)
then
8317 bhat=b(1:
ndim)/bnorm
8320 end subroutine trace_cartesian_rhs_bhat
8322 subroutine trace_rk45_try_boundary_finish(xnow,xstage,hfloor,xnext, &
8323 ds_actual,h_suggest,status,finished)
8324 double precision,
intent(in) :: xnow(
ndim),xstage(
ndim),hfloor
8325 double precision,
intent(out) :: xnext(
ndim),ds_actual
8326 double precision,
intent(inout) :: h_suggest
8327 integer,
intent(out) :: status
8328 logical,
intent(out) :: finished
8330 double precision :: xhit(
ndim)
8335 call trace_intersect_domain(xnow,xstage,xhit,hit_ok,face_id)
8336 if (.not.hit_ok)
return
8339 ds_actual=dsqrt(sum((xnext-xnow)**2))
8342 call trace_rk45_stats_note_attempt(.true.,.true.,ds_actual)
8344 end subroutine trace_rk45_try_boundary_finish
8346 subroutine trace_summary_rk45_cartesian_step(xnow,igrid,ds,forward, &
8347 threshold,h_suggest,xnext,ds_actual,status,accumulate_twist, &
8348 twist_increment,twist_status,twist_integrated)
8349 double precision,
intent(in) :: xnow(
ndim),ds,threshold
8350 integer,
intent(in) :: igrid
8351 logical,
intent(in) :: forward
8352 double precision,
intent(inout) :: h_suggest
8353 double precision,
intent(out) :: xnext(
ndim),ds_actual
8354 integer,
intent(out) :: status
8355 logical,
intent(in) :: accumulate_twist
8356 double precision,
intent(out) :: twist_increment
8357 integer,
intent(out) :: twist_status
8358 logical,
intent(out) :: twist_integrated
8360 double precision,
parameter :: b21=1.d0/5.d0
8361 double precision,
parameter :: b31=3.d0/40.d0,b32=9.d0/40.d0
8362 double precision,
parameter :: b41=3.d0/10.d0,b42=-9.d0/10.d0, &
8364 double precision,
parameter :: b51=-11.d0/54.d0,b52=5.d0/2.d0, &
8365 b53=-70.d0/27.d0,b54=35.d0/27.d0
8366 double precision,
parameter :: b61=1631.d0/55296.d0, &
8367 b62=175.d0/512.d0,b63=575.d0/13824.d0, &
8368 b64=44275.d0/110592.d0,b65=253.d0/4096.d0
8369 double precision,
parameter :: c1=37.d0/378.d0,c3=250.d0/621.d0, &
8370 c4=125.d0/594.d0,c6=512.d0/1771.d0
8371 double precision,
parameter :: cs1=2825.d0/27648.d0, &
8372 cs3=18575.d0/48384.d0,cs4=13525.d0/55296.d0, &
8373 cs5=277.d0/14336.d0,cs6=one/4.d0
8378 double precision :: h,hmax,hfloor,hcell,tol,err,grow,sgn
8379 double precision :: tw1,tw3,tw4,tw6
8380 double precision :: domain_min(
ndim),domain_max(
ndim)
8381 integer :: igrid1,igrid2,igrid3,igrid4,igrid5,igrid6
8382 integer :: iter,point_domain,face_id
8383 integer :: reject_reason
8384 logical :: hit_ok,boundary_limited,boundary_finished
8389 twist_increment=zero
8391 twist_integrated=.false.
8392 if (.not.trace_cartesian_like_geometry())
then
8398 if (hmax<=zero)
then
8405 hfloor=max(trace_step_min,100.d0*epsilon(one)*max(one,hmax))
8408 if (.not.forward) sgn=-one
8409 ^
d&domain_min(^
d)=xprobmin^
d;
8410 ^
d&domain_max(^
d)=xprobmax^
d;
8413 h=max(hfloor,min(h,hmax))
8414 call trace_cartesian_rhs_bhat(xnow,igrid,threshold,k1,igrid1,status)
8417 x2=xnow+sgn*h*b21*k1
8418 call trace_cartesian_rhs_bhat(x2,igrid1,threshold,k2,igrid2,status)
8423 call trace_rk45_try_boundary_finish(xnow,x2,hfloor,xnext, &
8424 ds_actual,h_suggest,status,boundary_finished)
8425 if (boundary_finished)
return
8427 reject_reason=trace_rk45_reject_stage_failure
8430 reject_reason=trace_rk45_reject_stage_outside
8431 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
8433 if (h<=hfloor*(one+epsilon(one)))
exit
8434 h=max(hfloor,half*h)
8438 x3=xnow+sgn*h*(b31*k1+b32*k2)
8439 call trace_cartesian_rhs_bhat(x3,igrid2,threshold,k3,igrid3,status)
8444 call trace_rk45_try_boundary_finish(xnow,x3,hfloor,xnext, &
8445 ds_actual,h_suggest,status,boundary_finished)
8446 if (boundary_finished)
return
8448 reject_reason=trace_rk45_reject_stage_failure
8451 reject_reason=trace_rk45_reject_stage_outside
8452 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
8454 if (h<=hfloor*(one+epsilon(one)))
exit
8455 h=max(hfloor,half*h)
8459 x4=xnow+sgn*h*(b41*k1+b42*k2+b43*k3)
8460 call trace_cartesian_rhs_bhat(x4,igrid3,threshold,k4,igrid4,status)
8465 call trace_rk45_try_boundary_finish(xnow,x4,hfloor,xnext, &
8466 ds_actual,h_suggest,status,boundary_finished)
8467 if (boundary_finished)
return
8469 reject_reason=trace_rk45_reject_stage_failure
8472 reject_reason=trace_rk45_reject_stage_outside
8473 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
8475 if (h<=hfloor*(one+epsilon(one)))
exit
8476 h=max(hfloor,half*h)
8480 x5s=xnow+sgn*h*(b51*k1+b52*k2+b53*k3+b54*k4)
8481 call trace_cartesian_rhs_bhat(x5s,igrid4,threshold,k5,igrid5,status)
8486 call trace_rk45_try_boundary_finish(xnow,x5s,hfloor,xnext, &
8487 ds_actual,h_suggest,status,boundary_finished)
8488 if (boundary_finished)
return
8490 reject_reason=trace_rk45_reject_stage_failure
8493 reject_reason=trace_rk45_reject_stage_outside
8494 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
8496 if (h<=hfloor*(one+epsilon(one)))
exit
8497 h=max(hfloor,half*h)
8501 x6=xnow+sgn*h*(b61*k1+b62*k2+b63*k3+b64*k4+b65*k5)
8502 call trace_cartesian_rhs_bhat(x6,igrid5,threshold,k6,igrid6,status)
8507 call trace_rk45_try_boundary_finish(xnow,x6,hfloor,xnext, &
8508 ds_actual,h_suggest,status,boundary_finished)
8509 if (boundary_finished)
return
8511 reject_reason=trace_rk45_reject_stage_failure
8514 reject_reason=trace_rk45_reject_stage_outside
8515 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
8517 if (h<=hfloor*(one+epsilon(one)))
exit
8518 h=max(hfloor,half*h)
8522 x5=xnow+sgn*h*(c1*k1+c3*k3+c4*k4+c6*k6)
8523 x4err=xnow+sgn*h*(cs1*k1+cs3*k3+cs4*k4+cs5*k5+cs6*k6)
8526 {
if (trace_coordinate_in_domain(x5(^db),^db)) point_domain=point_domain+1\}
8527 if (point_domain/=
ndim)
then
8528 call trace_intersect_domain(xnow,x5,xhit,hit_ok,face_id)
8531 ds_actual=dsqrt(sum((xnext-xnow)**2))
8534 call trace_rk45_stats_note_attempt(.true.,.true.,ds_actual)
8537 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
8538 trace_rk45_reject_boundary)
8543 call trace_cartesian_local_cell_size(xnow,igrid1,hcell,status)
8545 err=dsqrt(sum((x5-x4err)**2))
8546 tol=trace_rk45_atol+trace_rk45_rtol*max(h,hcell)
8547 if (err<=tol .or. h<=hfloor*(one+epsilon(one)))
then
8550 if (accumulate_twist)
then
8551 call trace_twist_density_at_point(xnow,igrid1,threshold,tw1, &
8554 call trace_twist_density_at_point(x3,igrid3,threshold,tw3, &
8557 call trace_twist_density_at_point(x4,igrid4,threshold,tw4, &
8560 call trace_twist_density_at_point(x6,igrid6,threshold,tw6, &
8563 twist_increment=h*(c1*tw1+c3*tw3+c4*tw4+c6*tw6)
8564 twist_integrated=.true.
8567 if (err>zero .and. tol>zero)
then
8568 grow=trace_rk45_safety*(tol/err)**0.2d0
8569 grow=max(trace_rk45_min_shrink,min(trace_rk45_max_grow,grow))
8571 grow=trace_rk45_max_grow
8573 h_suggest=min(hmax,max(hfloor,h*grow))
8574 call trace_rk45_stats_note_attempt(.true.,.false.,h)
8579 grow=trace_rk45_safety*(tol/max(err,smalldouble))**0.25d0
8580 grow=max(trace_rk45_min_shrink,min(one,grow))
8581 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
8582 trace_rk45_reject_error)
8583 h=max(hfloor,h*grow)
8586 call trace_intersect_domain(xnow,xnow+sgn*h*k1,xhit,hit_ok,face_id)
8588 boundary_limited=.true.
8590 ds_actual=dsqrt(sum((xnext-xnow)**2))
8592 call trace_rk45_stats_note_attempt(.true.,boundary_limited,ds_actual)
8597 end subroutine trace_summary_rk45_cartesian_step
8599 subroutine trace_summary_rk45_spherical_step(xnow,igrid,ds,forward, &
8600 threshold,h_suggest,sph_cache,xnext,ds_actual,status, &
8601 accumulate_twist,twist_increment,twist_status,twist_integrated)
8602 double precision,
intent(in) :: xnow(
ndim),ds,threshold
8603 integer,
intent(in) :: igrid
8604 logical,
intent(in) :: forward
8605 double precision,
intent(inout) :: h_suggest
8606 type(trace_sph_interp_ctx),
intent(inout) :: sph_cache
8607 double precision,
intent(out) :: xnext(
ndim),ds_actual
8608 integer,
intent(out) :: status
8609 logical,
intent(in) :: accumulate_twist
8610 double precision,
intent(out) :: twist_increment
8611 integer,
intent(out) :: twist_status
8612 logical,
intent(out) :: twist_integrated
8614 double precision,
parameter :: b21=1.d0/5.d0
8615 double precision,
parameter :: b31=3.d0/40.d0,b32=9.d0/40.d0
8616 double precision,
parameter :: b41=3.d0/10.d0,b42=-9.d0/10.d0, &
8618 double precision,
parameter :: b51=-11.d0/54.d0,b52=5.d0/2.d0, &
8619 b53=-70.d0/27.d0,b54=35.d0/27.d0
8620 double precision,
parameter :: b61=1631.d0/55296.d0, &
8621 b62=175.d0/512.d0,b63=575.d0/13824.d0, &
8622 b64=44275.d0/110592.d0,b65=253.d0/4096.d0
8623 double precision,
parameter :: c1=37.d0/378.d0,c3=250.d0/621.d0, &
8624 c4=125.d0/594.d0,c6=512.d0/1771.d0
8625 double precision,
parameter :: cs1=2825.d0/27648.d0, &
8626 cs3=18575.d0/48384.d0,cs4=13525.d0/55296.d0, &
8627 cs5=277.d0/14336.d0,cs6=one/4.d0
8632 double precision :: h,hmax,hfloor,hcell,tol,err,grow,sgn
8633 double precision :: tw1,tw3,tw4,tw6
8634 double precision :: r_metric,sin_theta_metric,alpha_hit
8635 double precision :: domain_min(
ndim),domain_max(
ndim)
8636 type(trace_sph_interp_ctx) :: ctx1,ctx2,ctx3,ctx4,ctx5,ctx6
8637 integer :: igrid1,igrid2,igrid3,igrid4,igrid5,igrid6
8638 integer :: iter,point_domain,face_id,ctx_status
8639 integer :: reject_reason
8640 logical :: hit_ok,field_ok
8641 character(len=std_len) :: field_type
8646 twist_increment=zero
8648 twist_integrated=.false.
8649 if (geo_coordinate/=geo_spherical)
then
8655 if (hmax<=zero)
then
8662 hfloor=max(trace_step_min,100.d0*epsilon(one)*max(one,hmax))
8665 if (.not.forward) sgn=-one
8667 ^
d&domain_min(^
d)=xprobmin^
d;
8668 ^
d&domain_max(^
d)=xprobmax^
d;
8671 h=max(hfloor,min(h,hmax))
8672 call trace_spherical_interp_ctx_build_cached(xnow,igrid,sph_cache, &
8678 call get_k_spherical_ctx(ctx1,k1,field_type,threshold,field_ok)
8679 if (.not.field_ok)
then
8686 x2=xnow+sgn*h*b21*k1
8687 call trace_spherical_interp_ctx_build_cached(x2,igrid1,sph_cache, &
8690 reject_reason=trace_rk45_reject_stage_failure
8693 reject_reason=trace_rk45_reject_stage_outside
8694 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
8696 if (h<=hfloor*(one+epsilon(one)))
exit
8697 h=max(hfloor,half*h)
8700 call get_k_spherical_ctx(ctx2,k2,field_type,threshold,field_ok)
8701 if (.not.field_ok)
then
8707 x3=xnow+sgn*h*(b31*k1+b32*k2)
8708 call trace_spherical_interp_ctx_build_cached(x3,igrid2,sph_cache, &
8711 reject_reason=trace_rk45_reject_stage_failure
8714 reject_reason=trace_rk45_reject_stage_outside
8715 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
8717 if (h<=hfloor*(one+epsilon(one)))
exit
8718 h=max(hfloor,half*h)
8721 call get_k_spherical_ctx(ctx3,k3,field_type,threshold,field_ok)
8722 if (.not.field_ok)
then
8728 x4=xnow+sgn*h*(b41*k1+b42*k2+b43*k3)
8729 call trace_spherical_interp_ctx_build_cached(x4,igrid3,sph_cache, &
8732 reject_reason=trace_rk45_reject_stage_failure
8735 reject_reason=trace_rk45_reject_stage_outside
8736 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
8738 if (h<=hfloor*(one+epsilon(one)))
exit
8739 h=max(hfloor,half*h)
8742 call get_k_spherical_ctx(ctx4,k4,field_type,threshold,field_ok)
8743 if (.not.field_ok)
then
8749 x5s=xnow+sgn*h*(b51*k1+b52*k2+b53*k3+b54*k4)
8750 call trace_spherical_interp_ctx_build_cached(x5s,igrid4,sph_cache, &
8753 reject_reason=trace_rk45_reject_stage_failure
8756 reject_reason=trace_rk45_reject_stage_outside
8757 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
8759 if (h<=hfloor*(one+epsilon(one)))
exit
8760 h=max(hfloor,half*h)
8763 call get_k_spherical_ctx(ctx5,k5,field_type,threshold,field_ok)
8764 if (.not.field_ok)
then
8770 x6=xnow+sgn*h*(b61*k1+b62*k2+b63*k3+b64*k4+b65*k5)
8771 call trace_spherical_interp_ctx_build_cached(x6,igrid5,sph_cache, &
8774 reject_reason=trace_rk45_reject_stage_failure
8777 reject_reason=trace_rk45_reject_stage_outside
8778 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
8780 if (h<=hfloor*(one+epsilon(one)))
exit
8781 h=max(hfloor,half*h)
8784 call get_k_spherical_ctx(ctx6,k6,field_type,threshold,field_ok)
8785 if (.not.field_ok)
then
8790 x5=xnow+sgn*h*(c1*k1+c3*k3+c4*k4+c6*k6)
8791 x4err=xnow+sgn*h*(cs1*k1+cs3*k3+cs4*k4+cs5*k5+cs6*k6)
8794 {
if (trace_coordinate_in_domain(x5(^db),^db)) point_domain=point_domain+1\}
8795 if (point_domain/=
ndim)
then
8796 call trace_intersect_domain(xnow,x5,xhit,hit_ok,face_id, &
8800 ds_actual=max(zero,min(one,alpha_hit))*h
8803 call trace_rk45_stats_note_attempt(.true.,.true.,ds_actual)
8806 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
8807 trace_rk45_reject_boundary)
8814 r_metric=max(abs(xnow(1)),smalldouble)
8815 sin_theta_metric=max(abs(dsin(xnow(2))),smalldouble)
8816 err=dsqrt((x5(1)-x4err(1))**2+ &
8817 (r_metric*(x5(2)-x4err(2)))**2+ &
8818 (r_metric*sin_theta_metric*(x5(3)-x4err(3)))**2)
8820 if (hcell<=zero) hcell=hmax
8821 tol=trace_rk45_atol+trace_rk45_rtol*max(h,hcell)
8822 if (err<=tol .or. h<=hfloor*(one+epsilon(one)))
then
8825 if (accumulate_twist)
then
8826 call trace_twist_density_at_point(xnow,ctx1%igrid,threshold,tw1, &
8827 twist_status,sph_cache)
8829 call trace_twist_density_at_point(x3,ctx3%igrid,threshold,tw3, &
8830 twist_status,sph_cache)
8832 call trace_twist_density_at_point(x4,ctx4%igrid,threshold,tw4, &
8833 twist_status,sph_cache)
8835 call trace_twist_density_at_point(x6,ctx6%igrid,threshold,tw6, &
8836 twist_status,sph_cache)
8838 twist_increment=h*(c1*tw1+c3*tw3+c4*tw4+c6*tw6)
8839 twist_integrated=.true.
8842 if (err>zero .and. tol>zero)
then
8843 grow=trace_rk45_safety*(tol/err)**0.2d0
8844 grow=max(trace_rk45_min_shrink,min(trace_rk45_max_grow,grow))
8846 grow=trace_rk45_max_grow
8848 h_suggest=min(hmax,max(hfloor,h*grow))
8849 call trace_rk45_stats_note_attempt(.true.,.false.,h)
8854 grow=trace_rk45_safety*(tol/max(err,smalldouble))**0.25d0
8855 grow=max(trace_rk45_min_shrink,min(one,grow))
8856 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
8857 trace_rk45_reject_error)
8858 h=max(hfloor,h*grow)
8862 end subroutine trace_summary_rk45_spherical_step
8864 subroutine trace_summary_rk2_step(xnow,igrid,ds,forward,threshold, &
8865 xnext,ds_actual,status,sph_cache)
8866 double precision,
intent(in) :: xnow(
ndim),ds,threshold
8867 integer,
intent(in) :: igrid
8868 logical,
intent(in) :: forward
8869 double precision,
intent(out) :: xnext(
ndim),ds_actual
8870 integer,
intent(out) :: status
8871 type(trace_sph_interp_ctx),
intent(inout),
optional :: sph_cache
8874 double precision :: ds_step
8875 double precision :: dxb^
d
8876 type(trace_sph_interp_ctx) :: ctx_now,ctx_stage
8878 integer :: igrid_stage
8879 integer :: ctx_status
8881 character(len=std_len) :: field_type
8890 if (geo_coordinate==geo_spherical)
then
8891 if (
present(sph_cache))
then
8892 call trace_spherical_interp_ctx_build_cached(xnow,igrid,sph_cache, &
8895 call trace_spherical_interp_ctx_build(xnow,igrid,ctx_now,ctx_status)
8901 ds_step=trace_spherical_effective_step_ctx(ds,ctx_now)
8902 call get_k_spherical_ctx(ctx_now,k1,field_type,threshold,field_ok)
8904 ds_step=trace_effective_step(xnow,ds,igrid,dxb^
d)
8905 call get_k(xnow,igrid,k1,ixi^
l,dxb^
d,field_type,threshold,field_ok)
8907 if (.not.field_ok)
then
8913 xstage=xnow+ds_step*k1
8915 xstage=xnow-ds_step*k1
8917 xstage_sample=xstage
8918 call trace_clamp_sample_position(xstage_sample)
8919 call trace_locate_point_with_hint(xstage_sample,igrid,igrid_stage,status)
8922 if (geo_coordinate==geo_spherical)
then
8923 if (
present(sph_cache))
then
8924 call trace_spherical_interp_ctx_build_cached(xstage_sample, &
8925 igrid_stage,sph_cache,ctx_stage,ctx_status)
8927 call trace_spherical_interp_ctx_build(xstage_sample,igrid_stage, &
8928 ctx_stage,ctx_status)
8934 call get_k_spherical_ctx(ctx_stage,k2,field_type,threshold,field_ok)
8936 call get_k(xstage_sample,igrid_stage,k2,ixi^
l,dxb^
d,field_type, &
8939 if (.not.field_ok)
then
8945 xnext=xnow+ds_step*(half*k1+half*k2)
8947 xnext=xnow-ds_step*(half*k1+half*k2)
8949 if (geo_coordinate==geo_spherical)
then
8950 ds_actual=abs(ds_step)
8952 ds_actual=dsqrt(sum((xnext-xnow)**2))
8954 end subroutine trace_summary_rk2_step
8956 double precision function trace_effective_step(x,ds,igrid,dxb^D) &
8958 double precision,
intent(in) :: x(
ndim),ds
8959 integer,
intent(in) :: igrid
8960 double precision,
intent(in) :: dxb^
d
8962 double precision :: r,sin_theta,cell_scale,dxloc(
ndim),step_cap,hcell
8963 type(trace_sph_interp_ctx) :: ctx
8967 if (trace_cartesian_like_geometry())
then
8968 if (trace_step_control_mode==trace_step_control_cell_fraction)
then
8970 call trace_cartesian_local_cell_size(x,igrid,hcell,status)
8972 ds_eff=dsign(min(step_cap,trace_step_fraction*hcell),ds)
8973 if (trace_step_min>zero)
then
8974 ds_eff=dsign(max(abs(ds_eff),min(trace_step_min,step_cap)),ds)
8976 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_step_limit(step_cap, &
8977 trace_step_fraction*hcell,abs(ds_eff))
8982 if (geo_coordinate/=geo_spherical)
return
8985 call trace_spherical_interp_ctx_build(x,igrid,ctx,status)
8987 ds_eff=trace_spherical_effective_step_ctx(ds,ctx)
8992 call trace_spherical_local_cell_widths(x,igrid,dxloc,status)
8994 r=max(abs(x(1)),smalldouble)
8995 sin_theta=abs(dsin(x(2)))
8996 cell_scale=min(abs(dxloc(1)),r*abs(dxloc(2)))
8997 cell_scale=min(cell_scale,r*max(sin_theta,smalldouble)*abs(dxloc(3)))
8998 if (cell_scale>zero)
then
8999 select case (trace_step_control_mode)
9000 case (trace_step_control_cell_fraction)
9001 ds_eff=min(step_cap,trace_step_fraction*cell_scale)
9002 if (trace_step_min>zero) ds_eff=max(ds_eff,min(trace_step_min,step_cap))
9004 ds_eff=min(step_cap,cell_scale)
9008 end function trace_effective_step
9010 logical function trace_spherical_metric_ok(x)
result(is_ok)
9011 double precision,
intent(in) :: x(
ndim)
9013 double precision :: metric_tol
9018 metric_tol=100.d0*epsilon(one)
9019 is_ok=x(1)>metric_tol .and. abs(dsin(x(2)))>metric_tol
9021 end function trace_spherical_metric_ok
9023 double precision function trace_segment_length(xa,xb,ds_full,alpha) &
9025 double precision,
intent(in) :: xa(
ndim),xb(
ndim),ds_full
9026 double precision,
intent(in),
optional :: alpha
9028 if (geo_coordinate==geo_spherical)
then
9029 if (
present(alpha))
then
9030 length=max(zero,min(one,alpha))*abs(ds_full)
9035 length=dsqrt(sum((xb-xa)**2))
9037 end function trace_segment_length
9041 integer,
intent(in) :: nseed,max_steps
9042 double precision,
intent(in) :: seeds(nseed,
ndim),dl
9044 double precision,
intent(in),
optional :: b_min
9046 double precision :: field_min
9048 field_min=smalldouble
9049 if (
present(b_min)) field_min=max(b_min,zero)
9050 call trace_summary_multi(seeds,nseed,dl,max_steps,results,field_min)
9055 integer,
intent(in) :: nseed,max_steps
9056 double precision,
intent(in) :: seeds(nseed,
ndim),dl
9058 double precision,
intent(in),
optional :: b_min
9060 double precision :: field_min
9062 field_min=smalldouble
9063 if (
present(b_min)) field_min=max(b_min,zero)
9064 call trace_summary_twist_multi(seeds,nseed,dl,max_steps,results,field_min)
9068 b_min,source_normal)
9070 integer,
intent(in) :: nseed,max_steps
9071 double precision,
intent(in) :: seeds(nseed,
ndim),dl
9073 double precision,
intent(in),
optional :: b_min
9074 double precision,
intent(in),
optional :: source_normal(3)
9076 double precision :: field_min,normal(3)
9077 logical :: have_normal
9079 field_min=smalldouble
9080 if (
present(b_min)) field_min=max(b_min,zero)
9082 have_normal=
present(source_normal)
9083 if (have_normal) normal=source_normal
9084 call trace_summary_mapping_multi(seeds,nseed,dl,max_steps,results, &
9085 field_min,have_normal,normal)
9089 need_twist,need_mapping,b_min,source_normal)
9091 integer,
intent(in) :: nseed,max_steps
9092 double precision,
intent(in) :: seeds(nseed,
ndim),dl
9094 logical,
intent(in),
optional :: need_twist,need_mapping
9095 double precision,
intent(in),
optional :: b_min
9096 double precision,
intent(in),
optional :: source_normal(3)
9098 double precision :: field_min,normal(3)
9099 logical :: do_twist,do_mapping,have_normal
9101 field_min=smalldouble
9102 if (
present(b_min)) field_min=max(b_min,zero)
9105 if (
present(need_twist)) do_twist=need_twist
9106 if (
present(need_mapping)) do_mapping=need_mapping
9108 have_normal=
present(source_normal)
9109 if (have_normal) normal=source_normal
9111 call trace_summary_topology_multi(seeds,nseed,dl,max_steps,results, &
9112 field_min,do_twist,do_mapping,have_normal,normal)
9118 integer,
intent(in) :: nseed,max_steps
9119 double precision,
intent(in) :: seeds(nseed,
ndim),dl
9121 double precision,
intent(in),
optional :: b_min
9124 type(trace_tangent_state),
allocatable :: states(:)
9125 double precision :: field_min
9126 double precision :: seed_local(
ndim),zero_vec(
ndim)
9127 integer :: common_status,iseed,idim,igrid,iforward,ibackward
9128 integer :: seed_status
9131 if (nseed<=0)
return
9133 field_min=smalldouble
9134 if (
present(b_min)) field_min=max(b_min,zero)
9136 do_twist=
present(twist_results)
9141 else if (
ndim/=3 .or. .not.trace_cartesian_like_geometry())
then
9143 else if (dl<=zero .or. max_steps<=0)
then
9149 seed_local(idim)=seeds(iseed,idim)
9151 call trace_init_qperp_result(seed_local,results(iseed))
9152 results(iseed)%status=common_status
9153 if (do_twist)
call trace_summary_init_twist_result(seed_local, &
9154 twist_results(iseed),common_status)
9159 allocate(states(2*nseed))
9162 seed_local(idim)=seeds(iseed,idim)
9164 call trace_qperp_prepare_seed_result(seed_local,field_min, &
9165 results(iseed),igrid,seed_status)
9169 call trace_tangent_state_init(seed_local,results(iseed)%u0, &
9170 results(iseed)%v0,igrid,iseed,1,states(iforward), &
9171 accumulate_twist=do_twist)
9172 call trace_tangent_state_init(seed_local,results(iseed)%u0, &
9173 results(iseed)%v0,igrid,iseed,-1,states(ibackward), &
9174 accumulate_twist=do_twist)
9175 if (trace_integrator_mode==trace_integrator_rk45_cartesian .or. &
9176 trace_integrator_mode==trace_integrator_rk45_spherical)
then
9177 call trace_rk45_stats_note_direction()
9178 call trace_rk45_stats_note_direction()
9179 else if (trace_integrator_mode==trace_integrator_rk2)
then
9180 call trace_rk2_stats_note_direction()
9181 call trace_rk2_stats_note_direction()
9184 call trace_tangent_state_init(seed_local,zero_vec,zero_vec,igrid, &
9185 iseed,1,states(iforward),accumulate_twist=do_twist)
9186 call trace_tangent_state_init(seed_local,zero_vec,zero_vec,igrid, &
9187 iseed,-1,states(ibackward),accumulate_twist=do_twist)
9188 states(iforward)%active=.false.
9189 states(ibackward)%active=.false.
9190 states(iforward)%status=seed_status
9191 states(ibackward)%status=seed_status
9195 select case (trace_integrator_mode)
9196 case (trace_integrator_rk45_cartesian)
9197 call trace_tangent_trace_states_grouped(states,2*nseed,dl,max_steps, &
9198 field_min,trace_mode=trace_tangent_group_rk45_cartesian)
9199 case (trace_integrator_rk45_spherical)
9200 call trace_tangent_trace_states_grouped_rk45_spherical(states, &
9201 2*nseed,dl,max_steps,field_min)
9203 call trace_tangent_trace_states_grouped(states,2*nseed,dl,max_steps, &
9211 call trace_qperp_finalize_from_states(states(iforward), &
9212 states(ibackward),results(iseed),field_min)
9214 if (do_twist)
call trace_tangent_fill_twist_result(seeds(iseed,:), &
9215 states(iforward),states(ibackward),twist_results(iseed))
9221 max_steps,results,b_min,twist_results)
9226 integer,
intent(in) :: nseed,max_steps
9227 double precision,
intent(in) :: seeds(nseed,
ndim),dl
9229 double precision,
intent(in),
optional :: b_min
9232 type(trace_tangent_state),
allocatable :: states(:)
9233 double precision :: field_min
9234 double precision :: seed_local(
ndim),zero_vec(
ndim)
9235 integer :: common_status,iseed,idim,igrid,iforward,ibackward
9236 integer :: seed_status
9239 if (nseed<=0)
return
9241 field_min=smalldouble
9242 if (
present(b_min)) field_min=max(b_min,zero)
9244 do_twist=
present(twist_results)
9249 else if (
ndim/=3 .or. .not.trace_cartesian_like_geometry())
then
9251 else if (dl<=zero .or. max_steps<=0)
then
9257 seed_local(idim)=seeds(iseed,idim)
9259 call trace_init_qperp_result(seed_local,results(iseed))
9260 results(iseed)%status=common_status
9261 results(iseed)%status_q0=common_status
9262 if (do_twist)
call trace_summary_init_twist_result(seed_local, &
9263 twist_results(iseed),common_status)
9268 allocate(states(2*nseed))
9271 seed_local(idim)=seeds(iseed,idim)
9273 call trace_qperp_prepare_seed_result(seed_local,field_min, &
9274 results(iseed),igrid,seed_status)
9278 call trace_tangent_state_init(seed_local,results(iseed)%u0, &
9279 results(iseed)%v0,igrid,iseed,1,states(iforward), &
9280 accumulate_twist=do_twist)
9281 call trace_tangent_state_init(seed_local,results(iseed)%u0, &
9282 results(iseed)%v0,igrid,iseed,-1,states(ibackward), &
9283 accumulate_twist=do_twist)
9284 call trace_rk45_stats_note_direction()
9285 call trace_rk45_stats_note_direction()
9287 call trace_tangent_state_init(seed_local,zero_vec,zero_vec,igrid, &
9288 iseed,1,states(iforward),accumulate_twist=do_twist)
9289 call trace_tangent_state_init(seed_local,zero_vec,zero_vec,igrid, &
9290 iseed,-1,states(ibackward),accumulate_twist=do_twist)
9291 states(iforward)%active=.false.
9292 states(ibackward)%active=.false.
9293 states(iforward)%status=seed_status
9294 states(ibackward)%status=seed_status
9295 results(iseed)%status_q0=seed_status
9299 call trace_tangent_trace_states_grouped(states,2*nseed,dl,max_steps, &
9300 field_min,trace_mode=trace_tangent_group_rk45_cartesian)
9306 call trace_q0_finalize_from_states(states(iforward), &
9307 states(ibackward),results(iseed),field_min)
9309 if (do_twist)
call trace_tangent_fill_twist_result(seeds(iseed,:), &
9310 states(iforward),states(ibackward),twist_results(iseed))
9316 max_steps,results,b_min)
9317 integer,
intent(in) :: nseed,max_steps
9318 double precision,
intent(in) :: seeds(nseed,
ndim),dl
9320 double precision,
intent(in),
optional :: b_min
9322 if (
present(b_min))
then
9332 results,b_min,twist_results)
9334 integer,
intent(in) :: nseed,max_steps
9335 double precision,
intent(in) :: seeds(nseed,
ndim),dl
9337 double precision,
intent(in),
optional :: b_min
9340 type(trace_tangent_state),
allocatable :: states(:)
9341 double precision :: field_min
9342 double precision :: seed_local(
ndim),zero_vec(
ndim)
9343 integer :: common_status,iseed,idim,igrid,iforward,ibackward
9344 integer :: seed_status
9347 if (nseed<=0)
return
9348 if (trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical) &
9349 call trace_spherical_profile_add_count(trace_profile_q_tangent_systems, &
9350 int(2*nseed,kind=8))
9352 field_min=smalldouble
9353 if (
present(b_min)) field_min=max(b_min,zero)
9355 do_twist=
present(twist_results)
9360 else if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
then
9362 else if (dl<=zero .or. max_steps<=0)
then
9368 seed_local(idim)=seeds(iseed,idim)
9370 call trace_init_qperp_result(seed_local,results(iseed))
9371 results(iseed)%status=common_status
9372 results(iseed)%status_q0=common_status
9373 if (do_twist)
call trace_summary_init_twist_result(seed_local, &
9374 twist_results(iseed),common_status)
9379 allocate(states(2*nseed))
9382 seed_local(idim)=seeds(iseed,idim)
9384 call trace_spherical_rmin_q_prepare_seed_result(seed_local,field_min, &
9385 results(iseed),igrid,seed_status)
9389 call trace_tangent_state_init(seed_local,results(iseed)%u0, &
9390 results(iseed)%v0,igrid,iseed,1,states(iforward), &
9391 accumulate_twist=do_twist)
9392 call trace_tangent_state_init(seed_local,results(iseed)%u0, &
9393 results(iseed)%v0,igrid,iseed,-1,states(ibackward), &
9394 accumulate_twist=do_twist)
9395 if (trace_integrator_mode==trace_integrator_rk45_spherical)
then
9396 call trace_rk45_stats_note_direction()
9397 call trace_rk45_stats_note_direction()
9398 else if (trace_integrator_mode==trace_integrator_rk2)
then
9399 call trace_rk2_stats_note_direction()
9400 call trace_rk2_stats_note_direction()
9403 call trace_tangent_state_init(seed_local,zero_vec,zero_vec,igrid, &
9404 iseed,1,states(iforward),accumulate_twist=do_twist)
9405 call trace_tangent_state_init(seed_local,zero_vec,zero_vec,igrid, &
9406 iseed,-1,states(ibackward),accumulate_twist=do_twist)
9407 states(iforward)%active=.false.
9408 states(ibackward)%active=.false.
9409 states(iforward)%status=seed_status
9410 states(ibackward)%status=seed_status
9414 if (trace_integrator_mode==trace_integrator_rk45_spherical)
then
9415 call trace_tangent_trace_states_grouped_rk45_spherical(states, &
9416 2*nseed,dl,max_steps,field_min)
9418 call trace_tangent_trace_states_grouped(states,2*nseed,dl,max_steps, &
9426 call trace_spherical_rmin_q_finalize_from_states(states(iforward), &
9427 states(ibackward),results(iseed),field_min)
9429 if (do_twist)
call trace_tangent_fill_twist_result(seeds(iseed,:), &
9430 states(iforward),states(ibackward),twist_results(iseed))
9436 max_steps,results,b_min,twist_results)
9439 integer,
intent(in) :: nseed,max_steps
9440 double precision,
intent(in) :: seeds(nseed,
ndim),dl
9442 double precision,
intent(in),
optional :: b_min
9445 type(trace_tangent_state),
allocatable :: states(:)
9446 double precision :: field_min
9447 double precision :: seed_local(
ndim),zero_vec(
ndim)
9448 integer :: common_status,iseed,idim,igrid,iforward,ibackward
9449 integer :: seed_status
9450 logical :: do_twist,is_spherical
9452 if (nseed<=0)
return
9454 field_min=smalldouble
9455 if (
present(b_min)) field_min=max(b_min,zero)
9457 do_twist=
present(twist_results)
9458 is_spherical=(geo_coordinate==geo_spherical)
9463 else if (
ndim/=3)
then
9465 else if (geo_coordinate==geo_cartesian .and. .not.
slab_uniform)
then
9467 else if (geo_coordinate/=geo_cartesian .and. &
9468 geo_coordinate/=geo_spherical)
then
9470 else if (dl<=zero .or. max_steps<=0)
then
9476 seed_local(idim)=seeds(iseed,idim)
9478 call trace_init_qperp_result(seed_local,results(iseed))
9479 results(iseed)%status=common_status
9480 results(iseed)%status_q0=common_status
9481 if (do_twist)
call trace_summary_init_twist_result(seed_local, &
9482 twist_results(iseed),common_status)
9487 allocate(states(2*nseed))
9490 seed_local(idim)=seeds(iseed,idim)
9492 if (is_spherical)
then
9493 call trace_spherical_rmin_q_prepare_seed_result(seed_local,field_min, &
9494 results(iseed),igrid,seed_status)
9496 call trace_qperp_prepare_seed_result(seed_local,field_min, &
9497 results(iseed),igrid,seed_status)
9502 call trace_tangent_state_init(seed_local,results(iseed)%u0, &
9503 results(iseed)%v0,igrid,iseed,1,states(iforward), &
9504 accumulate_twist=do_twist)
9505 call trace_tangent_state_init(seed_local,results(iseed)%u0, &
9506 results(iseed)%v0,igrid,iseed,-1,states(ibackward), &
9507 accumulate_twist=do_twist)
9508 if (trace_integrator_mode==trace_integrator_rk45_spherical)
then
9509 call trace_rk45_stats_note_direction()
9510 call trace_rk45_stats_note_direction()
9511 else if (trace_integrator_mode==trace_integrator_rk2)
then
9512 call trace_rk2_stats_note_direction()
9513 call trace_rk2_stats_note_direction()
9516 call trace_tangent_state_init(seed_local,zero_vec,zero_vec,igrid, &
9517 iseed,1,states(iforward),accumulate_twist=do_twist)
9518 call trace_tangent_state_init(seed_local,zero_vec,zero_vec,igrid, &
9519 iseed,-1,states(ibackward),accumulate_twist=do_twist)
9520 states(iforward)%active=.false.
9521 states(ibackward)%active=.false.
9522 states(iforward)%status=seed_status
9523 states(ibackward)%status=seed_status
9524 results(iseed)%status_q0=seed_status
9528 call trace_tangent_trace_states_grouped(states,2*nseed,dl,max_steps, &
9529 field_min,trace_mode=trace_tangent_group_rk2_short_boundary)
9535 if (is_spherical)
then
9536 call trace_spherical_rmin_q_finalize_from_states(states(iforward), &
9537 states(ibackward),results(iseed),field_min)
9539 call trace_q0_finalize_from_states(states(iforward), &
9540 states(ibackward),results(iseed),field_min)
9543 if (do_twist)
call trace_tangent_fill_twist_result(seeds(iseed,:), &
9544 states(iforward),states(ibackward),twist_results(iseed))
9550 results,b_min,twist_results)
9552 integer,
intent(in) :: nseed,max_steps
9553 double precision,
intent(in) :: seeds(nseed,
ndim),dl
9555 double precision,
intent(in),
optional :: b_min
9558 type(trace_tangent_state),
allocatable :: states(:)
9559 double precision :: field_min
9560 double precision :: seed_local(
ndim),zero_vec(
ndim)
9561 integer :: common_status,iseed,idim,igrid,iforward,ibackward
9562 integer :: seed_status
9563 integer :: cache_status
9566 if (nseed<=0)
return
9567 if (trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical) &
9568 call trace_spherical_profile_add_count( &
9569 trace_profile_qperp_tangent_systems,int(2*nseed,kind=8))
9571 field_min=smalldouble
9572 if (
present(b_min)) field_min=max(b_min,zero)
9574 do_twist=
present(twist_results)
9579 else if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
then
9581 else if (dl<=zero .or. max_steps<=0)
then
9587 seed_local(idim)=seeds(iseed,idim)
9589 call trace_init_qperp_result(seed_local,results(iseed))
9590 results(iseed)%status=common_status
9591 results(iseed)%status_qperp0=common_status
9592 if (do_twist)
call trace_summary_init_twist_result(seed_local, &
9593 twist_results(iseed),common_status)
9603 seed_local(idim)=seeds(iseed,idim)
9605 call trace_init_qperp_result(seed_local,results(iseed))
9606 results(iseed)%status=cache_status
9607 results(iseed)%status_qperp0=cache_status
9608 call trace_summary_init_twist_result(seed_local, &
9609 twist_results(iseed),cache_status)
9615 allocate(states(2*nseed))
9618 seed_local(idim)=seeds(iseed,idim)
9620 call trace_spherical_qperp_prepare_seed_result(seed_local,field_min, &
9621 results(iseed),igrid,seed_status)
9625 call trace_tangent_state_init(seed_local,results(iseed)%u0, &
9626 results(iseed)%v0,igrid,iseed,1,states(iforward), &
9627 accumulate_twist=do_twist)
9628 call trace_tangent_state_init(seed_local,results(iseed)%u0, &
9629 results(iseed)%v0,igrid,iseed,-1,states(ibackward), &
9630 accumulate_twist=do_twist)
9631 if (trace_integrator_mode==trace_integrator_rk45_spherical)
then
9632 call trace_rk45_stats_note_direction()
9633 call trace_rk45_stats_note_direction()
9634 else if (trace_integrator_mode==trace_integrator_rk2)
then
9635 call trace_rk2_stats_note_direction()
9636 call trace_rk2_stats_note_direction()
9639 call trace_tangent_state_init(seed_local,zero_vec,zero_vec,igrid, &
9640 iseed,1,states(iforward),accumulate_twist=do_twist)
9641 call trace_tangent_state_init(seed_local,zero_vec,zero_vec,igrid, &
9642 iseed,-1,states(ibackward),accumulate_twist=do_twist)
9643 states(iforward)%active=.false.
9644 states(ibackward)%active=.false.
9645 states(iforward)%status=seed_status
9646 states(ibackward)%status=seed_status
9650 if (trace_integrator_mode==trace_integrator_rk45_spherical)
then
9651 call trace_tangent_trace_states_grouped_rk45_spherical(states, &
9652 2*nseed,dl,max_steps,field_min)
9654 call trace_tangent_trace_states_grouped(states,2*nseed,dl,max_steps, &
9662 call trace_spherical_qperp_finalize_from_states(states(iforward), &
9663 states(ibackward),results(iseed),field_min)
9665 if (do_twist)
call trace_tangent_fill_twist_result(seeds(iseed,:), &
9666 states(iforward),states(ibackward),twist_results(iseed))
9673 max_steps,q_results,qperp_results,b_min,twist_results)
9675 integer,
intent(in) :: nseed,max_steps
9676 double precision,
intent(in) :: seeds(nseed,
ndim),dl
9679 double precision,
intent(in),
optional :: b_min
9682 type(trace_tangent_state),
allocatable :: states(:)
9683 type(trace_tangent_state) :: qperp_forward_state,qperp_backward_state
9684 double precision :: field_min
9685 double precision :: seed_local(
ndim),zero_vec(
ndim)
9686 integer :: common_status,iseed,idim,igrid_q,igrid_qperp
9687 integer :: iforward,ibackward,seed_status_q,seed_status_qperp
9690 if (nseed<=0)
return
9691 if (trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical)
then
9692 call trace_spherical_profile_add_count(trace_profile_q_tangent_systems, &
9693 int(2*nseed,kind=8))
9694 call trace_spherical_profile_add_count( &
9695 trace_profile_qperp_tangent_systems,int(2*nseed,kind=8))
9696 call trace_spherical_profile_add_count( &
9697 trace_profile_combined_tangent_systems,int(2*nseed,kind=8))
9700 field_min=smalldouble
9701 if (
present(b_min)) field_min=max(b_min,zero)
9703 do_twist=
present(twist_results)
9708 else if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
then
9710 else if (dl<=zero .or. max_steps<=0)
then
9716 seed_local(idim)=seeds(iseed,idim)
9718 call trace_init_qperp_result(seed_local,q_results(iseed))
9719 q_results(iseed)%status=common_status
9720 q_results(iseed)%status_q0=common_status
9721 call trace_init_qperp_result(seed_local,qperp_results(iseed))
9722 qperp_results(iseed)%status=common_status
9723 qperp_results(iseed)%status_qperp0=common_status
9724 if (do_twist)
call trace_summary_init_twist_result(seed_local, &
9725 twist_results(iseed),common_status)
9730 allocate(states(2*nseed))
9733 seed_local(idim)=seeds(iseed,idim)
9735 call trace_spherical_rmin_q_prepare_seed_result(seed_local,field_min, &
9736 q_results(iseed),igrid_q,seed_status_q)
9737 call trace_spherical_qperp_prepare_seed_result(seed_local,field_min, &
9738 qperp_results(iseed),igrid_qperp,seed_status_qperp)
9744 call trace_tangent_state_init(seed_local,q_results(iseed)%u0, &
9745 q_results(iseed)%v0,igrid_q,iseed,1,states(iforward), &
9746 accumulate_twist=do_twist)
9747 call trace_tangent_state_init(seed_local,q_results(iseed)%u0, &
9748 q_results(iseed)%v0,igrid_q,iseed,-1,states(ibackward), &
9749 accumulate_twist=do_twist)
9750 states(iforward)%has_extra=.true.
9751 states(ibackward)%has_extra=.true.
9752 states(iforward)%p=qperp_results(iseed)%u0
9753 states(iforward)%q=qperp_results(iseed)%v0
9754 states(ibackward)%p=qperp_results(iseed)%u0
9755 states(ibackward)%q=qperp_results(iseed)%v0
9756 if (trace_integrator_mode==trace_integrator_rk45_spherical)
then
9757 call trace_rk45_stats_note_direction()
9758 call trace_rk45_stats_note_direction()
9759 else if (trace_integrator_mode==trace_integrator_rk2)
then
9760 call trace_rk2_stats_note_direction()
9761 call trace_rk2_stats_note_direction()
9764 call trace_tangent_state_init(seed_local,zero_vec,zero_vec,igrid_q, &
9765 iseed,1,states(iforward),accumulate_twist=do_twist)
9766 call trace_tangent_state_init(seed_local,zero_vec,zero_vec,igrid_q, &
9767 iseed,-1,states(ibackward),accumulate_twist=do_twist)
9768 states(iforward)%active=.false.
9769 states(ibackward)%active=.false.
9771 states(iforward)%status=seed_status_q
9772 states(ibackward)%status=seed_status_q
9774 states(iforward)%status=seed_status_qperp
9775 states(ibackward)%status=seed_status_qperp
9780 if (trace_integrator_mode==trace_integrator_rk45_spherical)
then
9781 call trace_tangent_trace_states_grouped_rk45_spherical(states, &
9782 2*nseed,dl,max_steps,field_min)
9784 call trace_tangent_trace_states_grouped(states,2*nseed,dl,max_steps, &
9792 call trace_spherical_rmin_q_finalize_from_states(states(iforward), &
9793 states(ibackward),q_results(iseed),field_min)
9796 qperp_forward_state=states(iforward)
9797 qperp_backward_state=states(ibackward)
9798 qperp_forward_state%u_perp=states(iforward)%p_perp
9799 qperp_forward_state%v_perp=states(iforward)%q_perp
9800 qperp_backward_state%u_perp=states(ibackward)%p_perp
9801 qperp_backward_state%v_perp=states(ibackward)%q_perp
9802 call trace_spherical_qperp_finalize_from_states(qperp_forward_state, &
9803 qperp_backward_state,qperp_results(iseed),field_min)
9805 if (do_twist)
call trace_tangent_fill_twist_result(seeds(iseed,:), &
9806 states(iforward),states(ibackward),twist_results(iseed))
9811 subroutine trace_field_multi(xfm,wPm,wLm,dL,numL,numP,nwP,nwL,forwardm,ftype,tcondi)
9839 integer,
intent(in) :: numL,numP,nwP,nwL
9840 double precision,
intent(inout) :: xfm(numL,numP,ndim),wPm(numL,numP,nwP),wLm(numL,1+nwL)
9841 double precision,
intent(in) :: dL
9842 logical,
intent(in) :: forwardm(numL)
9843 character(len=std_len),
intent(in) :: ftype,tcondi
9845 double precision :: x3d(3),statusF(4+ndim),statusL(numL,4+ndim+nwL),statusS(numL,4+ndim+nwL)
9846 double precision :: xf(numP,ndim),wP(numP,nwP),wL(1+nwL)
9847 double precision,
allocatable :: data_send(:,:,:),data_recv(:,:,:)
9848 integer :: indomain,ipe_now,igrid_now,igrid,j,iL
9849 integer :: ipoint_in,ipoint_out,numSend,nRT,nRTmax
9850 integer :: ipointm(numL),igridm(numL)
9851 logical :: continueL(numL),myL(numL)
9852 logical :: stopT,forward
9854 if (tcondi/=
'TRAC')
then
9860 xfm(1:numl,2:nump,:)=zero
9870 {
if (xfm(il,1,^db)>=xprobmin^db .and. xfm(il,1,^db)<xprobmax^db) indomain=indomain+1\}
9871 if (indomain==ndim)
then
9872 if (tcondi/=
'TRAC') wlm(il,1)=1
9873 continuel(il)=.true.
9882 igridm(il)=igrid_now
9883 if (
mype==ipe_now)
then
9889 continuel(il)=.false.
9894 do while(stopt .eqv. .false.)
9898 if (myl(il) .and. continuel(il))
then
9900 ipoint_in=ipointm(il)
9901 xf(ipoint_in,:)=xfm(il,ipoint_in,:)
9903 forward=forwardm(il)
9905 call find_points_in_pe(igrid,ipoint_in,xf,wp,wl,dl,nump,nwp,nwl,forward,ftype,tcondi,statusf)
9906 ipoint_out=int(statusf(1))
9907 xfm(il,ipoint_in:ipoint_out-1,:)=xf(ipoint_in:ipoint_out-1,:)
9908 wpm(il,ipoint_in:ipoint_out-1,:)=wp(ipoint_in:ipoint_out-1,:)
9918 statuss(il,1:4+ndim)=statusf(1:4+ndim)
9919 statuss(il,4+ndim+1:4+ndim+nwl)=wl(2:1+nwl)
9920 if (tcondi==
'TRAC') wlm(il,1)=ipoint_out-1
9925 numsend=numl*(4+ndim+nwl)
9926 call mpi_allreduce(statuss,statusl,numsend,mpi_double_precision,&
9933 if (continuel(il))
then
9934 ipointm(il)=int(statusl(il,1))
9935 if (
mype==int(statusl(il,2))) myl(il)=.true.
9936 igridm(il)=int(statusl(il,3))
9940 continuel(il)=.false.
9942 if (myl(il)) xfm(il,ipointm(il),1:ndim)=statusl(il,4+1:4+ndim)
9943 if (tcondi/=
'TRAC')
then
9945 wlm(il,1)=ipointm(il)
9947 wlm(il,1)=ipointm(il)-1
9950 wlm(il,2:1+nwl)=statusl(il,4+ndim+1:4+ndim+nwl)
9956 if (tcondi/=
'TRAC')
then
9959 if (nrtmax<int(wlm(il,1))) nrtmax=int(wlm(il,1))
9961 numsend=numl*nrtmax*(ndim+nwp)
9963 allocate(data_send(numl,nrtmax,ndim+nwp),data_recv(numl,nrtmax,ndim+nwp))
9964 data_send(:,:,:)=zero
9967 data_send(il,1:nrt,1:ndim)=xfm(il,1:nrt,1:ndim)
9968 if (nwp>0) data_send(il,1:nrt,1+ndim:ndim+nwp)=wpm(il,1:nrt,1:nwp)
9970 call mpi_allreduce(data_send,data_recv,numsend,mpi_double_precision,&
9974 xfm(il,1:nrt,1:ndim)=data_recv(il,1:nrt,1:ndim)
9975 if (nwp>0) wpm(il,1:nrt,1:nwp)=data_recv(il,1:nrt,1+ndim:ndim+nwp)
9977 deallocate(data_send,data_recv)
10010 integer,
intent(in) :: numP,nwP,nwL
10011 double precision,
intent(inout) :: xf(numP,ndim),wP(numP,nwP),wL(1+nwL)
10012 double precision,
intent(in) :: dL
10013 logical,
intent(in) :: forward
10014 character(len=std_len),
intent(in) :: ftype,tcondi
10016 double precision :: x3d(3),statusF(4+ndim),status_bcast(4+ndim+nwL)
10017 double precision,
allocatable :: data_send(:,:),data_recv(:,:)
10018 integer :: indomain,ipoint_in,ipe_now,igrid_now,igrid,j
10019 integer :: ipoint_out,ipe_next,igrid_next,numRT
10030 {
if (xf(1,^db)>=xprobmin^db .and. xf(1,^db)<xprobmax^db) indomain=indomain+1\}
10031 if (indomain==ndim)
then
10042 if (
mype/=ipe_now) xf(1,:)=zero
10045 call mpistop(
'Field tracing error: given point is not in simulation box!')
10051 do while(stopt .eqv. .false.)
10053 if (
mype==ipe_now)
then
10056 call find_points_in_pe(igrid,ipoint_in,xf,wp,wl,dl,nump,nwp,nwl,forward,ftype,tcondi,statusf)
10057 status_bcast(1:4+ndim)=statusf(1:4+ndim)
10058 status_bcast(4+ndim+1:4+ndim+nwl)=wl(2:1+nwl)
10061 call mpi_bcast(status_bcast,4+ndim+nwl,mpi_double_precision,ipe_now,
icomm,
ierrmpi)
10062 statusf(1:4+ndim)=status_bcast(1:4+ndim)
10063 wl(2:1+nwl)=status_bcast(4+ndim+1:4+ndim+nwl)
10066 ipoint_out=int(statusf(1))
10067 ipe_next=int(statusf(2))
10068 igrid_next=int(statusf(3))
10077 if (
mype==ipe_next)
then
10079 xf(ipoint_out,j)=statusf(4+j)
10082 xf(ipoint_out,:)=zero
10087 igrid_now=igrid_next
10088 ipoint_in=ipoint_out
10091 if (tcondi/=
'TRAC')
then
10093 allocate(data_send(numrt,ndim+nwp),data_recv(numrt,ndim+nwp))
10094 data_send(:,:)=zero
10095 data_recv(:,:)=zero
10096 data_send(1:numrt,1:ndim)=xf(1:numrt,1:ndim)
10097 if (nwp>0) data_send(1:numrt,1+ndim:ndim+nwp)=wp(1:numrt,1:nwp)
10098 call mpi_allreduce(data_send,data_recv,numrt*(ndim+nwp),mpi_double_precision,&
10100 xf(1:numrt,1:ndim)=data_recv(1:numrt,1:ndim)
10101 if (nwp>0) wp(1:numrt,1:nwp)=data_recv(1:numrt,1+ndim:ndim+nwp)
10102 deallocate(data_send,data_recv)
10107 subroutine find_points_in_pe(igrid,ipoint_in,xf,wP,wL,dL,numP,nwP,nwL,forward,ftype,tcondi,statusF)
10109 integer,
intent(inout) :: igrid
10110 integer,
intent(in) :: ipoint_in,numP,nwP,nwL
10111 double precision,
intent(inout) :: xf(numP,ndim),wP(numP,nwP),wL(1+nwL)
10112 double precision,
intent(in) :: dL
10113 logical,
intent(in) :: forward
10114 character(len=std_len),
intent(in) :: ftype,tcondi
10115 double precision,
intent(inout) :: statusF(4+ndim)
10117 double precision :: xfout(ndim)
10118 integer :: ipe_next,igrid_next,ip_in,ip_out,j,indomain,trace_status
10119 logical :: newpe,stopT
10127 do while(newpe .eqv. .false.)
10130 dl,forward,ftype,tcondi,trace_status)
10139 {
if (xf(ip_out,^db)>=xprobmin^db .and. xf(ip_out,^db)<=xprobmax^db) indomain=indomain+1\}
10140 if (ip_out<nump .and. indomain==ndim)
then
10141 if (tcondi/=
'TRAC')
then
10144 call find_next_grid(igrid,igrid_next,ipe_next,xfout,newpe,stopt)
10154 call find_next_grid(igrid,igrid_next,ipe_next,xfout,newpe,stopt)
10161 if (ip_out>=nump)
then
10171 statusf(2)=ipe_next
10172 statusf(3)=igrid_next
10174 if (stopt) statusf(4)=trace_status
10176 statusf(4+j)=xf(ip_out,j)
10180 if (newpe .eqv. .false.) igrid=igrid_next
10191 integer,
intent(inout) :: igrid,igrid_next,ipe_next
10192 double precision,
intent(in) :: xf1(ndim)
10193 logical,
intent(inout) :: newpe,stopT
10195 double precision :: dxb^D,xb^L,xbmid^D
10196 double precision :: xbn^L
10197 integer :: idn^D,my_neighbor_type,inblock
10198 integer :: ic^D,inc^D,ipe_neighbor,igrid_neighbor
10209 {
if (xf1(^d)<=xbmin^d) idn^d=-1\}
10210 {
if (xf1(^d)>=xbmax^d) idn^d=1\}
10212 igrid_neighbor=
neighbor(1,idn^d,igrid)
10213 ipe_neighbor=
neighbor(2,idn^d,igrid)
10216 select case(my_neighbor_type)
10224 igrid_next=igrid_neighbor
10225 ipe_next=ipe_neighbor
10226 if (
mype==ipe_neighbor)
then
10234 igrid_next=igrid_neighbor
10235 ipe_next=ipe_neighbor
10236 if (
mype==ipe_neighbor)
then
10244 {xbmid^d=(xbmin^d+xbmax^d)/2.d0\}
10246 {
if (xf1(^d)<=xbmin^d) inc^d=0\}
10247 {
if (xf1(^d)>xbmin^d .and. xf1(^d)<=xbmid^d) inc^d=1\}
10248 {
if (xf1(^d)>xbmid^d .and. xf1(^d)<xbmax^d) inc^d=2\}
10249 {
if (xf1(^d)>=xbmax^d) inc^d=3\}
10252 if (
mype==ipe_next)
then
10262 dL,forward,ftype,tcondi,trace_status)
10266 integer,
intent(in) :: igrid,ip_in,numP,nwP,nwL
10267 integer,
intent(inout) :: ip_out
10268 double precision,
intent(inout) :: xf(numP,ndim),wP(numP,nwP),wL(1+nwL)
10269 double precision,
intent(in) :: dL
10270 logical,
intent(in) :: forward
10271 character(len=std_len),
intent(in) :: ftype,tcondi
10272 integer,
intent(out) :: trace_status
10274 double precision :: dxb^D,xb^L
10275 double precision :: field(ixg^T,ndir)
10276 double precision :: xs1(ndim),xs2(ndim),K1(ndim),K2(ndim)
10277 double precision :: xfpre(ndim),xfnow(ndim),xfnext(ndim)
10278 double precision :: Tpre,Tnow,Tnext,dTds,Lt,Lr,ds,T_bott,trac_delta
10279 integer :: ip,inblock,ixI^L,ixO^L,j
10280 logical :: field_ok
10290 if (tcondi/=
'TRAC')
then
10299 mainloop:
do ip=ip_in,nump-1
10303 call get_k(xs1,igrid,k1,ixi^l,dxb^d,ftype,smalldouble,field_ok)
10304 if (.not.field_ok)
then
10310 xs2(:)=xf(ip,:)+ds*k1(:)
10312 xs2(:)=xf(ip,:)-ds*k1(:)
10314 call get_k(xs2,igrid,k2,ixi^l,dxb^d,ftype,smalldouble,field_ok)
10315 if (.not.field_ok)
then
10321 xf(ip+1,:)=xf(ip,:)+ds*(0.5*k1(:)+0.5*k2(:))
10323 xf(ip+1,:)=xf(ip,:)-ds*(0.5*k1(:)+0.5*k2(:))
10328 if (tcondi/=
'TRAC')
then
10330 call usr_set_field_w(igrid,ip,xf,wp,wl,nump,nwp,nwl,dl,forward,ftype,tcondi)
10335 if (ip==ip_in)
then
10337 xfpre(:)=xf(ip,:)-ds*k1(:)
10339 xfpre(:)=xf(ip,:)+ds*k1(:)
10342 xfnext(:)=xf(ip+1,:)
10349 xfnext(:)=xf(ip+1,:)
10354 dtds=abs(tnext-tpre)/(2*ds)
10361 if (dtds>0.d0)
then
10365 if(lr>trac_delta*lt)
then
10366 if (tnow>wl(2)) wl(2)=tnow
10369 if (tnow>wl(3)) wl(3)=tnow
10375 {
if (xf(ip+1,^db)>=xbmin^db .and. xf(ip+1,^db)<xbmax^db) inblock=inblock+1\}
10376 if (tcondi==
'TRAC' .and. xf(ip+1,ndim)>
phys_trac_mask) inblock=0
10377 if (inblock/=ndim)
exit mainloop
10383 subroutine get_k(xfn,igrid,K,ixI^L,dxb^D,ftype,b_min,field_ok)
10386 integer :: ixI^L,igrid
10387 double precision :: dxb^D
10388 double precision :: xfn(ndim),K(ndim)
10389 character(len=std_len) :: ftype
10390 double precision,
intent(in),
optional :: b_min
10391 logical,
intent(out),
optional :: field_ok
10393 double precision :: dxc^D,xd^D
10394 double precision :: field(0:1^D&,ndir),Fx(ndim),factor(0:1^D&)
10395 double precision :: Ftotal,field_min
10396 double precision :: w_stencil(0:1^D&,1:nw)
10397 double precision :: x_stencil(0:1^D&,1:ndim)
10398 double precision :: vector_stencil(0:1^D&,1:ndir)
10399 logical :: valid_field
10400 integer :: ixb^D,ix^D,ixbl^D,j,status_interp
10403 if (geo_coordinate==geo_spherical)
then
10404 call trace_interp_weights_block(xfn,igrid,ixi^l,ixbl^d,xd^d,dxc^d, &
10407 if (
present(field_ok)) field_ok=.false.
10412 ^d&ixbl^d=floor((xfn(^d)-ps(igrid)%x(iximin^dd,^d))/dxb^d)+iximin^d;
10413 ^d&xd^d=(xfn(^d)-ps(igrid)%x(ixbl^dd,^d))/dxb^d;
10417 if(ftype==
'Bfield')
then
10419 if(
allocated(iw_mag))
then
10421 field(ix^d,1:ndir)=ps(igrid)%w(ixbl^d+ix^d,iw_mag(1:ndir)) &
10422 +ps(igrid)%B0(ixbl^d+ix^d,1:ndir,0)
10426 field(ix^d,1:ndir)=ps(igrid)%B0(ixbl^d+ix^d,1:ndir,0)
10431 field(ix^d,1:ndir)=ps(igrid)%w(ixbl^d+ix^d,iw_mag(1:ndir))
10434 else if (ftype==
'Vfield')
then
10439 w_stencil(ixs^s,1:nw)=ps(igrid)%w(ixbl^d:ixbl^d+1^d&,1:nw)
10440 x_stencil(ixs^s,1:ndim)=ps(igrid)%x(ixbl^d:ixbl^d+1^d&,1:ndim)
10441 call phys_get_v(w_stencil,x_stencil,ixs^l,ixs^l,vector_stencil)
10443 field(ix^d,1:ndir)=vector_stencil(ix^d,1:ndir)
10447 factor(ix^d)={abs(1-ix^d-xd^d)*}
10450 if (ftype==
'Bfield' .or. ftype==
'Vfield')
then
10454 fx(j)=fx(j)+field(ix^d,j)*factor(ix^d)
10460 call mpistop(
'Field tracing error: wrong field type!')
10465 ftotal=ftotal+(fx(j))**2
10467 ftotal=dsqrt(ftotal)
10469 field_min=smalldouble
10470 if (
present(b_min)) field_min=max(b_min,zero)
10471 valid_field=ftotal>zero .and. ftotal>=field_min
10472 if (
present(field_ok)) field_ok=valid_field
10475 if (valid_field)
then
10476 select case (geo_coordinate)
10477 case (geo_spherical)
10479 if (.not.trace_spherical_metric_ok(xfn))
then
10480 valid_field=.false.
10481 if (
present(field_ok)) field_ok=.false.
10485 k(2)=fx(2)/(xfn(1)*ftotal)
10486 k(3)=fx(3)/(xfn(1)*dsin(xfn(2))*ftotal)
10489 k(1:ndim)=fx(1:ndim)/ftotal
10493 end subroutine get_k
10498 integer,
intent(in) :: igrid,ixI^L
10499 double precision,
intent(inout) :: xloc(ndim)
10500 double precision,
intent(inout) :: Tloc
10501 double precision,
intent(in) :: dxb^D
10503 double precision :: xd^D
10504 double precision :: factor(0:1^D&),Tnear(0:1^D&)
10505 integer :: ixb^D,ix^D,ixbl^D,j,ixO^L
10507 ^d&ixbl^d=floor((xloc(^d)-ps(igrid)%x(iximin^dd,^d))/dxb^d)+iximin^d;
10508 ^d&xd^d=(xloc(^d)-ps(igrid)%x(ixbl^dd,^d))/dxb^d;
10509 ^d&ixomin^d=ixbl^d;
10510 ^d&ixomax^d=ixomin^d+1;
10513 factor(ix^d)={abs(1-ix^d-xd^d)*}
10514 tnear(ix^d)=ps(igrid)%wextra(ixbl^d+ix^d,iw_tcoff)
10520 tloc=tloc+tnear(ix^d)*factor(ix^d)
This module contains variables that describe the connectivity of the mesh and also data structures fo...
integer, dimension(:), allocatable igrids
integer, parameter neighbor_coarse
integer, dimension(:,:^d &,:), allocatable neighbor
integer, parameter neighbor_boundary
integer, dimension(:,:^d &,:), allocatable neighbor_child
integer, parameter neighbor_fine
integer, parameter neighbor_sibling
integer, dimension(:^d &,:), allocatable neighbor_type
Module with basic grid data structures.
Module with geometry-related routines (e.g., divergence, curl)
integer, parameter spherical
integer, parameter cartesian
integer, parameter cartesian_stretched
subroutine curlvector(qvec, ixil, ixol, curlvec, idirmin, idirmin0, ndir0, fourthorder)
Calculate curl of a vector qvec within ixL Options to employ standard second order CD evaluations use...
This module contains definitions of global parameters and variables and some generic functions/subrou...
type(state), pointer block
Block pointer for using one block and its previous state.
integer nstep
How many sub-steps the time integrator takes.
integer istep
Index of the sub-step in a multi-step time integrator.
double precision phys_trac_mask
integer, parameter ndim
Number of spatial dimensions for grid variables.
integer, parameter rpxmin
integer icomm
The MPI communicator.
integer mype
The rank of the current MPI task.
double precision dt
global time step
integer ixm
the mesh range of a physical block without ghost cells
integer ierrmpi
A global MPI error return code.
double precision, dimension(:), allocatable, parameter d
integer npe
The number of MPI tasks.
logical, dimension(ndim) periodb
True for dimensions with periodic boundaries.
logical b0field
split magnetic field as background B0 field
double precision, dimension(:,:), allocatable rnode
Corner coordinates.
double precision unit_temperature
Physical scaling factor for temperature.
double precision, dimension(^nd) dxlevel
store unstretched cell size of current level
integer, parameter rpxmax
logical slab_uniform
uniform Cartesian geometry or not (stretched Cartesian)
integer max_blocks
The maximum number of grid blocks in a processor.
Module with shared functionality for all the particle movers.
subroutine find_particle_ipe(x, igrid_particle, ipe_particle)
This module defines the procedures of a physics module. It contains function pointers for the various...
procedure(sub_get_v), pointer phys_get_v
integer, parameter, public trace_face_ymin
integer, parameter, public trace_face_zmax
integer, parameter, public trace_status_out_of_domain
subroutine, public trace_debug_sample_bhat_gradbhat(seed, bhat, grad_bhat, status, b_min, spherical_cartfd)
subroutine, public trace_spherical_profile_set(enabled)
subroutine, public trace_rk45_stats_reset()
subroutine, public trace_debug_transport_tangents_to_boundary(seed, u0, v0, dl, max_steps, forward, x_end, u_end, v_end, bhat_end, b_end, u_perp_end, v_perp_end, u_face_end, v_face_end, length, face_id, status, b_min)
subroutine trace_field_single(xf, wp, wl, dl, nump, nwp, nwl, forward, ftype, tcondi)
subroutine trace_field_multi(xfm, wpm, wlm, dl, numl, nump, nwp, nwl, forwardm, ftype, tcondi)
subroutine, public trace_field_twist_multi(seeds, nseed, dl, max_steps, results, b_min)
integer, parameter, public trace_status_max_steps
subroutine, public trace_field_rk2_short_boundary_q_multi(seeds, nseed, dl, max_steps, results, b_min, twist_results)
integer, parameter, public trace_status_bad_grad_stencil
subroutine, public trace_cartesian_global_min_cell_size(hmin, status)
subroutine, public trace_spherical_curl_cache_clear()
subroutine find_points_interp(igrid, ip_in, ip_out, xf, wp, wl, nump, nwp, nwl, dl, forward, ftype, tcondi, trace_status)
subroutine, public trace_debug_qperp_single(seed, dl, max_steps, qperp, logqperp, x_f, x_b, u_f_perp, v_f_perp, u_b_perp, v_b_perp, b_seed, b_f, b_b, length_f, length_b, face_f, face_b, status, n2, bfactor, b_min)
subroutine, public trace_field_qperp_multi(seeds, nseed, dl, max_steps, results, b_min, twist_results)
subroutine, public trace_field_spherical_rmin_q_multi(seeds, nseed, dl, max_steps, results, b_min, twist_results)
subroutine, public trace_rk45_stats_report(label)
subroutine, public trace_field_topology_multi(seeds, nseed, dl, max_steps, results, need_twist, need_mapping, b_min, source_normal)
integer, parameter, public trace_face_xmax
subroutine, public trace_field_twist_single(seed, dl, max_steps, result, b_min)
subroutine, public trace_debug_sample_endpoint_b_face_limit(xhit, face_id, b, bhat, status, b_min)
subroutine, public trace_field_mapping_single(seed, dl, max_steps, result, b_min, source_normal)
integer, parameter, public trace_status_trac_stop
integer, parameter, public trace_face_none
integer, parameter, public trace_status_boundary
subroutine, public trace_spherical_profile_report(label)
integer, parameter, public trace_face_ambiguous
subroutine, public trace_field_qperp_single(seed, dl, max_steps, result, b_min)
subroutine, public trace_debug_transport_tangents(seed, u0, v0, dl, nstep, forward, x_end, u_end, v_end, bhat_end, u_perp_end, v_perp_end, status, b_min)
integer, parameter, public trace_face_zmin
subroutine, public trace_debug_compare_gradbhat_methods(seed, eps, bhat_current, grad_current, status_current, bhat_xeps, grad_xeps, status_xeps, bhat_interp, grad_interp, status_interp, b_min)
integer, parameter, public trace_status_unsupported_geometry
integer, parameter, public trace_status_bad_q_bound
subroutine, public trace_set_step_control(mode, step_fraction, step_min)
subroutine, public trace_debug_cartesian_rk45_tangent_q0_multi(seeds, nseed, dl, max_steps, results, b_min)
integer, parameter, public trace_face_ymax
subroutine, public trace_spherical_global_min_cell_size(hmin, status)
subroutine get_k(xfn, igrid, k, ixil, dxbd, ftype, b_min, field_ok)
subroutine, public trace_rk2_stats_reset()
subroutine, public trace_spherical_curl_cache_build(status)
subroutine, public trace_spherical_profile_count_seeds(nseed)
integer, parameter, public trace_status_bad_curl_stencil
subroutine, public trace_spherical_profile_reset()
integer, parameter, public trace_status_invalid_input
subroutine, public trace_field_spherical_rmin_q_qperp_multi(seeds, nseed, dl, max_steps, q_results, qperp_results, b_min, twist_results)
subroutine, public trace_field_length_multi(seeds, nseed, dl, max_steps, results, b_min)
subroutine, public trace_rk45_stats_set_enabled(enabled)
subroutine, public trace_set_integrator(mode, atol, rtol, safety, min_shrink, max_grow, tangent_floor, tangent_rtol)
subroutine, public trace_rk2_stats_set_enabled(enabled)
subroutine, public trace_field_spherical_qperp_multi(seeds, nseed, dl, max_steps, results, b_min, twist_results)
subroutine, public trace_rk2_stats_report(label)
subroutine find_points_in_pe(igrid, ipoint_in, xf, wp, wl, dl, nump, nwp, nwl, forward, ftype, tcondi, statusf)
logical function, public trace_periodic_phi_supported()
integer, parameter, public trace_status_mpi_unsupported
integer, parameter, public trace_status_weak_field
subroutine, public trace_field_length_single(seed, dl, max_steps, result, b_min)
integer, parameter, public trace_status_seed_outside
subroutine find_next_grid(igrid, igrid_next, ipe_next, xf1, newpe, stopt)
integer, parameter, public trace_status_singular_q
subroutine, public trace_debug_compare_gradbhat(seed, eps, bhat_current, grad_current, status_current, bhat_xeps, grad_xeps, status_xeps, b_min)
integer, parameter, public trace_face_xmin
subroutine get_t_loc_trac(igrid, xloc, tloc, ixil, dxbd)
integer, parameter, public trace_status_bad_face_limit_sample
subroutine, public trace_field_mapping_multi(seeds, nseed, dl, max_steps, results, b_min, source_normal)
integer, parameter, public trace_status_active
subroutine, public trace_field_q0_multi_rk45_cartesian(seeds, nseed, dl, max_steps, results, b_min, twist_results)
Module with all the methods that users can customize in AMRVAC.
procedure(set_field_w), pointer usr_set_field_w
procedure(set_field), pointer usr_set_field