2 use,
intrinsic :: ieee_arithmetic, only: ieee_value,ieee_quiet_nan, &
33 double precision,
parameter,
private :: trace_q_min=2.d0
78 private :: trace_summary_seed,trace_summary_multi
79 private :: trace_summary_twist_seed,trace_summary_twist_multi
80 private :: trace_summary_mapping_seed,trace_summary_mapping_multi
81 private :: trace_summary_topology_multi
82 private :: trace_summary_validate,trace_summary_init_result
83 private :: trace_summary_init_twist_result
84 private :: trace_summary_init_mapping_result
85 private :: trace_summary_init_topology_result
86 private :: trace_summary_locate_seed,trace_summary_trace_seed
87 private :: trace_summary_trace_twist_seed
88 private :: trace_summary_init_state,trace_summary_advance_state
89 private :: trace_summary_trace_state_to_end,trace_summary_trace_states_grouped
90 private :: trace_summary_advance_state_in_grid
91 private :: trace_summary_rk2_step,trace_summary_rk45_cartesian_step
92 private :: trace_summary_rk45_spherical_step
93 private :: trace_intersect_domain
94 private :: trace_summary_accumulate_twist,trace_twist_density_at_point
95 private :: trace_tangent_accumulate_twist,trace_tangent_fill_twist_result
96 private :: sample_b_curlb_at_point
97 private :: sample_b_curlb_spherical_at_point
98 private :: sample_b_at_point,trace_summary_fill_mapping
99 private :: trace_total_b_at_cell,trace_bhat_at_cell
100 private :: sample_bhat_gradbhat_at_point
101 private :: sample_bhat_gradbhat_cellfd_at_point
102 private :: sample_bhat_gradbhat_xeps_at_point
103 private :: sample_bhat_gradbhat_interpderiv_at_point
104 private :: trace_debug_locate_point,trace_locate_point_with_hint
105 private :: trace_tangent_rhs
106 private :: trace_advance_tangent_state_rk2,trace_project_to_perp_bhat
107 private :: trace_tangent_rk2_trial,trace_endpoint_b_bhat
108 private :: trace_tangent_rk2_trial_from_rhs
109 private :: trace_tangent_state_advance_in_grid_rk45_cartesian
110 private :: trace_tangent_rk45_cartesian_step
111 private :: trace_tangent_rhs_cartesian_located
112 private :: trace_tangent_rk45_cartesian_finish_boundary
113 private :: trace_tangent_trace_states_grouped_rk45_spherical
114 private :: trace_tangent_state_advance_in_grid_rk45_spherical
115 private :: trace_tangent_rk45_spherical_step
116 private :: trace_tangent_rk45_spherical_finish_boundary
117 private :: trace_q0_finalize_from_states
118 private :: trace_sample_b_on_domain_face_limit
119 private :: trace_locate_face_limit_grid
120 private :: trace_face_normal,trace_project_to_boundary_face
121 private :: trace_make_perp_basis,trace_debug_nan
122 private :: trace_face_from_dim_side,trace_face_bn,trace_face_is_boundary
123 private :: trace_boundary_face_at_point
124 private :: trace_is_supported_summary_geometry
125 private :: trace_effective_step,trace_spherical_metric_ok
126 private :: trace_segment_length
127 private :: trace_summary_twist_status_from_states
128 private :: trace_init_qperp_result,trace_qperp_single_core
129 private :: trace_qperp_compute_q0_scalars
130 private :: trace_qperp_project_to_boundary_face
131 private :: trace_tangent_state_init
132 private :: trace_tangent_trace_states_grouped
133 private :: trace_tangent_state_advance_in_grid
134 private :: trace_tangent_state_finalize_boundary
135 private :: trace_qperp_prepare_seed_result
136 private :: trace_qperp_compute_scalars
137 private :: trace_qperp_finalize_from_states
138 private :: trace_spherical_rmin_q_prepare_seed_result
139 private :: trace_spherical_rmin_q_finalize_from_states
140 private :: trace_spherical_radial_q_finalize_from_states
141 private :: trace_spherical_radial_q_face_pair_admitted
142 private :: trace_spherical_radial_endpoint_matrix
143 private :: trace_spherical_radial_project_to_surface
144 private :: trace_spherical_qperp_prepare_seed_result
145 private :: trace_spherical_qperp_finalize_from_states
146 private :: trace_spherical_qperp_compute_from_states
147 private :: trace_spherical_q_from_endpoint_matrices
148 private :: trace_spherical_basis,trace_spherical_coord_to_cart
149 private :: trace_cart_to_spherical_coord
150 private :: trace_spherical_sample_b_bhat_cart
151 private :: trace_spherical_sample_bhat_gradbhat_covariant
152 private :: trace_spherical_sample_bhat_gradbhat_cartfd
153 private :: trace_spherical_bhat_cart_to_rhs
154 private :: trace_spherical_endpoint_b_bhat
155 private :: trace_spherical_face_probe_coord
156 private :: trace_spherical_physical_cell_scale
157 private :: trace_spherical_cell_scale_from_widths
158 private :: trace_spherical_interp_ctx_build
159 private :: trace_spherical_interp_ctx_build_cached
160 private :: trace_spherical_effective_step_ctx
161 private :: trace_spherical_sample_bsph_ctx
162 private :: trace_spherical_sample_b_bhat_cart_ctx
163 private :: trace_spherical_sample_cached_curlb_ctx
164 private :: trace_spherical_sample_bhat_gradbhat_covariant_ctx
165 private :: get_k_spherical_ctx
166 private :: trace_spherical_interp_ctx_fill
167 private :: trace_spherical_interp_ctx_load_bcorners
168 private :: trace_interp_weights_block,trace_interp_index_3d
169 private :: trace_interp_weights_block_near,trace_interp_index_3d_near
170 private :: trace_spherical_local_cell_widths
171 private :: trace_spherical_profile_add_count
172 private :: trace_spherical_profile_add_time
173 private :: trace_spherical_profile_note_trace_steps
174 private :: trace_spherical_profile_time
175 private :: trace_cartesian_like_geometry,trace_rk45_position_integrator
176 private :: trace_cartesian_rhs_bhat
177 private :: trace_cartesian_local_cell_size
178 private :: trace_rk45_try_boundary_finish
179 private :: trace_rk2_stats_note_direction
180 private :: trace_rk2_stats_note_step
181 private :: trace_rk2_stats_note_completion
182 private :: trace_rk2_stats_note_step_limit
183 private :: trace_rk2_stats_note_group_iteration
184 private :: trace_rk2_stats_note_grid_group
185 private :: trace_rk2_stats_note_rhs
186 private :: trace_rk2_stats_add_grouped_time
187 private :: trace_rk45_stats_note_direction
188 private :: trace_rk45_stats_note_attempt
189 private :: trace_rk45_stats_note_tangent_error
191 type,
private :: trace_sph_interp_ctx
192 logical :: valid=.false.
195 double precision :: x(3)=zero
196 double precision :: xd(3)=zero
197 double precision :: dxc(3)=zero
198 double precision :: w(0:1,3)=zero
199 double precision :: dxloc(3)=zero
200 double precision :: r=zero,theta=zero,phi=zero
201 double precision :: sin_theta=zero,cos_theta=zero
202 double precision :: sin_phi=zero,cos_phi=zero
203 double precision :: rsin_theta=zero
204 double precision :: h_local=zero
205 logical :: bcorner_valid=.false.
206 double precision :: bcorner(0:1,0:1,0:1,3)=zero
207 end type trace_sph_interp_ctx
209 type,
private :: trace_spherical_curl_cache_block
210 double precision,
dimension(:^D&,:),
allocatable :: current
211 logical :: ready=.false.
212 end type trace_spherical_curl_cache_block
214 type(trace_spherical_curl_cache_block),
allocatable,
private :: &
215 trace_spherical_curl_cache(:)
216 logical,
private :: trace_spherical_curl_cache_ready=.false.
218 integer,
parameter,
private :: trace_step_control_fixed=0
219 integer,
parameter,
private :: trace_step_control_cell_fraction=1
220 integer,
private :: trace_step_control_mode=trace_step_control_fixed
221 double precision,
private :: trace_step_fraction=0.1d0
222 double precision,
private :: trace_step_min=0.d0
224 integer,
parameter,
private :: trace_integrator_rk2=0
225 integer,
parameter,
private :: trace_integrator_rk45_cartesian=1
226 integer,
parameter,
private :: trace_integrator_rk45_spherical=2
227 integer,
parameter,
private :: trace_tangent_group_rk2_general=1
228 integer,
parameter,
private :: trace_tangent_group_rk2_short_boundary=2
229 integer,
parameter,
private :: trace_tangent_group_rk45_cartesian=3
230 integer,
parameter,
private :: trace_rk45_reject_error=1
231 integer,
parameter,
private :: trace_rk45_reject_stage_failure=2
232 integer,
parameter,
private :: trace_rk45_reject_stage_outside=3
233 integer,
parameter,
private :: trace_rk45_reject_boundary=4
234 integer,
parameter,
private :: trace_rk45_reject_tangent_error=5
235 integer,
private :: trace_integrator_mode=trace_integrator_rk2
236 double precision,
private :: trace_rk45_atol=1.
d-8
237 double precision,
private :: trace_rk45_rtol=1.
d-6
238 double precision,
private :: trace_rk45_safety=0.9d0
239 double precision,
private :: trace_rk45_min_shrink=0.2d0
240 double precision,
private :: trace_rk45_max_grow=5.d0
241 double precision,
private :: trace_rk45_tangent_floor=1.d0
242 double precision,
private :: trace_rk45_tangent_rtol=2.
d-5
243 logical,
private :: trace_rk2_stats_enabled=.false.
244 integer(kind=8),
private :: trace_rk2_directions=0_8
245 integer(kind=8),
private :: trace_rk2_completed_directions=0_8
246 integer(kind=8),
private :: trace_rk2_total_steps=0_8
247 integer(kind=8),
private :: trace_rk2_boundary_completions=0_8
248 integer(kind=8),
private :: trace_rk2_max_steps_failures=0_8
249 integer(kind=8),
private :: trace_rk2_domain_limited_steps=0_8
250 integer(kind=8),
private :: trace_rk2_grid_transition_steps=0_8
251 integer(kind=8),
private :: trace_rk2_cell_fraction_limited=0_8
252 integer(kind=8),
private :: trace_rk2_dl_limited=0_8
253 integer(kind=8),
private :: trace_rk2_dl_min_limited=0_8
254 integer(kind=8),
private :: trace_rk2_group_iterations=0_8
255 integer(kind=8),
private :: trace_rk2_grid_groups=0_8
256 integer(kind=8),
private :: trace_rk2_group_state_sum=0_8
257 integer(kind=8),
private :: trace_rk2_group_state_max=0_8
258 integer(kind=8),
private :: trace_rk2_rhs_calls=0_8
259 double precision,
private :: trace_rk2_sum_step_length=0.d0
260 double precision,
private :: trace_rk2_min_step_length=huge(one)
261 double precision,
private :: trace_rk2_max_step_length=0.d0
262 double precision,
private :: trace_rk2_grouped_time=0.d0
263 integer(kind=8),
private :: trace_rk2_max_steps_per_direction=0_8
264 logical,
private :: trace_rk45_stats_enabled=.false.
265 integer(kind=8),
private :: trace_rk45_directions=0_8
266 integer(kind=8),
private :: trace_rk45_attempts=0_8
267 integer(kind=8),
private :: trace_rk45_accepted=0_8
268 integer(kind=8),
private :: trace_rk45_rejected=0_8
269 integer(kind=8),
private :: trace_rk45_rejected_error=0_8
270 integer(kind=8),
private :: trace_rk45_rejected_position_error=0_8
271 integer(kind=8),
private :: trace_rk45_rejected_tangent_error=0_8
272 integer(kind=8),
private :: trace_rk45_rejected_stage_failure=0_8
273 integer(kind=8),
private :: trace_rk45_rejected_stage_outside=0_8
274 integer(kind=8),
private :: trace_rk45_rejected_boundary=0_8
275 integer(kind=8),
private :: trace_rk45_boundary_limited=0_8
276 double precision,
private :: trace_rk45_sum_accepted_h=0.d0
277 double precision,
private :: trace_rk45_min_accepted_h=huge(one)
278 double precision,
private :: trace_rk45_max_accepted_h=0.d0
279 integer(kind=8),
private :: trace_rk45_tangent_error_samples=0_8
280 integer(kind=8),
private :: trace_rk45_tangent_would_reject=0_8
281 double precision,
private :: trace_rk45_sum_tangent_error_ratio=0.d0
282 double precision,
private :: trace_rk45_max_tangent_error_ratio=0.d0
283 double precision,
private :: trace_rk45_max_tangent_u_error_ratio=0.d0
284 double precision,
private :: trace_rk45_max_tangent_v_error_ratio=0.d0
285 double precision,
private :: trace_rk45_max_position_error_ratio=0.d0
287 logical,
private :: trace_spherical_profile_enabled=.false.
288 logical,
parameter,
private :: trace_spherical_profile_timers=.false.
289 integer(kind=8),
private :: trace_profile_seeds=0_8
290 integer(kind=8),
private :: trace_profile_directions=0_8
291 integer(kind=8),
private :: trace_profile_steps=0_8
292 integer(kind=8),
private :: trace_profile_boundary_events=0_8
293 integer(kind=8),
private :: trace_profile_endpoint_finalizations=0_8
294 integer(kind=8),
private :: trace_profile_context_requests=0_8
295 integer(kind=8),
private :: trace_profile_same_cell_hits=0_8
296 integer(kind=8),
private :: trace_profile_same_grid_hits=0_8
297 integer(kind=8),
private :: trace_profile_full_context_builds=0_8
298 integer(kind=8),
private :: trace_profile_context_failures=0_8
299 integer(kind=8),
private :: trace_profile_cache_invalidations=0_8
300 integer(kind=8),
private :: trace_profile_b_samples=0_8
301 integer(kind=8),
private :: trace_profile_curl_samples=0_8
302 integer(kind=8),
private :: trace_profile_grad_samples=0_8
303 integer(kind=8),
private :: trace_profile_grad_success=0_8
304 integer(kind=8),
private :: trace_profile_grad_fallbacks=0_8
305 integer(kind=8),
private :: trace_profile_b_corner_loads=0_8
306 integer(kind=8),
private :: trace_profile_b_corner_hits=0_8
307 integer(kind=8),
private :: trace_profile_hlocal_evals=0_8
308 integer(kind=8),
private :: trace_profile_face_probes=0_8
309 integer(kind=8),
private :: trace_profile_tangent_systems=0_8
310 integer(kind=8),
private :: trace_profile_q_tangent_systems=0_8
311 integer(kind=8),
private :: trace_profile_qperp_tangent_systems=0_8
312 integer(kind=8),
private :: trace_profile_combined_tangent_systems=0_8
313 integer(kind=8),
private :: trace_profile_max_steps_per_trace=0_8
314 double precision,
private :: trace_profile_time_context=0.d0
315 double precision,
private :: trace_profile_time_b_interp=0.d0
316 double precision,
private :: trace_profile_time_curl_interp=0.d0
317 double precision,
private :: trace_profile_time_grad_bhat=0.d0
318 double precision,
private :: trace_profile_time_step=0.d0
319 double precision,
private :: trace_profile_time_tangent=0.d0
321 type,
private :: trace_summary_state
322 double precision :: x(
ndim)
323 double precision :: footpoint(
ndim)
324 double precision :: length
325 double precision :: twist
328 integer :: twist_status
334 logical :: accumulate_twist
335 double precision :: rk45_h
336 type(trace_sph_interp_ctx) :: sph_cache
337 end type trace_summary_state
339 type,
private :: trace_tangent_state
345 double precision :: x(
ndim)
346 double precision :: u(
ndim)
347 double precision :: v(
ndim)
348 double precision :: p(
ndim)
349 double precision :: q(
ndim)
350 double precision :: length
351 double precision :: twist
355 integer :: twist_status
357 double precision :: endpoint(
ndim)
358 double precision :: endpoint_b(
ndim)
359 double precision :: endpoint_bhat(
ndim)
360 double precision :: u_perp(
ndim)
361 double precision :: v_perp(
ndim)
362 double precision :: p_perp(
ndim)
363 double precision :: q_perp(
ndim)
364 double precision :: rk45_h
365 logical :: accumulate_twist
366 type(trace_sph_interp_ctx) :: sph_cache
367 end type trace_tangent_state
371 double precision :: forward_footpoint(
ndim)
372 double precision :: backward_footpoint(
ndim)
373 double precision :: forward_length
374 double precision :: backward_length
375 double precision :: total_length
376 integer :: forward_nstep
377 integer :: backward_nstep
378 integer :: forward_status
379 integer :: backward_status
384 double precision :: forward_twist
385 double precision :: backward_twist
386 double precision :: total_twist
387 logical :: valid_twist
388 integer :: status_twist
393 double precision :: source_b(3)
394 double precision :: forward_footpoint(
ndim)
395 double precision :: backward_footpoint(
ndim)
396 double precision :: forward_b(3)
397 double precision :: backward_b(3)
398 double precision :: forward_length
399 double precision :: backward_length
400 double precision :: source_bn
401 double precision :: forward_bn
402 double precision :: backward_bn
403 integer :: forward_face
404 integer :: backward_face
405 integer :: forward_status
406 integer :: backward_status
412 double precision :: qperp
413 double precision :: logqperp
414 double precision :: n2
415 double precision :: bfactor
416 double precision :: q0
417 double precision :: logq0
418 double precision :: qperp0
419 double precision :: logqperp0
420 double precision :: n2_qperp0
421 double precision :: bfactor_qperp0
422 double precision :: forward_bn_q0
423 double precision :: backward_bn_q0
424 double precision :: b_seed(
ndim)
425 double precision :: bhat_seed(
ndim)
426 double precision :: forward_endpoint(
ndim)
427 double precision :: backward_endpoint(
ndim)
428 double precision :: forward_b(
ndim)
429 double precision :: backward_b(
ndim)
430 double precision :: forward_bhat(
ndim)
431 double precision :: backward_bhat(
ndim)
432 double precision :: forward_length
433 double precision :: backward_length
434 integer :: forward_nstep
435 integer :: backward_nstep
438 double precision :: u_forward_perp(
ndim)
439 double precision :: v_forward_perp(
ndim)
440 double precision :: u_backward_perp(
ndim)
441 double precision :: v_backward_perp(
ndim)
442 integer :: forward_face
443 integer :: backward_face
444 integer :: forward_status
445 integer :: backward_status
447 integer :: status_qperp0
451 logical :: valid_qperp0
456 double precision :: length_forward
457 double precision :: length_backward
458 double precision :: length_total
459 double precision :: twist_forward
460 double precision :: twist_backward
461 double precision :: twist_total
462 double precision :: forward_endpoint(
ndim)
463 double precision :: backward_endpoint(
ndim)
464 integer :: forward_nstep
465 integer :: backward_nstep
466 integer :: forward_face
467 integer :: backward_face
468 integer :: forward_status
469 integer :: backward_status
470 double precision :: map_forward_endpoint(
ndim)
471 double precision :: map_backward_endpoint(
ndim)
472 double precision :: map_forward_length
473 double precision :: map_backward_length
474 integer :: map_forward_face
475 integer :: map_backward_face
476 integer :: map_forward_status
477 integer :: map_backward_status
478 double precision :: source_b(3)
479 double precision :: forward_b(3)
480 double precision :: backward_b(3)
481 double precision :: source_bn
482 double precision :: forward_bn
483 double precision :: backward_bn
485 logical :: has_mapping
486 logical :: valid_twist
488 integer :: status_twist
495 character(len=*),
intent(in) :: mode
496 double precision,
intent(in) :: step_fraction,step_min
498 character(len=len(mode)) :: mode_lc
503 code=iachar(mode_lc(i:i))
504 if (code>=iachar(
'A') .and. code<=iachar(
'Z'))
then
505 mode_lc(i:i)=achar(code+iachar(
'a')-iachar(
'A'))
509 select case (trim(mode_lc))
510 case (
'cell_fraction')
511 trace_step_control_mode=trace_step_control_cell_fraction
513 trace_step_control_mode=trace_step_control_fixed
515 trace_step_fraction=step_fraction
516 trace_step_min=max(zero,step_min)
520 max_grow,tangent_floor,tangent_rtol)
521 character(len=*),
intent(in) :: mode
522 double precision,
intent(in) :: atol,rtol,safety,min_shrink,max_grow
523 double precision,
intent(in) :: tangent_floor,tangent_rtol
525 character(len=len(mode)) :: mode_lc
530 code=iachar(mode_lc(i:i))
531 if (code>=iachar(
'A') .and. code<=iachar(
'Z'))
then
532 mode_lc(i:i)=achar(code+iachar(
'a')-iachar(
'A'))
536 select case (trim(mode_lc))
537 case (
'rk45_cartesian')
538 trace_integrator_mode=trace_integrator_rk45_cartesian
539 case (
'rk45_spherical')
540 trace_integrator_mode=trace_integrator_rk45_spherical
542 trace_integrator_mode=trace_integrator_rk2
544 trace_rk45_atol=max(atol,zero)
545 trace_rk45_rtol=max(rtol,zero)
546 trace_rk45_safety=max(0.1d0,min(safety,one))
547 trace_rk45_min_shrink=max(0.01d0,min(min_shrink,one))
548 trace_rk45_max_grow=max(one,max_grow)
549 trace_rk45_tangent_floor=max(tangent_floor,smalldouble)
550 trace_rk45_tangent_rtol=max(tangent_rtol,smalldouble)
554 logical,
intent(in) :: enabled
556 trace_rk2_stats_enabled=enabled
560 trace_rk2_directions=0_8
561 trace_rk2_completed_directions=0_8
562 trace_rk2_total_steps=0_8
563 trace_rk2_boundary_completions=0_8
564 trace_rk2_max_steps_failures=0_8
565 trace_rk2_domain_limited_steps=0_8
566 trace_rk2_grid_transition_steps=0_8
567 trace_rk2_cell_fraction_limited=0_8
568 trace_rk2_dl_limited=0_8
569 trace_rk2_dl_min_limited=0_8
570 trace_rk2_group_iterations=0_8
571 trace_rk2_grid_groups=0_8
572 trace_rk2_group_state_sum=0_8
573 trace_rk2_group_state_max=0_8
574 trace_rk2_rhs_calls=0_8
575 trace_rk2_sum_step_length=0.d0
576 trace_rk2_min_step_length=huge(one)
577 trace_rk2_max_step_length=0.d0
578 trace_rk2_grouped_time=0.d0
579 trace_rk2_max_steps_per_direction=0_8
583 character(len=*),
intent(in) :: label
585 double precision :: mean_group_size,mean_h,mean_steps_per_direction
587 if (.not.trace_rk2_stats_enabled)
return
590 if (trace_rk2_total_steps>0_8)
then
591 mean_h=trace_rk2_sum_step_length/dble(trace_rk2_total_steps)
593 mean_steps_per_direction=zero
594 if (trace_rk2_completed_directions>0_8)
then
595 mean_steps_per_direction=dble(trace_rk2_total_steps)/ &
596 dble(trace_rk2_completed_directions)
599 if (trace_rk2_grid_groups>0_8)
then
600 mean_group_size=dble(trace_rk2_group_state_sum)/ &
601 dble(trace_rk2_grid_groups)
604 write(*,
'(a)')
'[mt_rk2] Cartesian field-line RK2 summary: '// &
606 write(*,
'(a,i0)')
' traced_directions: ',trace_rk2_directions
607 write(*,
'(a,i0)')
' completed_directions: ', &
608 trace_rk2_completed_directions
609 write(*,
'(a,i0)')
' total_steps: ',trace_rk2_total_steps
610 write(*,
'(a,es12.4)')
' mean_step_length: ',mean_h
611 if (trace_rk2_total_steps>0_8)
then
612 write(*,
'(a,es12.4)')
' min_step_length: ', &
613 trace_rk2_min_step_length
614 write(*,
'(a,es12.4)')
' max_step_length: ', &
615 trace_rk2_max_step_length
617 write(*,
'(a,es12.4)')
' mean_steps_per_direction: ', &
618 mean_steps_per_direction
619 write(*,
'(a,i0)')
' max_steps_per_direction: ', &
620 trace_rk2_max_steps_per_direction
621 write(*,
'(a,i0)')
' boundary_completions: ', &
622 trace_rk2_boundary_completions
623 write(*,
'(a,i0)')
' max_steps_failures: ', &
624 trace_rk2_max_steps_failures
625 write(*,
'(a,i0)')
' domain_boundary_limited_steps: ', &
626 trace_rk2_domain_limited_steps
627 write(*,
'(a,i0)')
' block_grid_clipped_steps: 0'
628 write(*,
'(a,i0)')
' grid_transition_steps: ', &
629 trace_rk2_grid_transition_steps
630 write(*,
'(a,i0)')
' cell_fraction_limited_evals: ', &
631 trace_rk2_cell_fraction_limited
632 write(*,
'(a,i0)')
' dL_cap_limited_evals: ',trace_rk2_dl_limited
633 write(*,
'(a,i0)')
' dL_min_limited_evals: ',trace_rk2_dl_min_limited
634 write(*,
'(a,i0)')
' grouped_driver_outer_iterations: ', &
635 trace_rk2_group_iterations
636 write(*,
'(a,i0)')
' grouped_driver_parallel_batches: ', &
637 trace_rk2_grid_groups
638 write(*,
'(a,es12.4)')
' grouped_driver_mean_batch_size: ', &
640 write(*,
'(a,i0)')
' grouped_driver_max_batch_size: ', &
641 trace_rk2_group_state_max
642 write(*,
'(a,es12.4)')
' grouped_driver_cpu_time: ', &
643 trace_rk2_grouped_time
644 write(*,
'(a,i0)')
' trace_tangent_rhs_calls: ',trace_rk2_rhs_calls
645 write(*,
'(a)')
' note: Cartesian RK2 grouped tracing does not clip '// &
646 'steps to AMR block/grid boundaries; grid changes are counted after '// &
647 'accepted full steps.'
650 subroutine trace_rk2_stats_note_direction()
651 if (.not.trace_rk2_stats_enabled)
return
653 trace_rk2_directions=trace_rk2_directions+1_8
655 end subroutine trace_rk2_stats_note_direction
657 subroutine trace_rk2_stats_note_step(h,domain_limited,grid_transition)
658 double precision,
intent(in) :: h
659 logical,
intent(in) :: domain_limited,grid_transition
661 if (.not.trace_rk2_stats_enabled)
return
663 trace_rk2_total_steps=trace_rk2_total_steps+1_8
664 trace_rk2_sum_step_length=trace_rk2_sum_step_length+abs(h)
665 trace_rk2_min_step_length=min(trace_rk2_min_step_length,abs(h))
666 trace_rk2_max_step_length=max(trace_rk2_max_step_length,abs(h))
667 if (domain_limited) trace_rk2_domain_limited_steps= &
668 trace_rk2_domain_limited_steps+1_8
669 if (grid_transition) trace_rk2_grid_transition_steps= &
670 trace_rk2_grid_transition_steps+1_8
672 end subroutine trace_rk2_stats_note_step
674 subroutine trace_rk2_stats_note_completion(status,nstep)
675 integer,
intent(in) :: status,
nstep
677 if (.not.trace_rk2_stats_enabled)
return
679 trace_rk2_completed_directions=trace_rk2_completed_directions+1_8
680 trace_rk2_max_steps_per_direction=max( &
681 trace_rk2_max_steps_per_direction,int(
nstep,kind=8))
684 trace_rk2_boundary_completions=trace_rk2_boundary_completions+1_8
686 trace_rk2_max_steps_failures=trace_rk2_max_steps_failures+1_8
689 end subroutine trace_rk2_stats_note_completion
691 subroutine trace_rk2_stats_note_step_limit(step_cap,cell_step,actual_step)
692 double precision,
intent(in) :: step_cap,cell_step,actual_step
694 double precision :: tol
696 if (.not.trace_rk2_stats_enabled)
return
697 tol=100.d0*epsilon(one)*max(one,step_cap,cell_step,actual_step)
699 if (actual_step>=step_cap-tol)
then
700 trace_rk2_dl_limited=trace_rk2_dl_limited+1_8
701 else if (trace_step_min>zero .and. actual_step>=trace_step_min-tol .and. &
702 actual_step>cell_step+tol)
then
703 trace_rk2_dl_min_limited=trace_rk2_dl_min_limited+1_8
705 trace_rk2_cell_fraction_limited=trace_rk2_cell_fraction_limited+1_8
708 end subroutine trace_rk2_stats_note_step_limit
710 subroutine trace_rk2_stats_note_group_iteration()
711 if (.not.trace_rk2_stats_enabled)
return
713 trace_rk2_group_iterations=trace_rk2_group_iterations+1_8
715 end subroutine trace_rk2_stats_note_group_iteration
717 subroutine trace_rk2_stats_note_grid_group(group_size)
718 integer,
intent(in) :: group_size
720 if (.not.trace_rk2_stats_enabled)
return
722 trace_rk2_grid_groups=trace_rk2_grid_groups+1_8
723 trace_rk2_group_state_sum=trace_rk2_group_state_sum+ &
724 int(group_size,kind=8)
725 trace_rk2_group_state_max=max(trace_rk2_group_state_max, &
726 int(group_size,kind=8))
728 end subroutine trace_rk2_stats_note_grid_group
730 subroutine trace_rk2_stats_note_rhs()
731 if (.not.trace_rk2_stats_enabled)
return
733 trace_rk2_rhs_calls=trace_rk2_rhs_calls+1_8
734 end subroutine trace_rk2_stats_note_rhs
736 subroutine trace_rk2_stats_add_grouped_time(dt)
737 double precision,
intent(in) ::
dt
739 if (.not.trace_rk2_stats_enabled)
return
741 trace_rk2_grouped_time=trace_rk2_grouped_time+
dt
743 end subroutine trace_rk2_stats_add_grouped_time
746 logical,
intent(in) :: enabled
748 trace_rk45_stats_enabled=enabled
752 trace_rk45_directions=0_8
753 trace_rk45_attempts=0_8
754 trace_rk45_accepted=0_8
755 trace_rk45_rejected=0_8
756 trace_rk45_rejected_error=0_8
757 trace_rk45_rejected_position_error=0_8
758 trace_rk45_rejected_tangent_error=0_8
759 trace_rk45_rejected_stage_failure=0_8
760 trace_rk45_rejected_stage_outside=0_8
761 trace_rk45_rejected_boundary=0_8
762 trace_rk45_boundary_limited=0_8
763 trace_rk45_sum_accepted_h=0.d0
764 trace_rk45_min_accepted_h=huge(one)
765 trace_rk45_max_accepted_h=0.d0
766 trace_rk45_tangent_error_samples=0_8
767 trace_rk45_tangent_would_reject=0_8
768 trace_rk45_sum_tangent_error_ratio=0.d0
769 trace_rk45_max_tangent_error_ratio=0.d0
770 trace_rk45_max_tangent_u_error_ratio=0.d0
771 trace_rk45_max_tangent_v_error_ratio=0.d0
772 trace_rk45_max_position_error_ratio=0.d0
776 character(len=*),
intent(in) :: label
778 double precision :: mean_h,mean_reject_per_trace,mean_tangent_error
780 if (.not.trace_rk45_stats_enabled)
return
781 if (trace_integrator_mode/=trace_integrator_rk45_cartesian .and. &
782 trace_integrator_mode/=trace_integrator_rk45_spherical)
return
785 if (trace_rk45_accepted>0_8)
then
786 mean_h=trace_rk45_sum_accepted_h/dble(trace_rk45_accepted)
788 mean_reject_per_trace=zero
789 if (trace_rk45_directions>0_8)
then
790 mean_reject_per_trace=dble(trace_rk45_rejected)/dble(trace_rk45_directions)
793 select case (trace_integrator_mode)
794 case (trace_integrator_rk45_cartesian)
795 write(*,
'(a)')
'[mt_rk45] Cartesian field-line RK45 summary: '// &
797 case (trace_integrator_rk45_spherical)
798 write(*,
'(a)')
'[mt_rk45] Spherical field-line RK45 summary: '// &
801 write(*,
'(a,i0)')
' traced_directions: ',trace_rk45_directions
802 write(*,
'(a,i0)')
' attempts: ',trace_rk45_attempts
803 write(*,
'(a,i0)')
' accepted_steps: ',trace_rk45_accepted
804 write(*,
'(a,i0)')
' rejected_steps: ',trace_rk45_rejected
805 write(*,
'(a,i0)')
' rejected_error_steps: ', &
806 trace_rk45_rejected_error
807 write(*,
'(a,i0)')
' rejected_position_error_steps: ', &
808 trace_rk45_rejected_position_error
809 write(*,
'(a,i0)')
' rejected_tangent_error_steps: ', &
810 trace_rk45_rejected_tangent_error
811 write(*,
'(a,i0)')
' rejected_stage_failure_steps: ', &
812 trace_rk45_rejected_stage_failure
813 write(*,
'(a,i0)')
' rejected_stage_outside_steps: ', &
814 trace_rk45_rejected_stage_outside
815 write(*,
'(a,i0)')
' rejected_boundary_steps: ', &
816 trace_rk45_rejected_boundary
817 write(*,
'(a,es12.4)')
' rejected_steps_per_direction: ', &
818 mean_reject_per_trace
819 write(*,
'(a,i0)')
' boundary_limited_steps: ', &
820 trace_rk45_boundary_limited
821 write(*,
'(a,es12.4)')
' mean_accepted_step: ',mean_h
822 if (trace_rk45_accepted>0_8)
then
823 write(*,
'(a,es12.4)')
' min_accepted_step: ', &
824 trace_rk45_min_accepted_h
825 write(*,
'(a,es12.4)')
' max_accepted_step: ', &
826 trace_rk45_max_accepted_h
828 if (trace_rk45_tangent_error_samples>0_8)
then
829 write(*,
'(a)')
' error_control_mode: position_tangent'
830 mean_tangent_error=trace_rk45_sum_tangent_error_ratio/ &
831 dble(trace_rk45_tangent_error_samples)
832 write(*,
'(a,i0)')
' tangent_error_samples: ', &
833 trace_rk45_tangent_error_samples
834 write(*,
'(a,i0)')
' tangent_would_reject_steps: ', &
835 trace_rk45_tangent_would_reject
836 write(*,
'(a,es12.4)')
' max_position_error_ratio: ', &
837 trace_rk45_max_position_error_ratio
838 write(*,
'(a,es12.4)')
' mean_tangent_error_ratio: ', &
840 write(*,
'(a,es12.4)')
' max_tangent_error_ratio: ', &
841 trace_rk45_max_tangent_error_ratio
842 write(*,
'(a,es12.4)')
' max_tangent_u_error_ratio: ', &
843 trace_rk45_max_tangent_u_error_ratio
844 write(*,
'(a,es12.4)')
' max_tangent_v_error_ratio: ', &
845 trace_rk45_max_tangent_v_error_ratio
846 write(*,
'(a,es12.4)')
' tangent_error_rtol: ', &
847 trace_rk45_tangent_rtol
848 write(*,
'(a,es12.4)')
' tangent_error_floor: ', &
849 trace_rk45_tangent_floor
850 write(*,
'(a)')
' tangent_error_note: standard-logQ tangent '// &
851 'traces use position+tangent RK45 accept/reject.'
853 write(*,
'(a)')
' error_control_mode: position'
855 write(*,
'(a)')
' note: this experimental RK45 mode traces '// &
856 'position/length/twist and tangent-transport Q products where enabled.'
859 subroutine trace_rk45_stats_note_direction()
860 if (.not.trace_rk45_stats_enabled)
return
861 if (trace_integrator_mode/=trace_integrator_rk45_cartesian .and. &
862 trace_integrator_mode/=trace_integrator_rk45_spherical)
return
864 trace_rk45_directions=trace_rk45_directions+1_8
866 end subroutine trace_rk45_stats_note_direction
868 subroutine trace_rk45_stats_note_attempt(accepted,boundary_limited,h, &
870 logical,
intent(in) :: accepted,boundary_limited
871 double precision,
intent(in) :: h
872 integer,
intent(in),
optional :: reject_reason
874 if (.not.trace_rk45_stats_enabled)
return
875 if (trace_integrator_mode/=trace_integrator_rk45_cartesian .and. &
876 trace_integrator_mode/=trace_integrator_rk45_spherical)
return
878 trace_rk45_attempts=trace_rk45_attempts+1_8
880 trace_rk45_accepted=trace_rk45_accepted+1_8
881 trace_rk45_sum_accepted_h=trace_rk45_sum_accepted_h+abs(h)
882 trace_rk45_min_accepted_h=min(trace_rk45_min_accepted_h,abs(h))
883 trace_rk45_max_accepted_h=max(trace_rk45_max_accepted_h,abs(h))
884 if (boundary_limited) trace_rk45_boundary_limited= &
885 trace_rk45_boundary_limited+1_8
887 trace_rk45_rejected=trace_rk45_rejected+1_8
888 if (
present(reject_reason))
then
889 select case (reject_reason)
890 case (trace_rk45_reject_error)
891 trace_rk45_rejected_error=trace_rk45_rejected_error+1_8
892 trace_rk45_rejected_position_error= &
893 trace_rk45_rejected_position_error+1_8
894 case (trace_rk45_reject_tangent_error)
895 trace_rk45_rejected_error=trace_rk45_rejected_error+1_8
896 trace_rk45_rejected_tangent_error= &
897 trace_rk45_rejected_tangent_error+1_8
898 case (trace_rk45_reject_stage_failure)
899 trace_rk45_rejected_stage_failure= &
900 trace_rk45_rejected_stage_failure+1_8
901 case (trace_rk45_reject_stage_outside)
902 trace_rk45_rejected_stage_outside= &
903 trace_rk45_rejected_stage_outside+1_8
904 case (trace_rk45_reject_boundary)
905 trace_rk45_rejected_boundary=trace_rk45_rejected_boundary+1_8
910 end subroutine trace_rk45_stats_note_attempt
912 subroutine trace_rk45_stats_note_tangent_error(position_error_ratio, &
913 u_error_ratio,v_error_ratio)
914 double precision,
intent(in) :: position_error_ratio
915 double precision,
intent(in) :: u_error_ratio,v_error_ratio
917 double precision :: tangent_error_ratio
919 if (.not.trace_rk45_stats_enabled)
return
920 if (trace_integrator_mode/=trace_integrator_rk45_cartesian .and. &
921 trace_integrator_mode/=trace_integrator_rk45_spherical)
return
922 tangent_error_ratio=max(u_error_ratio,v_error_ratio)
924 trace_rk45_tangent_error_samples= &
925 trace_rk45_tangent_error_samples+1_8
926 trace_rk45_sum_tangent_error_ratio= &
927 trace_rk45_sum_tangent_error_ratio+tangent_error_ratio
928 trace_rk45_max_tangent_error_ratio= &
929 max(trace_rk45_max_tangent_error_ratio,tangent_error_ratio)
930 trace_rk45_max_tangent_u_error_ratio= &
931 max(trace_rk45_max_tangent_u_error_ratio,u_error_ratio)
932 trace_rk45_max_tangent_v_error_ratio= &
933 max(trace_rk45_max_tangent_v_error_ratio,v_error_ratio)
934 trace_rk45_max_position_error_ratio= &
935 max(trace_rk45_max_position_error_ratio,position_error_ratio)
936 if (tangent_error_ratio>trace_rk45_tangent_rtol) &
937 trace_rk45_tangent_would_reject= &
938 trace_rk45_tangent_would_reject+1_8
940 end subroutine trace_rk45_stats_note_tangent_error
943 logical,
intent(in) :: enabled
945 trace_spherical_profile_enabled=enabled
949 trace_profile_seeds=0_8
950 trace_profile_directions=0_8
951 trace_profile_steps=0_8
952 trace_profile_boundary_events=0_8
953 trace_profile_endpoint_finalizations=0_8
954 trace_profile_context_requests=0_8
955 trace_profile_same_cell_hits=0_8
956 trace_profile_same_grid_hits=0_8
957 trace_profile_full_context_builds=0_8
958 trace_profile_context_failures=0_8
959 trace_profile_cache_invalidations=0_8
960 trace_profile_b_samples=0_8
961 trace_profile_curl_samples=0_8
962 trace_profile_grad_samples=0_8
963 trace_profile_grad_success=0_8
964 trace_profile_grad_fallbacks=0_8
965 trace_profile_b_corner_loads=0_8
966 trace_profile_b_corner_hits=0_8
967 trace_profile_hlocal_evals=0_8
968 trace_profile_face_probes=0_8
969 trace_profile_tangent_systems=0_8
970 trace_profile_q_tangent_systems=0_8
971 trace_profile_qperp_tangent_systems=0_8
972 trace_profile_combined_tangent_systems=0_8
973 trace_profile_max_steps_per_trace=0_8
974 trace_profile_time_context=0.d0
975 trace_profile_time_b_interp=0.d0
976 trace_profile_time_curl_interp=0.d0
977 trace_profile_time_grad_bhat=0.d0
978 trace_profile_time_step=0.d0
979 trace_profile_time_tangent=0.d0
983 integer,
intent(in) :: nseed
985 if (.not.trace_spherical_profile_enabled)
return
986 call trace_spherical_profile_add_count(trace_profile_seeds, &
987 int(max(nseed,0),kind=8))
991 character(len=*),
intent(in) :: label
993 double precision :: avg_steps,denom,hit_denom
995 if (.not.trace_spherical_profile_enabled)
return
998 denom=max(one,dble(trace_profile_directions))
999 avg_steps=dble(trace_profile_steps)/denom
1000 hit_denom=max(one,dble(trace_profile_context_requests))
1002 write(*,
'(a)')
'[mt_profile] spherical topology profiling summary '// &
1004 write(*,
'(a,i0)')
' seeds: ',trace_profile_seeds
1005 write(*,
'(a,i0)')
' traced_directions: ',trace_profile_directions
1006 write(*,
'(a,i0)')
' accepted_steps_all_integrators: ', &
1008 write(*,
'(a,es12.4)')
' avg_steps_per_counted_trace: ',avg_steps
1009 write(*,
'(a,i0)')
' max_steps_per_trace: ', &
1010 trace_profile_max_steps_per_trace
1011 write(*,
'(a)')
' note: accepted steps include counted spherical '// &
1012 'summary and tangent integrations; shared Q/Qperp tangent '// &
1013 'transport is counted once.'
1014 write(*,
'(a)')
' note: profiling counters are diagnostic and may '// &
1015 'significantly slow hot loops; do not use profiling-on wall time '// &
1016 'as production timing.'
1017 write(*,
'(a,i0)')
' boundary_events: ',trace_profile_boundary_events
1018 write(*,
'(a,i0)')
' endpoint_finalizations: ', &
1019 trace_profile_endpoint_finalizations
1020 write(*,
'(a,i0)')
' context_requests: ',trace_profile_context_requests
1021 write(*,
'(a,i0,a,f6.2,a)')
' same_cell_hits: ', &
1022 trace_profile_same_cell_hits,
' (', &
1023 100.d0*dble(trace_profile_same_cell_hits)/hit_denom,
'%)'
1024 write(*,
'(a,i0,a,f6.2,a)')
' same_grid_hits: ', &
1025 trace_profile_same_grid_hits,
' (', &
1026 100.d0*dble(trace_profile_same_grid_hits)/hit_denom,
'%)'
1027 write(*,
'(a,i0,a,f6.2,a)')
' full_context_builds: ', &
1028 trace_profile_full_context_builds,
' (', &
1029 100.d0*dble(trace_profile_full_context_builds)/hit_denom,
'%)'
1030 write(*,
'(a,i0)')
' context_failures: ',trace_profile_context_failures
1031 write(*,
'(a,i0)')
' cache_invalidations: ', &
1032 trace_profile_cache_invalidations
1033 write(*,
'(a,i0)')
' B_samples: ',trace_profile_b_samples
1034 write(*,
'(a,i0)')
' curl_samples: ',trace_profile_curl_samples
1035 write(*,
'(a,i0)')
' grad_bhat_samples: ',trace_profile_grad_samples
1036 write(*,
'(a,i0)')
' grad_bhat_success: ',trace_profile_grad_success
1037 write(*,
'(a,i0)')
' grad_bhat_fallbacks: ', &
1038 trace_profile_grad_fallbacks
1039 write(*,
'(a,i0)')
' B_corner_loads: ',trace_profile_b_corner_loads
1040 write(*,
'(a,i0)')
' B_corner_cache_hits: ', &
1041 trace_profile_b_corner_hits
1042 write(*,
'(a,i0)')
' h_local_evals: ',trace_profile_hlocal_evals
1043 write(*,
'(a,i0)')
' boundary_face_probes: ', &
1044 trace_profile_face_probes
1045 write(*,
'(a,i0)')
' tangent_systems: ', &
1046 trace_profile_tangent_systems
1047 write(*,
'(a,i0)')
' q_tangent_systems: ', &
1048 trace_profile_q_tangent_systems
1049 write(*,
'(a,i0)')
' qperp_tangent_systems: ', &
1050 trace_profile_qperp_tangent_systems
1051 write(*,
'(a,i0)')
' combined_q_qperp_tangent_systems: ', &
1052 trace_profile_combined_tangent_systems
1053 write(*,
'(a)')
' timing_cpu_seconds:'
1054 if (.not.trace_spherical_profile_timers)
then
1055 write(*,
'(a)')
' disabled (hot-loop timers distort profiling runs)'
1058 write(*,
'(a,es12.4)')
' context: ',trace_profile_time_context
1059 write(*,
'(a,es12.4)')
' B_interp: ',trace_profile_time_b_interp
1060 write(*,
'(a,es12.4)')
' curl_interp: ', &
1061 trace_profile_time_curl_interp
1062 write(*,
'(a,es12.4)')
' grad_bhat: ',trace_profile_time_grad_bhat
1063 write(*,
'(a,es12.4)')
' step_size: ',trace_profile_time_step
1064 write(*,
'(a,es12.4)')
' tangent_transport: ', &
1065 trace_profile_time_tangent
1068 subroutine trace_spherical_profile_add_count(counter,delta)
1069 integer(kind=8),
intent(inout) :: counter
1070 integer(kind=8),
intent(in) :: delta
1072 if (.not.trace_spherical_profile_enabled)
return
1074 counter=counter+delta
1075 end subroutine trace_spherical_profile_add_count
1077 subroutine trace_spherical_profile_add_time(timer,dt)
1078 double precision,
intent(inout) :: timer
1079 double precision,
intent(in) ::
dt
1081 if (.not.trace_spherical_profile_enabled)
return
1082 if (.not.trace_spherical_profile_timers)
return
1085 end subroutine trace_spherical_profile_add_time
1087 subroutine trace_spherical_profile_note_trace_steps(nstep)
1088 integer,
intent(in) ::
nstep
1090 if (.not.trace_spherical_profile_enabled)
return
1092 trace_profile_max_steps_per_trace=max(trace_profile_max_steps_per_trace, &
1095 end subroutine trace_spherical_profile_note_trace_steps
1097 double precision function trace_spherical_profile_time()
result(tnow)
1098 if (.not.trace_spherical_profile_timers)
then
1103 end function trace_spherical_profile_time
1106 integer,
intent(out) :: status
1108 double precision :: bvec(ixg^t,1:3)
1109 integer :: iigrid,igrid,idirmin
1110 integer :: ixi^
l,ixo^
l,ixa^
l
1115 if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
then
1119 if (.not.
b0field .and. .not.
allocated(iw_mag))
then
1125 allocate(trace_spherical_curl_cache(
max_blocks))
1129 if (iximin1>ixamin1 .or. iximax1<ixamax1 .or. &
1130 iximin2>ixamin2 .or. iximax2<ixamax2 .or. &
1131 iximin3>ixamin3 .or. iximax3<ixamax3)
then
1139 allocate(trace_spherical_curl_cache(igrid)%current( &
1140 lbound(ps(igrid)%w,1):ubound(ps(igrid)%w,1), &
1141 lbound(ps(igrid)%w,2):ubound(ps(igrid)%w,2), &
1142 lbound(ps(igrid)%w,3):ubound(ps(igrid)%w,3),1:3))
1143 trace_spherical_curl_cache(igrid)%current=zero
1145 if (
allocated(iw_mag))
then
1146 bvec(:,:,:,1)=ps(igrid)%w(:,:,:,iw_mag(1))
1147 bvec(:,:,:,2)=ps(igrid)%w(:,:,:,iw_mag(2))
1148 bvec(:,:,:,3)=ps(igrid)%w(:,:,:,iw_mag(3))
1153 trace_spherical_curl_cache(igrid)%current,idirmin,1,3)
1155 trace_spherical_curl_cache(igrid)%current(ixo^s,1:3)= &
1156 trace_spherical_curl_cache(igrid)%current(ixo^s,1:3) &
1157 +ps(igrid)%J0(ixo^s,1:3)
1159 trace_spherical_curl_cache(igrid)%ready=.true.
1161 trace_spherical_curl_cache_ready=.true.
1168 if (
allocated(trace_spherical_curl_cache))
then
1169 do igrid=1,
size(trace_spherical_curl_cache)
1170 if (
allocated(trace_spherical_curl_cache(igrid)%current))
then
1171 deallocate(trace_spherical_curl_cache(igrid)%current)
1173 trace_spherical_curl_cache(igrid)%ready=.false.
1175 deallocate(trace_spherical_curl_cache)
1177 trace_spherical_curl_cache_ready=.false.
1183 double precision,
intent(in) :: seed(
ndim),dl
1184 integer,
intent(in) :: max_steps
1186 double precision,
intent(in),
optional :: b_min
1188 if (
present(b_min))
then
1189 call trace_summary_seed(seed,dl,max_steps,result,b_min)
1191 call trace_summary_seed(seed,dl,max_steps,result)
1197 double precision,
intent(in) :: seed(
ndim),dl
1198 integer,
intent(in) :: max_steps
1200 double precision,
intent(in),
optional :: b_min
1202 if (
present(b_min))
then
1203 call trace_summary_twist_seed(seed,dl,max_steps,result,b_min)
1205 call trace_summary_twist_seed(seed,dl,max_steps,result)
1212 double precision,
intent(in) :: seed(
ndim),dl
1213 integer,
intent(in) :: max_steps
1215 double precision,
intent(in),
optional :: b_min
1216 double precision,
intent(in),
optional :: source_normal(3)
1218 if (
present(b_min))
then
1219 if (
present(source_normal))
then
1220 call trace_summary_mapping_seed(seed,dl,max_steps,result,b_min, &
1223 call trace_summary_mapping_seed(seed,dl,max_steps,result,b_min)
1226 if (
present(source_normal))
then
1227 call trace_summary_mapping_seed(seed,dl,max_steps,result, &
1228 source_normal=source_normal)
1230 call trace_summary_mapping_seed(seed,dl,max_steps,result)
1237 double precision,
intent(in) :: seed(
ndim),dl
1238 integer,
intent(in) :: max_steps
1240 double precision,
intent(in),
optional :: b_min
1242 if (
present(b_min))
then
1243 call trace_qperp_single_core(seed,dl,max_steps,result,b_min)
1245 call trace_qperp_single_core(seed,dl,max_steps,result)
1251 double precision,
intent(in) :: seed(
ndim)
1252 double precision,
intent(out) :: bhat(3),grad_bhat(3,3)
1253 integer,
intent(out) :: status
1254 double precision,
intent(in),
optional :: b_min
1257 double precision :: field_min
1271 field_min=smalldouble
1272 if (
present(b_min)) field_min=max(b_min,zero)
1274 call trace_summary_locate_seed(seed,located,igrid)
1275 status=located%forward_status
1278 call sample_bhat_gradbhat_at_point(seed,igrid,field_min,bhat, &
1285 double precision,
intent(in) :: xhit(
ndim)
1286 integer,
intent(in) :: face_id
1287 double precision,
intent(out) :: b(
ndim),bhat(
ndim)
1288 integer,
intent(out) :: status
1289 double precision,
intent(in),
optional :: b_min
1291 double precision :: field_min,xprobe(
ndim),b3(3),bhat3(3)
1292 double precision :: xface,span
1293 integer :: normal_dim,side,igrid
1305 if (.not.trace_face_is_boundary(face_id))
then
1310 field_min=smalldouble
1311 if (
present(b_min)) field_min=max(b_min,zero)
1314 select case(face_id)
1344 span=max(abs(xprobmax1-xprobmin1), &
1345 max(abs(xprobmax2-xprobmin2),abs(xprobmax3-xprobmin3)))
1347 xprobe(normal_dim)=xface-side*1.
d-6*max(one,span)
1348 call trace_debug_locate_point(xprobe,igrid,status)
1351 call trace_sample_b_on_domain_face_limit(xhit,face_id,igrid,field_min, &
1361 grad_current,status_current,bhat_xeps,grad_xeps,status_xeps,b_min)
1363 double precision,
intent(in) :: seed(
ndim),eps
1364 double precision,
intent(out) :: bhat_current(3),grad_current(3,3)
1365 double precision,
intent(out) :: bhat_xeps(3),grad_xeps(3,3)
1366 integer,
intent(out) :: status_current,status_xeps
1367 double precision,
intent(in),
optional :: b_min
1370 double precision :: field_min
1389 field_min=smalldouble
1390 if (
present(b_min)) field_min=max(b_min,zero)
1392 call trace_summary_locate_seed(seed,located,igrid)
1393 status_current=located%forward_status
1395 call sample_bhat_gradbhat_at_point(seed,igrid,field_min, &
1396 bhat_current,grad_current,status_current)
1399 call sample_bhat_gradbhat_xeps_at_point(seed,eps,field_min,bhat_xeps, &
1400 grad_xeps,status_xeps)
1404 grad_current,status_current,bhat_xeps,grad_xeps,status_xeps, &
1405 bhat_interp,grad_interp,status_interp,b_min)
1407 double precision,
intent(in) :: seed(
ndim),eps
1408 double precision,
intent(out) :: bhat_current(3),grad_current(3,3)
1409 double precision,
intent(out) :: bhat_xeps(3),grad_xeps(3,3)
1410 double precision,
intent(out) :: bhat_interp(3),grad_interp(3,3)
1411 integer,
intent(out) :: status_current,status_xeps,status_interp
1412 double precision,
intent(in),
optional :: b_min
1415 double precision :: field_min
1439 field_min=smalldouble
1440 if (
present(b_min)) field_min=max(b_min,zero)
1442 call trace_summary_locate_seed(seed,located,igrid)
1443 status_current=located%forward_status
1444 status_interp=located%forward_status
1446 call sample_bhat_gradbhat_cellfd_at_point(seed,igrid,field_min, &
1447 bhat_current,grad_current,status_current)
1450 call sample_bhat_gradbhat_interpderiv_at_point(seed,igrid,field_min, &
1451 bhat_interp,grad_interp,status_interp)
1454 call sample_bhat_gradbhat_xeps_at_point(seed,eps,field_min,bhat_xeps, &
1455 grad_xeps,status_xeps)
1459 x_end,u_end,v_end,bhat_end,u_perp_end,v_perp_end,status,b_min)
1461 double precision,
intent(in) :: seed(
ndim),u0(
ndim),v0(
ndim),dl
1462 integer,
intent(in) ::
nstep
1463 logical,
intent(in) :: forward
1464 double precision,
intent(out) :: x_end(
ndim),u_end(
ndim),v_end(
ndim)
1465 double precision,
intent(out) :: bhat_end(
ndim)
1466 double precision,
intent(out) :: u_perp_end(
ndim),v_perp_end(
ndim)
1467 integer,
intent(out) :: status
1468 double precision,
intent(in),
optional :: b_min
1470 double precision :: field_min,h,bhat3(3),grad_end(3,3)
1471 integer :: igrid,
istep
1487 else if (dl<=zero .or.
nstep<0)
then
1492 field_min=smalldouble
1493 if (
present(b_min)) field_min=max(b_min,zero)
1495 if (.not.forward) h=-dl
1497 call trace_debug_locate_point(x_end,igrid,status)
1501 call trace_advance_tangent_state_rk2(x_end,u_end,v_end,igrid,h, &
1508 call sample_bhat_gradbhat_at_point(x_end,igrid,field_min,bhat3, &
1515 call trace_project_to_perp_bhat(u_end,bhat_end,u_perp_end)
1516 call trace_project_to_perp_bhat(v_end,bhat_end,v_perp_end)
1520 max_steps,forward,x_end,u_end,v_end,bhat_end,b_end,u_perp_end, &
1521 v_perp_end,u_face_end,v_face_end,length,face_id,status,b_min)
1523 double precision,
intent(in) :: seed(
ndim),u0(
ndim),v0(
ndim),dl
1524 integer,
intent(in) :: max_steps
1525 logical,
intent(in) :: forward
1526 double precision,
intent(out) :: x_end(
ndim),u_end(
ndim),v_end(
ndim)
1527 double precision,
intent(out) :: bhat_end(
ndim),b_end(
ndim)
1528 double precision,
intent(out) :: u_perp_end(
ndim),v_perp_end(
ndim)
1529 double precision,
intent(out) :: u_face_end(
ndim),v_face_end(
ndim)
1530 double precision,
intent(out) :: length
1531 integer,
intent(out) :: face_id,status
1532 double precision,
intent(in),
optional :: b_min
1534 double precision :: field_min,h,h_partial,partial_length
1538 integer :: igrid,igrid_trial,
istep,point_domain
1560 else if (dl<=zero .or. max_steps<0)
then
1565 field_min=smalldouble
1566 if (
present(b_min)) field_min=max(b_min,zero)
1568 if (.not.forward) h=-dl
1570 call trace_debug_locate_point(x_end,igrid,status)
1573 do istep=1,max_steps
1578 call trace_tangent_rhs(xold,uold,vold,igrid,field_min,kx1,ku1,kv1, &
1584 {
if (xprobe(^db)>=xprobmin^db .and. xprobe(^db)<xprobmax^db) point_domain=point_domain+1\}
1585 if (point_domain/=
ndim)
then
1586 call trace_intersect_domain(xold,xprobe,xhit,hit_ok,face_id)
1587 if (.not.hit_ok)
then
1588 call trace_boundary_face_at_point(xold,face_id,hit_ok)
1589 if (.not.hit_ok)
then
1600 partial_length=dsqrt(sum((xhit-xold)**2))
1601 if (partial_length<=100.d0*epsilon(one)*max(one,abs(h)))
then
1608 h_partial=sign(partial_length,h)
1609 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold,igrid, &
1610 h_partial,field_min,kx1,ku1,kv1,xtrial,utrial,vtrial,status)
1615 length=length+partial_length
1620 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold,igrid,h, &
1621 field_min,kx1,ku1,kv1,xtrial,utrial,vtrial,status)
1625 {
if (xtrial(^db)>=xprobmin^db .and. xtrial(^db)<xprobmax^db) point_domain=point_domain+1\}
1626 if (point_domain==
ndim)
then
1627 call trace_locate_point_with_hint(xtrial,igrid,igrid_trial,status)
1633 length=length+abs(h)
1635 call trace_intersect_domain(xold,xtrial,xhit,hit_ok,face_id)
1636 if (.not.hit_ok)
then
1637 call trace_boundary_face_at_point(xold,face_id,hit_ok)
1638 if (.not.hit_ok)
then
1649 partial_length=dsqrt(sum((xhit-xold)**2))
1650 if (partial_length<=100.d0*epsilon(one)*max(one,abs(h)))
then
1657 h_partial=sign(partial_length,h)
1658 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold,igrid, &
1659 h_partial,field_min,kx1,ku1,kv1,xtrial,utrial,vtrial,status)
1664 length=length+partial_length
1676 call trace_endpoint_b_bhat(x_end,face_id,igrid,field_min,b_end, &
1680 call trace_project_to_perp_bhat(u_end,bhat_end,u_perp_end)
1681 call trace_project_to_perp_bhat(v_end,bhat_end,v_perp_end)
1682 call trace_project_to_boundary_face(u_end,bhat_end,face_id,u_face_end)
1683 call trace_project_to_boundary_face(v_end,bhat_end,face_id,v_face_end)
1687 x_f,x_b,u_f_perp,v_f_perp,u_b_perp,v_b_perp,b_seed,b_f,b_b, &
1688 length_f,length_b,face_f,face_b,status,N2,bfactor,b_min)
1690 double precision,
intent(in) :: seed(
ndim),dl
1691 integer,
intent(in) :: max_steps
1692 double precision,
intent(out) :: qperp,logqperp,n2,bfactor
1693 double precision,
intent(out) :: x_f(
ndim),x_b(
ndim)
1694 double precision,
intent(out) :: u_f_perp(
ndim),v_f_perp(
ndim)
1695 double precision,
intent(out) :: u_b_perp(
ndim),v_b_perp(
ndim)
1696 double precision,
intent(out) :: b_seed(
ndim),b_f(
ndim),b_b(
ndim)
1697 double precision,
intent(out) :: length_f,length_b
1698 integer,
intent(out) :: face_f,face_b,status
1699 double precision,
intent(in),
optional :: b_min
1703 if (
present(b_min))
then
1710 logqperp=result%logqperp
1712 bfactor=result%bfactor
1713 x_f=result%forward_endpoint
1714 x_b=result%backward_endpoint
1715 u_f_perp=result%u_forward_perp
1716 v_f_perp=result%v_forward_perp
1717 u_b_perp=result%u_backward_perp
1718 v_b_perp=result%v_backward_perp
1719 b_seed=result%B_seed
1720 b_f=result%forward_B
1721 b_b=result%backward_B
1722 length_f=result%forward_length
1723 length_b=result%backward_length
1724 face_f=result%forward_face
1725 face_b=result%backward_face
1726 status=result%status
1729 subroutine trace_init_qperp_result(seed,result)
1730 double precision,
intent(in) :: seed(
ndim)
1734 result%qperp=trace_debug_nan()
1735 result%logqperp=trace_debug_nan()
1736 result%N2=trace_debug_nan()
1737 result%bfactor=trace_debug_nan()
1738 result%q0=trace_debug_nan()
1739 result%logq0=trace_debug_nan()
1740 result%qperp0=trace_debug_nan()
1741 result%logqperp0=trace_debug_nan()
1742 result%N2_qperp0=trace_debug_nan()
1743 result%bfactor_qperp0=trace_debug_nan()
1744 result%forward_Bn_q0=trace_debug_nan()
1745 result%backward_Bn_q0=trace_debug_nan()
1747 result%bhat_seed=zero
1748 result%forward_endpoint=seed
1749 result%backward_endpoint=seed
1750 result%forward_B=zero
1751 result%backward_B=zero
1752 result%forward_bhat=zero
1753 result%backward_bhat=zero
1754 result%forward_length=zero
1755 result%backward_length=zero
1756 result%forward_nstep=0
1757 result%backward_nstep=0
1760 result%u_forward_perp=zero
1761 result%v_forward_perp=zero
1762 result%u_backward_perp=zero
1763 result%v_backward_perp=zero
1771 result%valid=.false.
1772 result%valid_q0=.false.
1773 result%valid_qperp0=.false.
1774 end subroutine trace_init_qperp_result
1776 subroutine trace_qperp_single_core(seed,dL,max_steps,result,b_min)
1777 double precision,
intent(in) :: seed(
ndim),dl
1778 integer,
intent(in) :: max_steps
1780 double precision,
intent(in),
optional :: b_min
1782 double precision :: field_min,b3(3),bseed_norm
1784 integer :: igrid,status,indomain
1786 call trace_init_qperp_result(seed,result)
1791 else if (
ndim/=3 .or. .not.trace_cartesian_like_geometry())
then
1794 else if (dl<=zero .or. max_steps<=0)
then
1800 {
if (seed(^db)>=xprobmin^db .and. seed(^db)<xprobmax^db) indomain=indomain+1\}
1801 if (indomain/=
ndim)
then
1806 field_min=smalldouble
1807 if (
present(b_min)) field_min=max(b_min,zero)
1809 call trace_debug_locate_point(seed,igrid,status)
1811 result%status=status
1814 call sample_b_at_point(seed,igrid,field_min,b3,status)
1816 result%status=status
1819 result%B_seed=b3(1:
ndim)
1820 bseed_norm=dsqrt(sum(result%B_seed**2))
1821 if (bseed_norm<=zero .or. bseed_norm<field_min)
then
1825 result%bhat_seed=result%B_seed/bseed_norm
1826 call trace_make_perp_basis(b3/bseed_norm,result%u0,result%v0,status)
1828 result%status=status
1833 result%v0,dl,max_steps,.true.,result%forward_endpoint,u_end, &
1834 v_end,result%forward_bhat,result%forward_B,result%u_forward_perp, &
1835 result%v_forward_perp,u_face,v_face,result%forward_length, &
1836 result%forward_face,status,b_min=field_min)
1837 result%forward_status=status
1839 result%status=status
1844 result%v0,dl,max_steps,.false.,result%backward_endpoint,u_end, &
1845 v_end,result%backward_bhat,result%backward_B,result%u_backward_perp, &
1846 result%v_backward_perp,u_face,v_face,result%backward_length, &
1847 result%backward_face,status,b_min=field_min)
1848 result%backward_status=status
1850 result%status=status
1854 call trace_qperp_compute_scalars(result,field_min)
1855 end subroutine trace_qperp_single_core
1857 subroutine trace_tangent_state_init(seed,u0,v0,igrid,seed_id,direction, &
1858 state,accumulate_twist)
1859 double precision,
intent(in) :: seed(
ndim),u0(
ndim),v0(
ndim)
1860 integer,
intent(in) :: igrid,seed_id,direction
1861 type(trace_tangent_state),
intent(out) :: state
1862 logical,
intent(in),
optional :: accumulate_twist
1864 state%seed_id=seed_id
1865 state%direction=direction
1867 state%complete=.false.
1868 state%has_extra=.false.
1882 state%endpoint_B=zero
1883 state%endpoint_bhat=zero
1889 state%accumulate_twist=.false.
1890 if (
present(accumulate_twist)) state%accumulate_twist=accumulate_twist
1891 state%sph_cache%valid=.false.
1892 if (trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical)
then
1893 call trace_spherical_profile_add_count(trace_profile_directions,1_8)
1894 call trace_spherical_profile_add_count(trace_profile_tangent_systems,1_8)
1896 end subroutine trace_tangent_state_init
1898 subroutine trace_tangent_trace_states_grouped(states,nstate,dL,max_steps, &
1899 threshold,trace_mode)
1903 integer,
intent(in) :: nstate,max_steps
1904 integer,
intent(in),
optional :: trace_mode
1905 type(trace_tangent_state),
intent(inout) :: states(nstate)
1906 double precision,
intent(in) :: dl,threshold
1908 logical,
allocatable :: processed(:)
1909 double precision :: t0,tgroup0,tgroup1
1910 integer :: active_count,group_size,istate,jstate,target_grid,group_mode
1911 logical :: any_active
1912 logical :: profile_tangent
1914 group_mode=trace_tangent_group_rk2_general
1915 if (
present(trace_mode)) group_mode=trace_mode
1916 profile_tangent=(group_mode/=trace_tangent_group_rk45_cartesian .and. &
1917 trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical)
1918 if (profile_tangent) t0=trace_spherical_profile_time()
1920 if (trace_cartesian_like_geometry())
then
1925 if (trace_rk2_stats_enabled)
call cpu_time(tgroup0)
1930 if (states(istate)%active)
then
1932 active_count=active_count+1
1935 if (.not.any_active)
exit
1936 call trace_rk2_stats_note_group_iteration()
1937 call trace_rk2_stats_note_grid_group(active_count)
1940 if (.not.states(jstate)%active) cycle
1941 select case (group_mode)
1942 case (trace_tangent_group_rk2_general)
1943 call trace_tangent_state_advance_in_grid(states(jstate), &
1944 states(jstate)%igrid,dl,max_steps,threshold)
1945 case (trace_tangent_group_rk2_short_boundary)
1946 call trace_tangent_state_advance_in_grid(states(jstate), &
1947 states(jstate)%igrid,dl,max_steps,threshold, &
1948 short_boundary=.true.)
1949 case (trace_tangent_group_rk45_cartesian)
1950 call trace_tangent_state_advance_in_grid_rk45_cartesian( &
1951 states(jstate),states(jstate)%igrid,dl,max_steps,threshold)
1954 states(jstate)%active=.false.
1955 states(jstate)%complete=.true.
1960 if (trace_rk2_stats_enabled)
then
1961 call cpu_time(tgroup1)
1962 call trace_rk2_stats_add_grouped_time(tgroup1-tgroup0)
1967 if (trace_rk2_stats_enabled)
call cpu_time(tgroup0)
1968 allocate(processed(nstate))
1972 if (states(istate)%active)
then
1977 if (.not.any_active)
exit
1978 call trace_rk2_stats_note_group_iteration()
1982 if (.not.states(istate)%active .or. processed(istate)) cycle
1983 target_grid=states(istate)%igrid
1984 if (trace_rk2_stats_enabled)
then
1987 if (states(jstate)%active .and. .not.processed(jstate) .and. &
1988 states(jstate)%igrid==target_grid) group_size=group_size+1
1990 call trace_rk2_stats_note_grid_group(group_size)
1994 if (.not.states(jstate)%active .or. processed(jstate)) cycle
1995 if (states(jstate)%igrid/=target_grid) cycle
1996 select case (group_mode)
1997 case (trace_tangent_group_rk2_general)
1998 call trace_tangent_state_advance_in_grid(states(jstate), &
1999 target_grid,dl,max_steps,threshold)
2000 case (trace_tangent_group_rk2_short_boundary)
2001 call trace_tangent_state_advance_in_grid(states(jstate), &
2002 target_grid,dl,max_steps,threshold,short_boundary=.true.)
2003 case (trace_tangent_group_rk45_cartesian)
2004 call trace_tangent_state_advance_in_grid_rk45_cartesian( &
2005 states(jstate),target_grid,dl,max_steps,threshold)
2008 states(jstate)%active=.false.
2009 states(jstate)%complete=.true.
2011 processed(jstate)=.true.
2016 deallocate(processed)
2017 if (trace_rk2_stats_enabled)
then
2018 call cpu_time(tgroup1)
2019 call trace_rk2_stats_add_grouped_time(tgroup1-tgroup0)
2021 if (profile_tangent)
call trace_spherical_profile_add_time( &
2022 trace_profile_time_tangent,trace_spherical_profile_time()-t0)
2023 end subroutine trace_tangent_trace_states_grouped
2025 subroutine trace_tangent_state_advance_in_grid_rk45_cartesian(state, &
2026 igrid,dL,max_steps,threshold)
2027 type(trace_tangent_state),
intent(inout) :: state
2028 integer,
intent(in) :: igrid,max_steps
2029 double precision,
intent(in) :: dl,threshold
2033 if (.not.state%active)
return
2035 do while(state%active .and. state%igrid==igrid .and. &
2036 state%nstep<max_steps)
2037 call trace_tangent_rk45_cartesian_step(state,dl,threshold,status)
2040 state%active=.false.
2041 state%complete=.true.
2046 if (state%active .and. state%nstep>=max_steps)
then
2048 state%active=.false.
2049 state%complete=.true.
2051 end subroutine trace_tangent_state_advance_in_grid_rk45_cartesian
2053 subroutine trace_tangent_rk45_cartesian_step(state,dL,threshold,status)
2054 type(trace_tangent_state),
intent(inout) :: state
2055 double precision,
intent(in) :: dl,threshold
2056 integer,
intent(out) :: status
2058 double precision,
parameter :: b21=1.d0/5.d0
2059 double precision,
parameter :: b31=3.d0/40.d0,b32=9.d0/40.d0
2060 double precision,
parameter :: b41=3.d0/10.d0,b42=-9.d0/10.d0, &
2062 double precision,
parameter :: b51=-11.d0/54.d0,b52=5.d0/2.d0, &
2063 b53=-70.d0/27.d0,b54=35.d0/27.d0
2064 double precision,
parameter :: b61=1631.d0/55296.d0, &
2065 b62=175.d0/512.d0,b63=575.d0/13824.d0, &
2066 b64=44275.d0/110592.d0,b65=253.d0/4096.d0
2067 double precision,
parameter :: c1=37.d0/378.d0,c3=250.d0/621.d0, &
2068 c4=125.d0/594.d0,c6=512.d0/1771.d0
2069 double precision,
parameter :: cs1=2825.d0/27648.d0, &
2070 cs3=18575.d0/48384.d0,cs4=13525.d0/55296.d0, &
2071 cs5=277.d0/14336.d0,cs6=one/4.d0
2075 double precision :: kx5(
ndim),kx6(
ndim)
2077 double precision :: ku5(
ndim),ku6(
ndim)
2079 double precision :: kv5(
ndim),kv6(
ndim)
2083 double precision :: x5sol(
ndim),x4err(
ndim)
2084 double precision :: u5sol(
ndim),v5sol(
ndim)
2085 double precision :: u4err(
ndim),v4err(
ndim)
2086 double precision :: h,hmax,hfloor,hcell,tol,err,grow,hsigned
2087 double precision :: pos_err_ratio,u_err_ratio,v_err_ratio
2088 double precision :: tan_err_ratio,control_ratio
2089 double precision :: tw1,tw3,tw4,tw6,twist_increment
2090 double precision :: dxb^
d
2091 integer :: igrid1,igrid2,igrid3,igrid4,igrid5,igrid6
2092 integer :: iter,point_domain,reject_reason,twist_status
2093 logical :: boundary_finished,pos_ok,tan_ok
2096 if (.not.trace_cartesian_like_geometry())
then
2109 hmax=abs(trace_effective_step(xold,dl,state%igrid,dxb^
d))
2110 if (hmax<=zero)
then
2117 hfloor=max(trace_step_min,100.d0*epsilon(one)*max(one,hmax))
2121 h=max(hfloor,min(h,hmax))
2123 if (state%direction<0) hsigned=-h
2125 call trace_tangent_rhs_cartesian_located(xold,uold,vold, &
2126 state%igrid,threshold,kx1,ku1,kv1,igrid1,status)
2129 x2=xold+hsigned*b21*kx1
2130 u2=uold+hsigned*b21*ku1
2131 v2=vold+hsigned*b21*kv1
2132 call trace_tangent_rhs_cartesian_located(x2,u2,v2,igrid1, &
2133 threshold,kx2,ku2,kv2,igrid2,status)
2136 call trace_tangent_rk45_cartesian_finish_boundary(state,xold,uold, &
2137 vold,x2,hsigned,threshold,kx1,ku1,kv1,status, &
2139 if (boundary_finished)
return
2140 reject_reason=trace_rk45_reject_stage_failure
2143 reject_reason=trace_rk45_reject_stage_outside
2144 if (trace_rk45_stats_enabled) &
2145 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
2147 if (h<=hfloor*(one+epsilon(one)))
exit
2148 h=max(hfloor,half*h)
2152 x3=xold+hsigned*(b31*kx1+b32*kx2)
2153 u3=uold+hsigned*(b31*ku1+b32*ku2)
2154 v3=vold+hsigned*(b31*kv1+b32*kv2)
2155 call trace_tangent_rhs_cartesian_located(x3,u3,v3,igrid2, &
2156 threshold,kx3,ku3,kv3,igrid3,status)
2159 call trace_tangent_rk45_cartesian_finish_boundary(state,xold,uold, &
2160 vold,x3,hsigned,threshold,kx1,ku1,kv1,status, &
2162 if (boundary_finished)
return
2163 reject_reason=trace_rk45_reject_stage_failure
2166 reject_reason=trace_rk45_reject_stage_outside
2167 if (trace_rk45_stats_enabled) &
2168 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
2170 if (h<=hfloor*(one+epsilon(one)))
exit
2171 h=max(hfloor,half*h)
2175 x4=xold+hsigned*(b41*kx1+b42*kx2+b43*kx3)
2176 u4=uold+hsigned*(b41*ku1+b42*ku2+b43*ku3)
2177 v4=vold+hsigned*(b41*kv1+b42*kv2+b43*kv3)
2178 call trace_tangent_rhs_cartesian_located(x4,u4,v4,igrid3, &
2179 threshold,kx4,ku4,kv4,igrid4,status)
2182 call trace_tangent_rk45_cartesian_finish_boundary(state,xold,uold, &
2183 vold,x4,hsigned,threshold,kx1,ku1,kv1,status, &
2185 if (boundary_finished)
return
2186 reject_reason=trace_rk45_reject_stage_failure
2189 reject_reason=trace_rk45_reject_stage_outside
2190 if (trace_rk45_stats_enabled) &
2191 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
2193 if (h<=hfloor*(one+epsilon(one)))
exit
2194 h=max(hfloor,half*h)
2198 x5s=xold+hsigned*(b51*kx1+b52*kx2+b53*kx3+b54*kx4)
2199 u5s=uold+hsigned*(b51*ku1+b52*ku2+b53*ku3+b54*ku4)
2200 v5s=vold+hsigned*(b51*kv1+b52*kv2+b53*kv3+b54*kv4)
2201 call trace_tangent_rhs_cartesian_located(x5s,u5s,v5s,igrid4, &
2202 threshold,kx5,ku5,kv5,igrid5,status)
2205 call trace_tangent_rk45_cartesian_finish_boundary(state,xold,uold, &
2206 vold,x5s,hsigned,threshold,kx1,ku1,kv1,status, &
2208 if (boundary_finished)
return
2209 reject_reason=trace_rk45_reject_stage_failure
2212 reject_reason=trace_rk45_reject_stage_outside
2213 if (trace_rk45_stats_enabled) &
2214 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
2216 if (h<=hfloor*(one+epsilon(one)))
exit
2217 h=max(hfloor,half*h)
2221 x6=xold+hsigned*(b61*kx1+b62*kx2+b63*kx3+b64*kx4+b65*kx5)
2222 u6=uold+hsigned*(b61*ku1+b62*ku2+b63*ku3+b64*ku4+b65*ku5)
2223 v6=vold+hsigned*(b61*kv1+b62*kv2+b63*kv3+b64*kv4+b65*kv5)
2224 call trace_tangent_rhs_cartesian_located(x6,u6,v6,igrid5, &
2225 threshold,kx6,ku6,kv6,igrid6,status)
2228 call trace_tangent_rk45_cartesian_finish_boundary(state,xold,uold, &
2229 vold,x6,hsigned,threshold,kx1,ku1,kv1,status, &
2231 if (boundary_finished)
return
2232 reject_reason=trace_rk45_reject_stage_failure
2235 reject_reason=trace_rk45_reject_stage_outside
2236 if (trace_rk45_stats_enabled) &
2237 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
2239 if (h<=hfloor*(one+epsilon(one)))
exit
2240 h=max(hfloor,half*h)
2244 x5sol=xold+hsigned*(c1*kx1+c3*kx3+c4*kx4+c6*kx6)
2245 u5sol=uold+hsigned*(c1*ku1+c3*ku3+c4*ku4+c6*ku6)
2246 v5sol=vold+hsigned*(c1*kv1+c3*kv3+c4*kv4+c6*kv6)
2247 x4err=xold+hsigned*(cs1*kx1+cs3*kx3+cs4*kx4+ &
2249 u4err=uold+hsigned*(cs1*ku1+cs3*ku3+cs4*ku4+ &
2251 v4err=vold+hsigned*(cs1*kv1+cs3*kv3+cs4*kv4+ &
2255 {
if (x5sol(^db)>=xprobmin^db .and. x5sol(^db)<xprobmax^db) point_domain=point_domain+1\}
2256 if (point_domain/=
ndim)
then
2257 call trace_tangent_rk45_cartesian_finish_boundary(state,xold,uold, &
2258 vold,x5sol,hsigned,threshold,kx1,ku1,kv1,status, &
2260 if (boundary_finished)
return
2261 if (trace_rk45_stats_enabled) &
2262 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
2263 trace_rk45_reject_boundary)
2268 call trace_cartesian_local_cell_size(xold,igrid1,hcell,status)
2270 err=dsqrt(sum((x5sol-x4err)**2))
2271 tol=trace_rk45_atol+trace_rk45_rtol*max(h,hcell)
2273 pos_err_ratio=err/tol
2277 u_err_ratio=dsqrt(sum((u5sol-u4err)**2))/ &
2278 max(dsqrt(sum(u5sol**2)),trace_rk45_tangent_floor)
2279 v_err_ratio=dsqrt(sum((v5sol-v4err)**2))/ &
2280 max(dsqrt(sum(v5sol**2)),trace_rk45_tangent_floor)
2281 tan_err_ratio=max(u_err_ratio,v_err_ratio)
2282 if (trace_rk45_stats_enabled) &
2283 call trace_rk45_stats_note_tangent_error(pos_err_ratio, &
2284 u_err_ratio,v_err_ratio)
2286 tan_ok=(tan_err_ratio<=trace_rk45_tangent_rtol)
2287 if ((pos_ok .and. tan_ok) .or. h<=hfloor*(one+epsilon(one)))
then
2288 if (state%accumulate_twist .and. &
2291 call trace_twist_density_at_point(xold,igrid1,threshold,tw1, &
2294 call trace_twist_density_at_point(x3,igrid3,threshold,tw3, &
2297 call trace_twist_density_at_point(x4,igrid4,threshold,tw4, &
2300 call trace_twist_density_at_point(x6,igrid6,threshold,tw6, &
2303 twist_increment=h*(c1*tw1+c3*tw3+c4*tw4+c6*tw6)
2304 state%twist=state%twist+twist_increment
2306 state%twist_status=twist_status
2312 state%length=state%length+h
2313 state%nstep=state%nstep+1
2314 call trace_locate_point_with_hint(state%x,igrid6,state%igrid,status)
2316 control_ratio=max(pos_err_ratio, &
2317 tan_err_ratio/trace_rk45_tangent_rtol)
2318 if (control_ratio>zero)
then
2319 grow=trace_rk45_safety*(one/control_ratio)**0.2d0
2320 grow=max(trace_rk45_min_shrink,min(trace_rk45_max_grow,grow))
2322 grow=trace_rk45_max_grow
2324 state%rk45_h=min(hmax,max(hfloor,h*grow))
2325 if (trace_rk45_stats_enabled) &
2326 call trace_rk45_stats_note_attempt(.true.,.false.,h)
2331 if (.not.pos_ok)
then
2332 grow=trace_rk45_safety*(tol/max(err,smalldouble))**0.25d0
2333 if (trace_rk45_stats_enabled) &
2334 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
2335 trace_rk45_reject_error)
2337 grow=trace_rk45_safety*(trace_rk45_tangent_rtol/ &
2338 max(tan_err_ratio,smalldouble))**0.25d0
2339 if (trace_rk45_stats_enabled) &
2340 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
2341 trace_rk45_reject_tangent_error)
2343 grow=max(trace_rk45_min_shrink,min(one,grow))
2344 h=max(hfloor,h*grow)
2347 call trace_tangent_rk45_cartesian_finish_boundary(state,xold,uold, &
2348 vold,xold+hsigned*kx1,hsigned,threshold,kx1,ku1,kv1,status, &
2351 end subroutine trace_tangent_rk45_cartesian_step
2353 subroutine trace_tangent_rhs_cartesian_located(x,u,v,igrid_hint, &
2354 threshold,kx,ku,kv,igrid,status)
2355 double precision,
intent(in) :: x(
ndim),u(
ndim),v(
ndim),threshold
2356 integer,
intent(in) :: igrid_hint
2357 double precision,
intent(out) :: kx(
ndim),ku(
ndim),kv(
ndim)
2358 integer,
intent(out) :: igrid,status
2365 if (.not.trace_cartesian_like_geometry())
return
2367 call trace_locate_point_with_hint(x,igrid_hint,igrid,status)
2369 call trace_tangent_rhs(x,u,v,igrid,threshold,kx,ku,kv,status)
2370 end subroutine trace_tangent_rhs_cartesian_located
2372 subroutine trace_tangent_rk45_cartesian_finish_boundary(state,xold,uold, &
2373 vold,xstage,hsigned,threshold,kx1,ku1,kv1,status,finished)
2374 type(trace_tangent_state),
intent(inout) :: state
2375 double precision,
intent(in) :: xold(
ndim),uold(
ndim),vold(
ndim)
2376 double precision,
intent(in) :: xstage(
ndim),hsigned,threshold
2377 double precision,
intent(in) :: kx1(
ndim),ku1(
ndim),kv1(
ndim)
2378 integer,
intent(out) :: status
2379 logical,
intent(out) :: finished
2381 double precision :: xhit(
ndim),utrial(
ndim),vtrial(
ndim)
2382 double precision :: xtrial(
ndim),partial_length,h_partial
2386 call trace_intersect_domain(xold,xstage,xhit,hit_ok,state%face_id)
2387 if (.not.hit_ok)
return
2389 partial_length=dsqrt(sum((xhit-xold)**2))
2390 if (partial_length>100.d0*epsilon(one)*max(one,abs(hsigned)))
then
2391 h_partial=sign(partial_length,hsigned)
2392 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold,state%igrid, &
2393 h_partial,threshold,kx1,ku1,kv1,xtrial,utrial,vtrial,status)
2395 call trace_tangent_accumulate_twist(state,xhit,partial_length, &
2399 state%length=state%length+partial_length
2400 state%nstep=state%nstep+1
2408 state%active=.false.
2409 state%complete=.true.
2411 call trace_tangent_state_finalize_boundary(state,threshold)
2412 call trace_rk45_stats_note_attempt(.true.,.true.,partial_length)
2415 end subroutine trace_tangent_rk45_cartesian_finish_boundary
2417 subroutine trace_tangent_trace_states_grouped_rk45_spherical(states, &
2418 nstate,dL,max_steps,threshold)
2419 integer,
intent(in) :: nstate,max_steps
2420 type(trace_tangent_state),
intent(inout) :: states(nstate)
2421 double precision,
intent(in) :: dl,threshold
2423 logical,
allocatable :: processed(:)
2424 integer :: istate,jstate,target_grid
2425 logical :: any_active
2427 allocate(processed(nstate))
2431 if (states(istate)%active)
then
2436 if (.not.any_active)
exit
2440 if (.not.states(istate)%active .or. processed(istate)) cycle
2441 target_grid=states(istate)%igrid
2444 if (.not.states(jstate)%active .or. processed(jstate)) cycle
2445 if (states(jstate)%igrid/=target_grid) cycle
2446 call trace_tangent_state_advance_in_grid_rk45_spherical( &
2447 states(jstate),target_grid,dl,max_steps,threshold)
2448 processed(jstate)=.true.
2453 deallocate(processed)
2454 end subroutine trace_tangent_trace_states_grouped_rk45_spherical
2456 subroutine trace_tangent_state_advance_in_grid_rk45_spherical(state, &
2457 igrid,dL,max_steps,threshold)
2458 type(trace_tangent_state),
intent(inout) :: state
2459 integer,
intent(in) :: igrid,max_steps
2460 double precision,
intent(in) :: dl,threshold
2464 if (.not.state%active)
return
2466 do while(state%active .and. state%igrid==igrid .and. &
2467 state%nstep<max_steps)
2468 call trace_tangent_rk45_spherical_step(state,dl,threshold,status)
2471 state%active=.false.
2472 state%complete=.true.
2477 if (state%active .and. state%nstep>=max_steps)
then
2479 state%active=.false.
2480 state%complete=.true.
2482 if ((.not.state%active) .and. trace_spherical_profile_enabled .and. &
2483 geo_coordinate==geo_spherical)
then
2484 call trace_spherical_profile_note_trace_steps(state%nstep)
2486 end subroutine trace_tangent_state_advance_in_grid_rk45_spherical
2488 subroutine trace_tangent_rk45_spherical_step(state,dL,threshold,status)
2489 type(trace_tangent_state),
intent(inout) :: state
2490 double precision,
intent(in) :: dl,threshold
2491 integer,
intent(out) :: status
2493 double precision,
parameter :: b21=1.d0/5.d0
2494 double precision,
parameter :: b31=3.d0/40.d0,b32=9.d0/40.d0
2495 double precision,
parameter :: b41=3.d0/10.d0,b42=-9.d0/10.d0, &
2497 double precision,
parameter :: b51=-11.d0/54.d0,b52=5.d0/2.d0, &
2498 b53=-70.d0/27.d0,b54=35.d0/27.d0
2499 double precision,
parameter :: b61=1631.d0/55296.d0, &
2500 b62=175.d0/512.d0,b63=575.d0/13824.d0, &
2501 b64=44275.d0/110592.d0,b65=253.d0/4096.d0
2502 double precision,
parameter :: c1=37.d0/378.d0,c3=250.d0/621.d0, &
2503 c4=125.d0/594.d0,c6=512.d0/1771.d0
2504 double precision,
parameter :: cs1=2825.d0/27648.d0, &
2505 cs3=18575.d0/48384.d0,cs4=13525.d0/55296.d0, &
2506 cs5=277.d0/14336.d0,cs6=one/4.d0
2509 double precision :: pold(
ndim),qold(
ndim)
2511 double precision :: kx5(
ndim),kx6(
ndim)
2513 double precision :: ku5(
ndim),ku6(
ndim)
2515 double precision :: kv5(
ndim),kv6(
ndim)
2517 double precision :: kp5(
ndim),kp6(
ndim)
2519 double precision :: kq5(
ndim),kq6(
ndim)
2525 double precision :: x5sol(
ndim),x4err(
ndim)
2526 double precision :: u5sol(
ndim),v5sol(
ndim)
2527 double precision :: u4err(
ndim),v4err(
ndim)
2528 double precision :: p5sol(
ndim),q5sol(
ndim)
2529 double precision :: p4err(
ndim),q4err(
ndim)
2530 double precision :: h,hmax,hfloor,hcell,tol,err,grow,hsigned
2531 double precision :: pos_err_ratio,u_err_ratio,v_err_ratio
2532 double precision :: p_err_ratio,q_err_ratio
2533 double precision :: tan_err_ratio,control_ratio
2534 double precision :: tw1,tw3,tw4,tw6,twist_increment
2535 double precision :: r_metric,sin_theta_metric
2536 double precision :: domain_min(
ndim),domain_max(
ndim)
2537 type(trace_sph_interp_ctx) :: ctx1,ctx2,ctx3,ctx4,ctx5,ctx6
2538 integer :: igrid1,igrid2,igrid3,igrid4,igrid5,igrid6
2539 integer :: iter,point_domain,ctx_status,reject_reason,twist_status
2540 logical :: boundary_finished,pos_ok,tan_ok
2543 if (geo_coordinate/=geo_spherical)
then
2557 call trace_spherical_interp_ctx_build_cached(xold,state%igrid, &
2558 state%sph_cache,ctx1,ctx_status)
2563 hmax=abs(trace_spherical_effective_step_ctx(dl,ctx1))
2565 if (hmax<=zero)
then
2572 hfloor=max(trace_step_min,100.d0*epsilon(one)*max(one,hmax))
2574 ^
d&domain_min(^
d)=xprobmin^
d;
2575 ^
d&domain_max(^
d)=xprobmax^
d;
2578 h=max(hfloor,min(h,hmax))
2580 if (state%direction<0) hsigned=-h
2582 if (state%has_extra)
then
2583 call trace_tangent_rhs(xold,uold,vold,ctx1%igrid,threshold,kx1, &
2584 ku1,kv1,status,pold,qold,kp1,kq1,sph_ctx=ctx1)
2586 call trace_tangent_rhs(xold,uold,vold,ctx1%igrid,threshold,kx1, &
2587 ku1,kv1,status,sph_ctx=ctx1)
2592 x2=xold+hsigned*b21*kx1
2593 u2=uold+hsigned*b21*ku1
2594 v2=vold+hsigned*b21*kv1
2595 if (state%has_extra)
then
2596 p2=pold+hsigned*b21*kp1
2597 q2=qold+hsigned*b21*kq1
2599 call trace_spherical_interp_ctx_build_cached(x2,igrid1, &
2600 state%sph_cache,ctx2,ctx_status)
2602 call trace_tangent_rk45_spherical_finish_boundary(state,xold,uold, &
2603 vold,x2,hsigned,threshold,kx1,ku1,kv1,status, &
2604 boundary_finished,pold,qold,kp1,kq1)
2605 if (boundary_finished)
return
2606 reject_reason=trace_rk45_reject_stage_failure
2609 reject_reason=trace_rk45_reject_stage_outside
2610 call trace_rk45_stats_note_attempt(.false.,.false.,h,reject_reason)
2611 if (h<=hfloor*(one+epsilon(one)))
exit
2612 h=max(hfloor,half*h)
2615 if (state%has_extra)
then
2616 call trace_tangent_rhs(x2,u2,v2,ctx2%igrid,threshold,kx2,ku2, &
2617 kv2,status,p2,q2,kp2,kq2,sph_ctx=ctx2)
2619 call trace_tangent_rhs(x2,u2,v2,ctx2%igrid,threshold,kx2,ku2, &
2620 kv2,status,sph_ctx=ctx2)
2625 x3=xold+hsigned*(b31*kx1+b32*kx2)
2626 u3=uold+hsigned*(b31*ku1+b32*ku2)
2627 v3=vold+hsigned*(b31*kv1+b32*kv2)
2628 if (state%has_extra)
then
2629 p3=pold+hsigned*(b31*kp1+b32*kp2)
2630 q3=qold+hsigned*(b31*kq1+b32*kq2)
2632 call trace_spherical_interp_ctx_build_cached(x3,igrid2, &
2633 state%sph_cache,ctx3,ctx_status)
2635 call trace_tangent_rk45_spherical_finish_boundary(state,xold,uold, &
2636 vold,x3,hsigned,threshold,kx1,ku1,kv1,status, &
2637 boundary_finished,pold,qold,kp1,kq1)
2638 if (boundary_finished)
return
2639 reject_reason=trace_rk45_reject_stage_failure
2642 reject_reason=trace_rk45_reject_stage_outside
2643 call trace_rk45_stats_note_attempt(.false.,.false.,h,reject_reason)
2644 if (h<=hfloor*(one+epsilon(one)))
exit
2645 h=max(hfloor,half*h)
2648 if (state%has_extra)
then
2649 call trace_tangent_rhs(x3,u3,v3,ctx3%igrid,threshold,kx3,ku3, &
2650 kv3,status,p3,q3,kp3,kq3,sph_ctx=ctx3)
2652 call trace_tangent_rhs(x3,u3,v3,ctx3%igrid,threshold,kx3,ku3, &
2653 kv3,status,sph_ctx=ctx3)
2658 x4=xold+hsigned*(b41*kx1+b42*kx2+b43*kx3)
2659 u4=uold+hsigned*(b41*ku1+b42*ku2+b43*ku3)
2660 v4=vold+hsigned*(b41*kv1+b42*kv2+b43*kv3)
2661 if (state%has_extra)
then
2662 p4=pold+hsigned*(b41*kp1+b42*kp2+b43*kp3)
2663 q4=qold+hsigned*(b41*kq1+b42*kq2+b43*kq3)
2665 call trace_spherical_interp_ctx_build_cached(x4,igrid3, &
2666 state%sph_cache,ctx4,ctx_status)
2668 call trace_tangent_rk45_spherical_finish_boundary(state,xold,uold, &
2669 vold,x4,hsigned,threshold,kx1,ku1,kv1,status, &
2670 boundary_finished,pold,qold,kp1,kq1)
2671 if (boundary_finished)
return
2672 reject_reason=trace_rk45_reject_stage_failure
2675 reject_reason=trace_rk45_reject_stage_outside
2676 call trace_rk45_stats_note_attempt(.false.,.false.,h,reject_reason)
2677 if (h<=hfloor*(one+epsilon(one)))
exit
2678 h=max(hfloor,half*h)
2681 if (state%has_extra)
then
2682 call trace_tangent_rhs(x4,u4,v4,ctx4%igrid,threshold,kx4,ku4, &
2683 kv4,status,p4,q4,kp4,kq4,sph_ctx=ctx4)
2685 call trace_tangent_rhs(x4,u4,v4,ctx4%igrid,threshold,kx4,ku4, &
2686 kv4,status,sph_ctx=ctx4)
2691 x5s=xold+hsigned*(b51*kx1+b52*kx2+b53*kx3+b54*kx4)
2692 u5s=uold+hsigned*(b51*ku1+b52*ku2+b53*ku3+b54*ku4)
2693 v5s=vold+hsigned*(b51*kv1+b52*kv2+b53*kv3+b54*kv4)
2694 if (state%has_extra)
then
2695 p5s=pold+hsigned*(b51*kp1+b52*kp2+b53*kp3+b54*kp4)
2696 q5s=qold+hsigned*(b51*kq1+b52*kq2+b53*kq3+b54*kq4)
2698 call trace_spherical_interp_ctx_build_cached(x5s,igrid4, &
2699 state%sph_cache,ctx5,ctx_status)
2701 call trace_tangent_rk45_spherical_finish_boundary(state,xold,uold, &
2702 vold,x5s,hsigned,threshold,kx1,ku1,kv1,status, &
2703 boundary_finished,pold,qold,kp1,kq1)
2704 if (boundary_finished)
return
2705 reject_reason=trace_rk45_reject_stage_failure
2708 reject_reason=trace_rk45_reject_stage_outside
2709 call trace_rk45_stats_note_attempt(.false.,.false.,h,reject_reason)
2710 if (h<=hfloor*(one+epsilon(one)))
exit
2711 h=max(hfloor,half*h)
2714 if (state%has_extra)
then
2715 call trace_tangent_rhs(x5s,u5s,v5s,ctx5%igrid,threshold,kx5,ku5, &
2716 kv5,status,p5s,q5s,kp5,kq5,sph_ctx=ctx5)
2718 call trace_tangent_rhs(x5s,u5s,v5s,ctx5%igrid,threshold,kx5,ku5, &
2719 kv5,status,sph_ctx=ctx5)
2724 x6=xold+hsigned*(b61*kx1+b62*kx2+b63*kx3+b64*kx4+b65*kx5)
2725 u6=uold+hsigned*(b61*ku1+b62*ku2+b63*ku3+b64*ku4+b65*ku5)
2726 v6=vold+hsigned*(b61*kv1+b62*kv2+b63*kv3+b64*kv4+b65*kv5)
2727 if (state%has_extra)
then
2728 p6=pold+hsigned*(b61*kp1+b62*kp2+b63*kp3+b64*kp4+b65*kp5)
2729 q6=qold+hsigned*(b61*kq1+b62*kq2+b63*kq3+b64*kq4+b65*kq5)
2731 call trace_spherical_interp_ctx_build_cached(x6,igrid5, &
2732 state%sph_cache,ctx6,ctx_status)
2734 call trace_tangent_rk45_spherical_finish_boundary(state,xold,uold, &
2735 vold,x6,hsigned,threshold,kx1,ku1,kv1,status, &
2736 boundary_finished,pold,qold,kp1,kq1)
2737 if (boundary_finished)
return
2738 reject_reason=trace_rk45_reject_stage_failure
2741 reject_reason=trace_rk45_reject_stage_outside
2742 call trace_rk45_stats_note_attempt(.false.,.false.,h,reject_reason)
2743 if (h<=hfloor*(one+epsilon(one)))
exit
2744 h=max(hfloor,half*h)
2747 if (state%has_extra)
then
2748 call trace_tangent_rhs(x6,u6,v6,ctx6%igrid,threshold,kx6,ku6, &
2749 kv6,status,p6,q6,kp6,kq6,sph_ctx=ctx6)
2751 call trace_tangent_rhs(x6,u6,v6,ctx6%igrid,threshold,kx6,ku6, &
2752 kv6,status,sph_ctx=ctx6)
2757 x5sol=xold+hsigned*(c1*kx1+c3*kx3+c4*kx4+c6*kx6)
2758 u5sol=uold+hsigned*(c1*ku1+c3*ku3+c4*ku4+c6*ku6)
2759 v5sol=vold+hsigned*(c1*kv1+c3*kv3+c4*kv4+c6*kv6)
2760 x4err=xold+hsigned*(cs1*kx1+cs3*kx3+cs4*kx4+ &
2762 u4err=uold+hsigned*(cs1*ku1+cs3*ku3+cs4*ku4+ &
2764 v4err=vold+hsigned*(cs1*kv1+cs3*kv3+cs4*kv4+ &
2766 if (state%has_extra)
then
2767 p5sol=pold+hsigned*(c1*kp1+c3*kp3+c4*kp4+c6*kp6)
2768 q5sol=qold+hsigned*(c1*kq1+c3*kq3+c4*kq4+c6*kq6)
2769 p4err=pold+hsigned*(cs1*kp1+cs3*kp3+cs4*kp4+ &
2771 q4err=qold+hsigned*(cs1*kq1+cs3*kq3+cs4*kq4+ &
2776 {
if (x5sol(^db)>=domain_min(^db) .and. x5sol(^db)<domain_max(^db)) point_domain=point_domain+1\}
2777 if (point_domain/=
ndim)
then
2778 call trace_tangent_rk45_spherical_finish_boundary(state,xold,uold, &
2779 vold,x5sol,hsigned,threshold,kx1,ku1,kv1,status, &
2780 boundary_finished,pold,qold,kp1,kq1)
2781 if (boundary_finished)
return
2782 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
2783 trace_rk45_reject_boundary)
2790 r_metric=max(abs(xold(1)),smalldouble)
2791 sin_theta_metric=max(abs(dsin(xold(2))),smalldouble)
2792 err=dsqrt((x5sol(1)-x4err(1))**2+ &
2793 (r_metric*(x5sol(2)-x4err(2)))**2+ &
2794 (r_metric*sin_theta_metric*(x5sol(3)-x4err(3)))**2)
2796 if (hcell<=zero) hcell=hmax
2797 tol=trace_rk45_atol+trace_rk45_rtol*max(h,hcell)
2799 pos_err_ratio=err/tol
2803 u_err_ratio=dsqrt(sum((u5sol-u4err)**2))/ &
2804 max(dsqrt(sum(u5sol**2)),trace_rk45_tangent_floor)
2805 v_err_ratio=dsqrt(sum((v5sol-v4err)**2))/ &
2806 max(dsqrt(sum(v5sol**2)),trace_rk45_tangent_floor)
2807 if (state%has_extra)
then
2808 p_err_ratio=dsqrt(sum((p5sol-p4err)**2))/ &
2809 max(dsqrt(sum(p5sol**2)),trace_rk45_tangent_floor)
2810 q_err_ratio=dsqrt(sum((q5sol-q4err)**2))/ &
2811 max(dsqrt(sum(q5sol**2)),trace_rk45_tangent_floor)
2812 u_err_ratio=max(u_err_ratio,p_err_ratio)
2813 v_err_ratio=max(v_err_ratio,q_err_ratio)
2815 tan_err_ratio=max(u_err_ratio,v_err_ratio)
2816 call trace_rk45_stats_note_tangent_error(pos_err_ratio, &
2817 u_err_ratio,v_err_ratio)
2819 tan_ok=(tan_err_ratio<=trace_rk45_tangent_rtol)
2820 if ((pos_ok .and. tan_ok) .or. h<=hfloor*(one+epsilon(one)))
then
2821 if (state%accumulate_twist .and. &
2824 call trace_twist_density_at_point(xold,ctx1%igrid,threshold,tw1, &
2825 twist_status,sph_cache=ctx1)
2827 call trace_twist_density_at_point(x3,ctx3%igrid,threshold, &
2828 tw3,twist_status,sph_cache=ctx3)
2830 call trace_twist_density_at_point(x4,ctx4%igrid,threshold, &
2831 tw4,twist_status,sph_cache=ctx4)
2833 call trace_twist_density_at_point(x6,ctx6%igrid,threshold, &
2834 tw6,twist_status,sph_cache=ctx6)
2836 twist_increment=h*(c1*tw1+c3*tw3+c4*tw4+c6*tw6)
2837 state%twist=state%twist+twist_increment
2839 state%twist_status=twist_status
2845 if (state%has_extra)
then
2849 state%length=state%length+h
2850 state%nstep=state%nstep+1
2851 call trace_locate_point_with_hint(state%x,igrid6,state%igrid,status)
2853 state%sph_cache%valid=.false.
2854 if (trace_spherical_profile_enabled) &
2855 call trace_spherical_profile_add_count(trace_profile_steps,1_8)
2856 control_ratio=max(pos_err_ratio, &
2857 tan_err_ratio/trace_rk45_tangent_rtol)
2858 if (control_ratio>zero)
then
2859 grow=trace_rk45_safety*(one/control_ratio)**0.2d0
2860 grow=max(trace_rk45_min_shrink,min(trace_rk45_max_grow,grow))
2862 grow=trace_rk45_max_grow
2864 state%rk45_h=min(hmax,max(hfloor,h*grow))
2865 call trace_rk45_stats_note_attempt(.true.,.false.,h)
2870 if (.not.pos_ok)
then
2871 grow=trace_rk45_safety*(tol/max(err,smalldouble))**0.25d0
2872 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
2873 trace_rk45_reject_error)
2875 grow=trace_rk45_safety*(trace_rk45_tangent_rtol/ &
2876 max(tan_err_ratio,smalldouble))**0.25d0
2877 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
2878 trace_rk45_reject_tangent_error)
2880 grow=max(trace_rk45_min_shrink,min(one,grow))
2881 h=max(hfloor,h*grow)
2884 call trace_tangent_rk45_spherical_finish_boundary(state,xold,uold, &
2885 vold,xold+hsigned*kx1,hsigned,threshold,kx1,ku1,kv1,status, &
2886 boundary_finished,pold,qold,kp1,kq1)
2888 end subroutine trace_tangent_rk45_spherical_step
2890 subroutine trace_tangent_rk45_spherical_finish_boundary(state,xold,uold, &
2891 vold,xstage,hsigned,threshold,kx1,ku1,kv1,status,finished, &
2893 type(trace_tangent_state),
intent(inout) :: state
2894 double precision,
intent(in) :: xold(
ndim),uold(
ndim),vold(
ndim)
2895 double precision,
intent(in) :: xstage(
ndim),hsigned,threshold
2896 double precision,
intent(in) :: kx1(
ndim),ku1(
ndim),kv1(
ndim)
2897 integer,
intent(out) :: status
2898 logical,
intent(out) :: finished
2899 double precision,
intent(in),
optional :: pold(
ndim),qold(
ndim)
2900 double precision,
intent(in),
optional :: kp1(
ndim),kq1(
ndim)
2902 double precision :: xhit(
ndim),utrial(
ndim),vtrial(
ndim)
2903 double precision :: ptrial(
ndim),qtrial(
ndim)
2904 double precision :: xtrial(
ndim),partial_length,h_partial,alpha_hit
2908 call trace_intersect_domain(xold,xstage,xhit,hit_ok,state%face_id, &
2910 if (.not.hit_ok)
return
2912 partial_length=trace_segment_length(xold,xhit,hsigned,alpha_hit)
2913 if (partial_length>100.d0*epsilon(one)*max(one,abs(hsigned)))
then
2914 h_partial=sign(partial_length,hsigned)
2915 if (state%has_extra)
then
2916 if (.not.(
present(pold) .and.
present(qold) .and.
present(kp1) &
2917 .and.
present(kq1)))
then
2921 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold,state%igrid, &
2922 h_partial,threshold,kx1,ku1,kv1,xtrial,utrial,vtrial,status, &
2923 pold,qold,kp1,kq1,ptrial,qtrial,sph_cache=state%sph_cache)
2925 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold,state%igrid, &
2926 h_partial,threshold,kx1,ku1,kv1,xtrial,utrial,vtrial,status, &
2927 sph_cache=state%sph_cache)
2930 call trace_tangent_accumulate_twist(state,xhit,partial_length, &
2934 if (state%has_extra)
then
2938 state%length=state%length+partial_length
2939 state%nstep=state%nstep+1
2940 if (trace_spherical_profile_enabled) &
2941 call trace_spherical_profile_add_count(trace_profile_steps,1_8)
2945 if (state%has_extra)
then
2946 if (.not.(
present(pold) .and.
present(qold)))
then
2957 state%active=.false.
2958 state%complete=.true.
2960 state%sph_cache%valid=.false.
2961 if (trace_spherical_profile_enabled)
then
2962 call trace_spherical_profile_add_count(trace_profile_boundary_events,1_8)
2964 call trace_tangent_state_finalize_boundary(state,threshold)
2965 call trace_rk45_stats_note_attempt(.true.,.true.,partial_length)
2968 end subroutine trace_tangent_rk45_spherical_finish_boundary
2970 subroutine trace_tangent_state_advance_in_grid(state,igrid,dL,max_steps, &
2971 threshold,short_boundary)
2972 type(trace_tangent_state),
intent(inout) :: state
2973 integer,
intent(in) :: igrid,max_steps
2974 double precision,
intent(in) :: dl,threshold
2975 logical,
intent(in),
optional :: short_boundary
2977 integer,
parameter :: max_bisect=50
2978 double precision :: h,h_partial,partial_length,alpha_hit
2979 double precision :: h_abs_low,h_abs_high,h_abs_mid,h_abs_final,hsign
2981 double precision :: ptrial(
ndim),qtrial(
ndim)
2983 double precision :: pold(
ndim),qold(
ndim)
2987 double precision :: dxb^
d
2988 type(trace_sph_interp_ctx) :: ctx_old
2989 integer :: igrid_old,igrid_trial,point_domain,iter
2990 integer :: ctx_status,trial_status
2991 logical :: hit_ok,use_short_boundary
2993 if (.not.state%active)
return
2994 use_short_boundary=.false.
2995 if (
present(short_boundary)) use_short_boundary=short_boundary
2997 do while(state%active .and. state%igrid==igrid .and. &
2998 state%nstep<max_steps)
3006 if (geo_coordinate==geo_spherical)
then
3007 call trace_spherical_interp_ctx_build_cached(xold,state%igrid, &
3008 state%sph_cache,ctx_old,ctx_status)
3011 h=trace_spherical_effective_step_ctx(dl,ctx_old)
3013 h=trace_effective_step(xold,dl,state%igrid,dxb^
d)
3015 if (state%direction<0) h=-h
3017 if (state%has_extra)
then
3019 call trace_tangent_rhs(xold,uold,vold,state%igrid,threshold,kx1, &
3020 ku1,kv1,state%status,pold,qold,kp1,kq1,sph_ctx=ctx_old)
3022 call trace_tangent_rhs(xold,uold,vold,state%igrid,threshold,kx1, &
3023 ku1,kv1,state%status,pold,qold,kp1,kq1)
3027 call trace_tangent_rhs(xold,uold,vold,state%igrid,threshold,kx1, &
3028 ku1,kv1,state%status,sph_ctx=ctx_old)
3030 call trace_tangent_rhs(xold,uold,vold,state%igrid,threshold,kx1, &
3031 ku1,kv1,state%status)
3035 state%active=.false.
3036 state%complete=.true.
3037 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3040 if (use_short_boundary)
then
3044 if (state%has_extra)
then
3045 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold,state%igrid, &
3046 h,threshold,kx1,ku1,kv1,xtrial,utrial,vtrial,state%status, &
3047 pold,qold,kp1,kq1,ptrial,qtrial,sph_cache=state%sph_cache, &
3050 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold,state%igrid, &
3051 h,threshold,kx1,ku1,kv1,xtrial,utrial,vtrial,state%status, &
3052 sph_cache=state%sph_cache,clamp_stage=.true.)
3055 state%active=.false.
3056 state%complete=.true.
3057 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3062 {
if (xtrial(^db)>=xprobmin^db .and. xtrial(^db)<xprobmax^db) point_domain=point_domain+1\}
3063 if (point_domain==
ndim)
then
3064 igrid_old=state%igrid
3065 call trace_locate_point_with_hint(xtrial,state%igrid,igrid_trial, &
3068 state%active=.false.
3069 state%complete=.true.
3070 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3073 call trace_tangent_accumulate_twist(state,xtrial,abs(h),threshold)
3077 if (state%has_extra)
then
3081 state%igrid=igrid_trial
3082 state%length=state%length+abs(h)
3083 state%nstep=state%nstep+1
3084 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_step(abs(h),.false., &
3085 igrid_trial/=igrid_old)
3086 if (trace_spherical_profile_enabled .and. &
3087 geo_coordinate==geo_spherical)
then
3088 call trace_spherical_profile_add_count(trace_profile_steps,1_8)
3099 do iter=1,max_bisect
3100 h_abs_mid=half*(h_abs_low+h_abs_high)
3101 if (h_abs_high-h_abs_low<=100.d0*epsilon(one)*max(one,abs(h))) &
3104 if (state%has_extra)
then
3105 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold, &
3106 state%igrid,hsign*h_abs_mid,threshold,kx1,ku1,kv1, &
3107 xtrial,utrial,vtrial,trial_status,pold,qold,kp1,kq1, &
3108 ptrial,qtrial,sph_cache=state%sph_cache, &
3111 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold, &
3112 state%igrid,hsign*h_abs_mid,threshold,kx1,ku1,kv1, &
3113 xtrial,utrial,vtrial,trial_status, &
3114 sph_cache=state%sph_cache,clamp_stage=.true.)
3117 h_abs_high=h_abs_mid
3121 {
if (xtrial(^db)>=xprobmin^db .and. xtrial(^db)<xprobmax^db) point_domain=point_domain+1\}
3122 if (point_domain==
ndim)
then
3127 if (state%has_extra)
then
3132 h_abs_high=h_abs_mid
3137 call trace_intersect_domain(xlow,xhigh,xhit,hit_ok,state%face_id, &
3140 h_abs_final=h_abs_low+max(zero,min(one,alpha_hit))* &
3141 (h_abs_high-h_abs_low)
3144 h_abs_final=h_abs_low
3145 call trace_boundary_face_at_point(xhit,state%face_id,hit_ok)
3147 if (.not.hit_ok)
then
3149 state%active=.false.
3150 state%complete=.true.
3151 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3155 partial_length=h_abs_final
3156 if (partial_length>100.d0*epsilon(one)*max(one,abs(h)))
then
3158 if (state%has_extra)
then
3159 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold, &
3160 state%igrid,hsign*h_abs_final,threshold,kx1,ku1,kv1, &
3161 xtrial,utrial,vtrial,trial_status,pold,qold,kp1,kq1, &
3162 ptrial,qtrial,sph_cache=state%sph_cache, &
3165 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold, &
3166 state%igrid,hsign*h_abs_final,threshold,kx1,ku1,kv1, &
3167 xtrial,utrial,vtrial,trial_status, &
3168 sph_cache=state%sph_cache,clamp_stage=.true.)
3171 state%status=trial_status
3172 state%active=.false.
3173 state%complete=.true.
3174 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3177 call trace_tangent_accumulate_twist(state,xhit,partial_length, &
3181 if (state%has_extra)
then
3185 state%length=state%length+partial_length
3186 state%nstep=state%nstep+1
3187 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_step(partial_length,.true.,.false.)
3188 if (trace_spherical_profile_enabled .and. &
3189 geo_coordinate==geo_spherical)
then
3190 call trace_spherical_profile_add_count(trace_profile_steps,1_8)
3195 if (state%has_extra)
then
3203 state%active=.false.
3204 if (trace_spherical_profile_enabled .and. &
3205 geo_coordinate==geo_spherical)
then
3206 call trace_spherical_profile_add_count( &
3207 trace_profile_boundary_events,1_8)
3209 call trace_tangent_state_finalize_boundary(state,threshold)
3210 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3218 {
if (xprobe(^db)>=xprobmin^db .and. xprobe(^db)<xprobmax^db) point_domain=point_domain+1\}
3219 if (point_domain/=
ndim)
then
3220 call trace_intersect_domain(xold,xprobe,xhit,hit_ok,state%face_id, &
3222 if (.not.hit_ok)
then
3223 call trace_boundary_face_at_point(xold,state%face_id,hit_ok)
3225 state%active=.false.
3229 if (state%has_extra)
then
3234 if (hit_ok)
call trace_tangent_state_finalize_boundary(state, &
3236 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3239 partial_length=trace_segment_length(xold,xhit,h,alpha_hit)
3240 if (partial_length<=100.d0*epsilon(one)*max(one,abs(h)))
then
3244 if (state%has_extra)
then
3250 state%active=.false.
3251 call trace_tangent_state_finalize_boundary(state,threshold)
3252 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3255 h_partial=sign(partial_length,h)
3256 if (state%has_extra)
then
3257 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold,state%igrid, &
3258 h_partial,threshold,kx1,ku1,kv1,xtrial,utrial,vtrial, &
3259 state%status,pold,qold,kp1,kq1,ptrial,qtrial, &
3260 sph_cache=state%sph_cache)
3262 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold,state%igrid, &
3263 h_partial,threshold,kx1,ku1,kv1,xtrial,utrial,vtrial, &
3264 state%status,sph_cache=state%sph_cache)
3267 state%active=.false.
3268 state%complete=.true.
3269 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3272 call trace_tangent_accumulate_twist(state,xhit,partial_length, &
3277 if (state%has_extra)
then
3281 state%length=state%length+partial_length
3284 state%active=.false.
3285 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_step(partial_length,.true.,.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)
3291 if (state%has_extra)
then
3292 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold,state%igrid,h, &
3293 threshold,kx1,ku1,kv1,xtrial,utrial,vtrial,state%status, &
3294 pold,qold,kp1,kq1,ptrial,qtrial,sph_cache=state%sph_cache)
3296 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold,state%igrid,h, &
3297 threshold,kx1,ku1,kv1,xtrial,utrial,vtrial,state%status, &
3298 sph_cache=state%sph_cache)
3301 state%active=.false.
3302 state%complete=.true.
3303 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3308 {
if (xtrial(^db)>=xprobmin^db .and. xtrial(^db)<xprobmax^db) point_domain=point_domain+1\}
3309 if (point_domain==
ndim)
then
3310 igrid_old=state%igrid
3311 call trace_locate_point_with_hint(xtrial,state%igrid,igrid_trial, &
3314 state%active=.false.
3315 state%complete=.true.
3316 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3319 call trace_tangent_accumulate_twist(state,xtrial,abs(h),threshold)
3323 if (state%has_extra)
then
3327 state%igrid=igrid_trial
3328 state%length=state%length+abs(h)
3329 state%nstep=state%nstep+1
3330 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_step(abs(h),.false., &
3331 igrid_trial/=igrid_old)
3332 if (trace_spherical_profile_enabled .and. &
3333 geo_coordinate==geo_spherical)
then
3334 call trace_spherical_profile_add_count(trace_profile_steps,1_8)
3337 call trace_intersect_domain(xold,xtrial,xhit,hit_ok,state%face_id, &
3339 if (.not.hit_ok)
then
3340 call trace_boundary_face_at_point(xold,state%face_id,hit_ok)
3342 state%active=.false.
3346 if (state%has_extra)
then
3351 if (hit_ok)
call trace_tangent_state_finalize_boundary(state, &
3353 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3356 partial_length=trace_segment_length(xold,xhit,h,alpha_hit)
3357 if (partial_length<=100.d0*epsilon(one)*max(one,abs(h)))
then
3361 if (state%has_extra)
then
3367 state%active=.false.
3368 call trace_tangent_state_finalize_boundary(state,threshold)
3369 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3372 h_partial=sign(partial_length,h)
3373 if (state%has_extra)
then
3374 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold,state%igrid, &
3375 h_partial,threshold,kx1,ku1,kv1,xtrial,utrial,vtrial, &
3376 state%status,pold,qold,kp1,kq1,ptrial,qtrial, &
3377 sph_cache=state%sph_cache)
3379 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold,state%igrid, &
3380 h_partial,threshold,kx1,ku1,kv1,xtrial,utrial,vtrial, &
3381 state%status,sph_cache=state%sph_cache)
3384 state%active=.false.
3385 state%complete=.true.
3386 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3389 call trace_tangent_accumulate_twist(state,xhit,partial_length, &
3394 if (state%has_extra)
then
3398 state%length=state%length+partial_length
3401 state%active=.false.
3402 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_step(partial_length,.true.,.false.)
3403 if (trace_spherical_profile_enabled .and. &
3404 geo_coordinate==geo_spherical)
then
3405 call trace_spherical_profile_add_count(trace_profile_boundary_events, &
3408 call trace_tangent_state_finalize_boundary(state,threshold)
3409 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3414 if (state%active .and. state%nstep>=max_steps)
then
3416 state%active=.false.
3417 state%complete=.true.
3418 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3420 if ((.not.state%active) .and. trace_spherical_profile_enabled .and. &
3421 geo_coordinate==geo_spherical)
then
3422 call trace_spherical_profile_note_trace_steps(state%nstep)
3424 end subroutine trace_tangent_state_advance_in_grid
3426 subroutine trace_tangent_state_finalize_boundary(state,threshold)
3427 type(trace_tangent_state),
intent(inout) :: state
3428 double precision,
intent(in) :: threshold
3431 if (trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical) &
3432 call trace_spherical_profile_add_count( &
3433 trace_profile_endpoint_finalizations,1_8)
3435 call trace_endpoint_b_bhat(state%endpoint,state%face_id,state%igrid, &
3436 threshold,state%endpoint_B,state%endpoint_bhat,state%status)
3439 call trace_project_to_perp_bhat(state%u,state%endpoint_bhat, &
3441 call trace_project_to_perp_bhat(state%v,state%endpoint_bhat, &
3443 if (state%has_extra)
then
3444 call trace_project_to_perp_bhat(state%p,state%endpoint_bhat, &
3446 call trace_project_to_perp_bhat(state%q,state%endpoint_bhat, &
3449 state%complete=.true.
3450 end subroutine trace_tangent_state_finalize_boundary
3452 subroutine trace_qperp_prepare_seed_result(seed,field_min,result,igrid, &
3454 double precision,
intent(in) :: seed(
ndim),field_min
3456 integer,
intent(out) :: igrid,status
3458 double precision :: b3(3),bseed_norm
3461 call trace_init_qperp_result(seed,result)
3466 {
if (seed(^db)>=xprobmin^db .and. seed(^db)<xprobmax^db) indomain=indomain+1\}
3467 if (indomain/=
ndim)
then
3469 result%status=status
3473 call trace_debug_locate_point(seed,igrid,status)
3475 result%status=status
3479 call sample_b_at_point(seed,igrid,field_min,b3,status)
3481 result%status=status
3484 result%B_seed=b3(1:
ndim)
3485 bseed_norm=dsqrt(sum(result%B_seed**2))
3486 if (bseed_norm<=zero .or. bseed_norm<field_min)
then
3488 result%status=status
3492 result%bhat_seed=result%B_seed/bseed_norm
3493 call trace_make_perp_basis(b3/bseed_norm,result%u0,result%v0,status)
3495 end subroutine trace_qperp_prepare_seed_result
3497 subroutine trace_qperp_compute_scalars(result,field_min)
3499 double precision,
intent(in) :: field_min
3501 double precision :: bseed_norm,bf_norm,bb_norm,dot_f,dot_b,qtmp
3503 bseed_norm=dsqrt(sum(result%B_seed**2))
3504 bf_norm=dsqrt(sum(result%forward_B**2))
3505 bb_norm=dsqrt(sum(result%backward_B**2))
3506 if (bseed_norm<=zero .or. bf_norm<=zero .or. bb_norm<=zero .or. &
3507 bseed_norm<field_min .or. bf_norm<field_min .or. &
3508 bb_norm<field_min)
then
3513 dot_f=sum(result%u_forward_perp*result%v_forward_perp)
3514 dot_b=sum(result%u_backward_perp*result%v_backward_perp)
3515 result%N2=sum(result%u_forward_perp**2)* &
3516 sum(result%v_backward_perp**2)+ &
3517 sum(result%u_backward_perp**2)* &
3518 sum(result%v_forward_perp**2)-2.d0*dot_f*dot_b
3519 result%bfactor=abs(bf_norm*bb_norm)/(bseed_norm**2)
3520 qtmp=result%N2*result%bfactor
3521 if (qtmp>zero .and. ieee_is_finite(qtmp))
then
3522 qtmp=max(qtmp,trace_q_min)
3524 result%logqperp=dlog10(qtmp)
3528 result%logqperp0=result%logqperp
3529 result%valid_qperp0=.true.
3532 result%N2=trace_debug_nan()
3533 result%bfactor=trace_debug_nan()
3534 result%qperp=trace_debug_nan()
3535 result%logqperp=trace_debug_nan()
3537 result%valid=.false.
3538 result%qperp0=trace_debug_nan()
3539 result%logqperp0=trace_debug_nan()
3540 result%valid_qperp0=.false.
3543 call trace_qperp_compute_q0_scalars(result,field_min)
3544 end subroutine trace_qperp_compute_scalars
3546 subroutine trace_qperp_compute_q0_scalars(result,field_min)
3548 double precision,
intent(in) :: field_min
3550 double precision :: bseed_norm,bnf,bnb,n2bnd,qtmp
3551 double precision :: uf_face(
ndim),vf_face(
ndim)
3552 double precision :: ub_face(
ndim),vb_face(
ndim)
3553 integer :: status_f,status_b
3555 result%q0=trace_debug_nan()
3556 result%logq0=trace_debug_nan()
3557 result%N2_qperp0=trace_debug_nan()
3558 result%bfactor_qperp0=trace_debug_nan()
3559 result%forward_Bn_q0=trace_debug_nan()
3560 result%backward_Bn_q0=trace_debug_nan()
3561 result%valid_q0=.false.
3564 result%status_q0=result%forward_status
3568 result%status_q0=result%backward_status
3572 bseed_norm=dsqrt(sum(result%B_seed**2))
3573 if (bseed_norm<=zero .or. bseed_norm<field_min)
then
3578 call trace_qperp_project_to_boundary_face(result%u_forward_perp, &
3579 result%forward_B,result%forward_face,uf_face,bnf,status_f)
3580 call trace_qperp_project_to_boundary_face(result%v_forward_perp, &
3581 result%forward_B,result%forward_face,vf_face,bnf,status_f)
3582 call trace_qperp_project_to_boundary_face(result%u_backward_perp, &
3583 result%backward_B,result%backward_face,ub_face,bnb,status_b)
3584 call trace_qperp_project_to_boundary_face(result%v_backward_perp, &
3585 result%backward_B,result%backward_face,vb_face,bnb,status_b)
3587 result%status_q0=status_f
3591 result%status_q0=status_b
3594 if (abs(bnf)<field_min .or. abs(bnb)<field_min)
then
3599 n2bnd=sum(uf_face**2)*sum(vb_face**2)+ &
3600 sum(ub_face**2)*sum(vf_face**2)- &
3601 2.d0*sum(uf_face*vf_face)*sum(ub_face*vb_face)
3602 result%N2_qperp0=abs(n2bnd)
3603 result%bfactor_qperp0=abs(bnf*bnb)/(bseed_norm**2)
3604 result%forward_Bn_q0=bnf
3605 result%backward_Bn_q0=bnb
3606 qtmp=result%N2_qperp0*result%bfactor_qperp0
3607 if (qtmp>zero .and. ieee_is_finite(qtmp))
then
3608 qtmp=max(qtmp,trace_q_min)
3610 result%logq0=dlog10(qtmp)
3611 result%valid_q0=.true.
3614 result%q0=trace_debug_nan()
3615 result%logq0=trace_debug_nan()
3616 result%valid_q0=.false.
3619 end subroutine trace_qperp_compute_q0_scalars
3621 subroutine trace_qperp_project_to_boundary_face(vec,B,face_id,vec_face, &
3623 double precision,
intent(in) :: vec(
ndim),b(
ndim)
3624 integer,
intent(in) :: face_id
3625 double precision,
intent(out) :: vec_face(
ndim),bn
3626 integer,
intent(out) :: status
3628 double precision :: normal(
ndim),vecn
3634 call trace_face_normal(face_id,normal,ok)
3641 vecn=sum(vec*normal)
3642 vec_face=vec-vecn/bn*b
3644 end subroutine trace_qperp_project_to_boundary_face
3646 subroutine trace_qperp_finalize_from_states(forward_state,backward_state, &
3648 type(trace_tangent_state),
intent(in) :: forward_state,backward_state
3650 double precision,
intent(in) :: field_min
3652 result%forward_endpoint=forward_state%endpoint
3653 result%forward_B=forward_state%endpoint_B
3654 result%forward_bhat=forward_state%endpoint_bhat
3655 result%forward_length=forward_state%length
3656 result%forward_nstep=forward_state%nstep
3657 result%forward_face=forward_state%face_id
3658 result%forward_status=forward_state%status
3659 result%u_forward_perp=forward_state%u_perp
3660 result%v_forward_perp=forward_state%v_perp
3662 result%backward_endpoint=backward_state%endpoint
3663 result%backward_B=backward_state%endpoint_B
3664 result%backward_bhat=backward_state%endpoint_bhat
3665 result%backward_length=backward_state%length
3666 result%backward_nstep=backward_state%nstep
3667 result%backward_face=backward_state%face_id
3668 result%backward_status=backward_state%status
3669 result%u_backward_perp=backward_state%u_perp
3670 result%v_backward_perp=backward_state%v_perp
3673 result%status=forward_state%status
3677 result%status=backward_state%status
3681 call trace_qperp_compute_scalars(result,field_min)
3682 end subroutine trace_qperp_finalize_from_states
3684 subroutine trace_q0_finalize_from_states(forward_state,backward_state, &
3686 type(trace_tangent_state),
intent(in) :: forward_state,backward_state
3688 double precision,
intent(in) :: field_min
3690 result%forward_endpoint=forward_state%endpoint
3691 result%forward_B=forward_state%endpoint_B
3692 result%forward_bhat=forward_state%endpoint_bhat
3693 result%forward_length=forward_state%length
3694 result%forward_nstep=forward_state%nstep
3695 result%forward_face=forward_state%face_id
3696 result%forward_status=forward_state%status
3697 result%u_forward_perp=forward_state%u_perp
3698 result%v_forward_perp=forward_state%v_perp
3700 result%backward_endpoint=backward_state%endpoint
3701 result%backward_B=backward_state%endpoint_B
3702 result%backward_bhat=backward_state%endpoint_bhat
3703 result%backward_length=backward_state%length
3704 result%backward_nstep=backward_state%nstep
3705 result%backward_face=backward_state%face_id
3706 result%backward_status=backward_state%status
3707 result%u_backward_perp=backward_state%u_perp
3708 result%v_backward_perp=backward_state%v_perp
3711 result%status=forward_state%status
3712 result%status_q0=forward_state%status
3716 result%status=backward_state%status
3717 result%status_q0=backward_state%status
3722 call trace_qperp_compute_q0_scalars(result,field_min)
3723 end subroutine trace_q0_finalize_from_states
3725 subroutine trace_spherical_rmin_q_prepare_seed_result(seed,field_min, &
3726 result,igrid,status)
3727 double precision,
intent(in) :: seed(
ndim),field_min
3729 integer,
intent(out) :: igrid,status
3731 double precision :: bcart(3),bhat_cart(3),er(3),etheta(3),ephi(3)
3732 double precision :: radial_tol
3735 call trace_init_qperp_result(seed,result)
3739 if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
then
3741 result%status=status
3742 result%status_q0=status
3747 {
if (seed(^db)>=xprobmin^db .and. seed(^db)<xprobmax^db) indomain=indomain+1\}
3748 if (indomain/=
ndim)
then
3750 result%status=status
3751 result%status_q0=status
3755 call trace_debug_locate_point(seed,igrid,status)
3757 result%status=status
3758 result%status_q0=status
3763 call trace_spherical_sample_b_bhat_cart(seed,igrid,field_min,bcart, &
3766 result%status=status
3767 result%status_q0=status
3770 call trace_spherical_basis(seed,er,etheta,ephi,status)
3772 result%status=status
3773 result%status_q0=status
3776 result%B_seed=bcart(1:
ndim)
3777 result%bhat_seed=bhat_cart(1:
ndim)
3778 radial_tol=100.d0*epsilon(one)*max(one,abs(xprobmin1),abs(xprobmax1))
3781 if (abs(seed(1)-xprobmin1)<=radial_tol .or. &
3782 abs(seed(1)-xprobmax1)<=radial_tol)
then
3783 result%u0=etheta(1:
ndim)
3784 result%v0=ephi(1:
ndim)
3786 call trace_make_perp_basis(bhat_cart,result%u0,result%v0,status)
3788 result%status=status
3789 result%status_q0=status
3794 end subroutine trace_spherical_rmin_q_prepare_seed_result
3796 subroutine trace_spherical_rmin_q_finalize_from_states(forward_state, &
3797 backward_state,result,field_min)
3798 type(trace_tangent_state),
intent(in) :: forward_state,backward_state
3800 double precision,
intent(in) :: field_min
3802 call trace_spherical_radial_q_finalize_from_states(forward_state, &
3803 backward_state,result,field_min)
3805 end subroutine trace_spherical_rmin_q_finalize_from_states
3807 subroutine trace_spherical_radial_q_finalize_from_states(forward_state, &
3808 backward_state,result,field_min)
3809 type(trace_tangent_state),
intent(in) :: forward_state,backward_state
3811 double precision,
intent(in) :: field_min
3813 double precision :: bnf,bnb,frob2,qtmp,logqtmp,bfactor
3814 double precision :: af(2,2),ab(2,2)
3815 integer :: status_f,status_b,status_q
3818 result%forward_endpoint=forward_state%endpoint
3819 result%forward_B=forward_state%endpoint_B
3820 result%forward_bhat=forward_state%endpoint_bhat
3821 result%forward_length=forward_state%length
3822 result%forward_nstep=forward_state%nstep
3823 result%forward_face=forward_state%face_id
3824 result%forward_status=forward_state%status
3825 result%u_forward_perp=forward_state%u
3826 result%v_forward_perp=forward_state%v
3828 result%backward_endpoint=backward_state%endpoint
3829 result%backward_B=backward_state%endpoint_B
3830 result%backward_bhat=backward_state%endpoint_bhat
3831 result%backward_length=backward_state%length
3832 result%backward_nstep=backward_state%nstep
3833 result%backward_face=backward_state%face_id
3834 result%backward_status=backward_state%status
3835 result%u_backward_perp=backward_state%u
3836 result%v_backward_perp=backward_state%v
3838 result%q0=trace_debug_nan()
3839 result%logq0=trace_debug_nan()
3840 result%N2_qperp0=trace_debug_nan()
3841 result%bfactor_qperp0=trace_debug_nan()
3842 result%forward_Bn_q0=trace_debug_nan()
3843 result%backward_Bn_q0=trace_debug_nan()
3844 result%valid_q0=.false.
3847 result%status_q0=forward_state%status
3848 result%status=forward_state%status
3852 result%status_q0=backward_state%status
3853 result%status=backward_state%status
3858 if (.not.trace_spherical_radial_q_face_pair_admitted( &
3859 forward_state%face_id,backward_state%face_id))
then
3864 if (dsqrt(sum(result%B_seed**2))<=zero .or. &
3865 dsqrt(sum(result%B_seed**2))<field_min)
then
3870 call trace_spherical_radial_endpoint_matrix(forward_state,af,bnf,status_f)
3871 result%forward_Bn_q0=bnf
3873 result%status_q0=status_f
3877 call trace_spherical_radial_endpoint_matrix(backward_state,ab,bnb,status_b)
3878 result%backward_Bn_q0=bnb
3880 result%status_q0=status_b
3884 if (abs(bnf)<1.
d-10 .or. abs(bnb)<1.
d-10)
then
3889 call trace_spherical_q_from_endpoint_matrices(af,ab,qtmp,logqtmp, &
3890 frob2,bfactor,valid_q,status_q)
3891 result%N2_qperp0=frob2
3892 result%bfactor_qperp0=bfactor
3893 if (.not.valid_q)
then
3894 result%status_q0=status_q
3899 result%logq0=logqtmp
3900 result%valid_q0=.true.
3902 end subroutine trace_spherical_radial_q_finalize_from_states
3904 logical function trace_spherical_radial_q_face_pair_admitted(face_forward, &
3905 face_backward)
result(is_admitted)
3906 integer,
intent(in) :: face_forward,face_backward
3909 select case (face_forward)
3917 end function trace_spherical_radial_q_face_pair_admitted
3919 subroutine trace_spherical_radial_endpoint_matrix(state,Amat,Bn,status)
3920 type(trace_tangent_state),
intent(in) :: state
3921 double precision,
intent(out) :: amat(2,2),bn
3922 integer,
intent(out) :: status
3924 double precision :: u_face(
ndim),v_face(
ndim)
3925 double precision :: er(3),etheta(3),ephi(3)
3926 double precision :: bn_u,bn_v
3927 integer :: status_u,status_v,basis_status
3933 call trace_spherical_radial_project_to_surface(state%u,state%endpoint_B, &
3934 state%endpoint,state%face_id,u_face,bn_u,status_u)
3940 call trace_spherical_radial_project_to_surface(state%v,state%endpoint_B, &
3941 state%endpoint,state%face_id,v_face,bn_v,status_v)
3950 call trace_spherical_basis(state%endpoint,er,etheta,ephi,basis_status)
3955 amat(1,1)=sum(u_face*etheta(1:
ndim))
3956 amat(2,1)=sum(u_face*ephi(1:
ndim))
3957 amat(1,2)=sum(v_face*etheta(1:
ndim))
3958 amat(2,2)=sum(v_face*ephi(1:
ndim))
3961 end subroutine trace_spherical_radial_endpoint_matrix
3963 subroutine trace_spherical_radial_project_to_surface(vec,B,x,face_id, &
3965 double precision,
intent(in) :: vec(
ndim),b(
ndim),x(
ndim)
3966 integer,
intent(in) :: face_id
3967 double precision,
intent(out) :: vec_face(
ndim),bn
3968 integer,
intent(out) :: status
3970 double precision :: er(3),etheta(3),ephi(3),normal(
ndim),vecn
3971 double precision :: bhat(
ndim),bnorm
3976 if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
return
3979 call trace_spherical_basis(x,er,etheta,ephi,status)
3981 select case (face_id)
3990 bnorm=dsqrt(sum(b**2))
3991 if (bnorm<=smalldouble)
then
3997 if (abs(bn)<=smalldouble)
then
4001 vecn=sum(vec*normal)
4002 vec_face=vec-vecn/bn*bhat
4005 end subroutine trace_spherical_radial_project_to_surface
4007 subroutine trace_spherical_qperp_prepare_seed_result(seed,field_min, &
4008 result,igrid,status)
4009 double precision,
intent(in) :: seed(
ndim),field_min
4011 integer,
intent(out) :: igrid,status
4013 double precision :: bcart(3),bhat_cart(3)
4016 call trace_init_qperp_result(seed,result)
4020 if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
then
4022 result%status=status
4027 {
if (seed(^db)>=xprobmin^db .and. seed(^db)<xprobmax^db) indomain=indomain+1\}
4028 if (indomain/=
ndim)
then
4030 result%status=status
4034 call trace_debug_locate_point(seed,igrid,status)
4036 result%status=status
4041 call trace_spherical_sample_b_bhat_cart(seed,igrid,field_min,bcart, &
4044 result%status=status
4047 result%B_seed=bcart(1:
ndim)
4048 result%bhat_seed=bhat_cart(1:
ndim)
4049 call trace_make_perp_basis(bhat_cart,result%u0,result%v0,status)
4052 end subroutine trace_spherical_qperp_prepare_seed_result
4054 subroutine trace_spherical_qperp_finalize_from_states(forward_state, &
4055 backward_state,result,field_min)
4056 type(trace_tangent_state),
intent(in) :: forward_state,backward_state
4058 double precision,
intent(in) :: field_min
4060 result%forward_endpoint=forward_state%endpoint
4061 result%forward_B=forward_state%endpoint_B
4062 result%forward_bhat=forward_state%endpoint_bhat
4063 result%forward_length=forward_state%length
4064 result%forward_nstep=forward_state%nstep
4065 result%forward_face=forward_state%face_id
4066 result%forward_status=forward_state%status
4067 result%u_forward_perp=forward_state%u_perp
4068 result%v_forward_perp=forward_state%v_perp
4070 result%backward_endpoint=backward_state%endpoint
4071 result%backward_B=backward_state%endpoint_B
4072 result%backward_bhat=backward_state%endpoint_bhat
4073 result%backward_length=backward_state%length
4074 result%backward_nstep=backward_state%nstep
4075 result%backward_face=backward_state%face_id
4076 result%backward_status=backward_state%status
4077 result%u_backward_perp=backward_state%u_perp
4078 result%v_backward_perp=backward_state%v_perp
4081 result%status=forward_state%status
4082 result%status_qperp0=forward_state%status
4086 result%status=backward_state%status
4087 result%status_qperp0=backward_state%status
4091 call trace_spherical_qperp_compute_from_states(result,field_min)
4092 end subroutine trace_spherical_qperp_finalize_from_states
4094 subroutine trace_spherical_qperp_compute_from_states(result,field_min)
4096 double precision,
intent(in) :: field_min
4099 double precision :: forward_bhat3(3),backward_bhat3(3)
4100 double precision :: af(2,2),ab(2,2)
4101 double precision :: bseed_norm,bf_norm,bb_norm,frob2,qtmp,logqtmp,bfactor
4102 integer :: status_f,status_b,status_q
4105 result%qperp=trace_debug_nan()
4106 result%logqperp=trace_debug_nan()
4107 result%N2=trace_debug_nan()
4108 result%bfactor=trace_debug_nan()
4109 result%qperp0=trace_debug_nan()
4110 result%logqperp0=trace_debug_nan()
4111 result%N2_qperp0=trace_debug_nan()
4112 result%bfactor_qperp0=trace_debug_nan()
4113 result%valid=.false.
4114 result%valid_qperp0=.false.
4122 bseed_norm=dsqrt(sum(result%B_seed**2))
4123 bf_norm=dsqrt(sum(result%forward_B**2))
4124 bb_norm=dsqrt(sum(result%backward_B**2))
4125 if (bseed_norm<=zero .or. bf_norm<=zero .or. bb_norm<=zero .or. &
4126 bseed_norm<field_min .or. bf_norm<field_min .or. &
4127 bb_norm<field_min)
then
4135 forward_bhat3(1:
ndim)=result%forward_bhat
4136 backward_bhat3(1:
ndim)=result%backward_bhat
4137 call trace_make_perp_basis(forward_bhat3,f1,f2,status_f)
4138 call trace_make_perp_basis(backward_bhat3,b1,b2,status_b)
4140 result%status=status_f
4141 result%status_qperp0=status_f
4145 result%status=status_b
4146 result%status_qperp0=status_b
4150 af(1,1)=sum(result%u_forward_perp*f1)
4151 af(2,1)=sum(result%u_forward_perp*f2)
4152 af(1,2)=sum(result%v_forward_perp*f1)
4153 af(2,2)=sum(result%v_forward_perp*f2)
4154 ab(1,1)=sum(result%u_backward_perp*b1)
4155 ab(2,1)=sum(result%u_backward_perp*b2)
4156 ab(1,2)=sum(result%v_backward_perp*b1)
4157 ab(2,2)=sum(result%v_backward_perp*b2)
4159 call trace_spherical_q_from_endpoint_matrices(af,ab,qtmp,logqtmp, &
4160 frob2,bfactor,valid_q,status_q)
4162 result%bfactor=bfactor
4163 result%N2_qperp0=frob2
4164 result%bfactor_qperp0=bfactor
4165 if (.not.valid_q)
then
4166 result%status=status_q
4167 result%status_qperp0=status_q
4172 result%logqperp=logqtmp
4176 result%logqperp0=result%logqperp
4177 result%valid_qperp0=.true.
4179 end subroutine trace_spherical_qperp_compute_from_states
4181 subroutine trace_spherical_q_from_endpoint_matrices(Af,Ab,qval,logq, &
4182 frob2,bfactor,valid,status)
4183 double precision,
intent(in) :: af(2,2),ab(2,2)
4184 double precision,
intent(out) :: qval,logq,frob2,bfactor
4185 logical,
intent(out) :: valid
4186 integer,
intent(out) :: status
4188 double precision :: dmat(2,2),detab,detd,q_tol,det_tol
4190 qval=trace_debug_nan()
4191 logq=trace_debug_nan()
4192 frob2=trace_debug_nan()
4193 bfactor=trace_debug_nan()
4197 detab=ab(1,1)*ab(2,2)-ab(1,2)*ab(2,1)
4199 if (.not.ieee_is_finite(detab) .or. abs(detab)<=det_tol)
then
4204 dmat(1,1)=(af(1,1)*ab(2,2)-af(1,2)*ab(2,1))/detab
4205 dmat(1,2)=(-af(1,1)*ab(1,2)+af(1,2)*ab(1,1))/detab
4206 dmat(2,1)=(af(2,1)*ab(2,2)-af(2,2)*ab(2,1))/detab
4207 dmat(2,2)=(-af(2,1)*ab(1,2)+af(2,2)*ab(1,1))/detab
4208 detd=dmat(1,1)*dmat(2,2)-dmat(1,2)*dmat(2,1)
4211 if (.not.ieee_is_finite(detd) .or. abs(detd)<=det_tol)
then
4216 qval=frob2/abs(detd)
4218 if (qval>zero .and. ieee_is_finite(qval))
then
4219 if (qval<trace_q_min-q_tol)
then
4223 qval=max(qval,trace_q_min)
4228 qval=trace_debug_nan()
4229 logq=trace_debug_nan()
4234 end subroutine trace_spherical_q_from_endpoint_matrices
4236 subroutine trace_spherical_basis(x,er,etheta,ephi,status)
4237 double precision,
intent(in) :: x(
ndim)
4238 double precision,
intent(out) :: er(3),etheta(3),ephi(3)
4239 integer,
intent(out) :: status
4241 double precision :: theta,phi,sint,cost,sinp,cosp
4247 if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
return
4250 if (.not.trace_spherical_metric_ok(x))
then
4260 er=(/ sint*cosp,sint*sinp,cost /)
4261 etheta=(/ cost*cosp,cost*sinp,-sint /)
4262 ephi=(/ -sinp,cosp,zero /)
4265 end subroutine trace_spherical_basis
4267 subroutine trace_spherical_coord_to_cart(x,xcart,status)
4268 double precision,
intent(in) :: x(
ndim)
4269 double precision,
intent(out) :: xcart(3)
4270 integer,
intent(out) :: status
4272 double precision :: r,theta,phi,sint
4276 if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
return
4279 if (.not.trace_spherical_metric_ok(x))
then
4287 xcart(1)=r*sint*dcos(phi)
4288 xcart(2)=r*sint*dsin(phi)
4289 xcart(3)=r*dcos(theta)
4292 end subroutine trace_spherical_coord_to_cart
4294 subroutine trace_cart_to_spherical_coord(xcart,x,status)
4295 double precision,
intent(in) :: xcart(3)
4296 double precision,
intent(out) :: x(
ndim)
4297 integer,
intent(out) :: status
4299 double precision :: r,rho,phi,twopi
4303 if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
return
4306 r=dsqrt(sum(xcart**2))
4307 if (r<=100.d0*epsilon(one))
then
4311 rho=dsqrt(xcart(1)**2+xcart(2)**2)
4312 phi=datan2(xcart(2),xcart(1))
4313 twopi=2.d0*dacos(-one)
4314 if (phi<xprobmin3 .and. phi+twopi<xprobmax3) phi=phi+twopi
4315 if (phi>=xprobmax3 .and. phi-twopi>=xprobmin3) phi=phi-twopi
4317 x(2)=datan2(rho,xcart(3))
4321 end subroutine trace_cart_to_spherical_coord
4323 subroutine trace_spherical_interp_ctx_build(x,igrid,ctx,status)
4324 double precision,
intent(in) :: x(
ndim)
4325 integer,
intent(in) :: igrid
4326 type(trace_sph_interp_ctx),
intent(out) :: ctx
4327 integer,
intent(out) :: status
4329 double precision :: xd^
d,dxc^
d
4330 double precision :: t0
4331 integer :: ixi^
l,ixbl^
d
4333 if (trace_spherical_profile_enabled)
then
4334 call trace_spherical_profile_add_count(trace_profile_context_requests, &
4336 call trace_spherical_profile_add_count( &
4337 trace_profile_full_context_builds,1_8)
4338 t0=trace_spherical_profile_time()
4358 ctx%bcorner_valid=.false.
4361 if (
ndim/=3 .or. geo_coordinate/=geo_spherical .or. igrid<0)
then
4362 if (trace_spherical_profile_enabled)
then
4363 call trace_spherical_profile_add_count(trace_profile_context_failures, &
4365 call trace_spherical_profile_add_time(trace_profile_time_context, &
4366 trace_spherical_profile_time()-t0)
4373 if (.not.trace_spherical_metric_ok(x))
then
4375 if (trace_spherical_profile_enabled)
then
4376 call trace_spherical_profile_add_count(trace_profile_context_failures, &
4378 call trace_spherical_profile_add_time(trace_profile_time_context, &
4379 trace_spherical_profile_time()-t0)
4385 call trace_interp_weights_block(x,igrid,ixi^
l,ixbl^
d,xd^
d,dxc^
d,status)
4387 if (trace_spherical_profile_enabled)
then
4388 call trace_spherical_profile_add_count(trace_profile_context_failures, &
4390 call trace_spherical_profile_add_time(trace_profile_time_context, &
4391 trace_spherical_profile_time()-t0)
4396 call trace_spherical_interp_ctx_fill(x,igrid,ixbl^
d,xd^
d,dxc^
d,ctx, &
4399 call trace_spherical_interp_ctx_load_bcorners(ctx,status)
4401 if (trace_spherical_profile_enabled)
then
4403 call trace_spherical_profile_add_count(trace_profile_context_failures, &
4406 call trace_spherical_profile_add_time(trace_profile_time_context, &
4407 trace_spherical_profile_time()-t0)
4410 end subroutine trace_spherical_interp_ctx_build
4412 subroutine trace_spherical_interp_ctx_build_cached(x,igrid,cache,ctx,status)
4413 double precision,
intent(in) :: x(
ndim)
4414 integer,
intent(in) :: igrid
4415 type(trace_sph_interp_ctx),
intent(inout) :: cache
4416 type(trace_sph_interp_ctx),
intent(out) :: ctx
4417 integer,
intent(out) :: status
4419 double precision :: xd^
d,dxc^
d
4420 double precision :: t0
4421 integer :: ixi^
l,ixbl^
d
4422 logical :: same_cell
4424 if (trace_spherical_profile_enabled)
then
4425 call trace_spherical_profile_add_count(trace_profile_context_requests, &
4427 t0=trace_spherical_profile_time()
4431 if (
ndim/=3 .or. geo_coordinate/=geo_spherical .or. igrid<0)
then
4432 if (trace_spherical_profile_enabled)
then
4433 call trace_spherical_profile_add_count(trace_profile_context_failures, &
4435 call trace_spherical_profile_add_time(trace_profile_time_context, &
4436 trace_spherical_profile_time()-t0)
4438 call trace_spherical_interp_ctx_build(x,igrid,ctx,status)
4443 if (cache%valid .and. cache%igrid==igrid)
then
4445 call trace_interp_weights_block_near(x,igrid,ixi^
l,cache%ixbl, &
4446 ixbl^
d,xd^
d,dxc^
d,status)
4448 call trace_spherical_interp_ctx_fill(x,igrid,ixbl^
d,xd^
d,dxc^
d, &
4451 same_cell=(ixbl1==cache%ixbl(1) .and. ixbl2==cache%ixbl(2) .and. &
4452 ixbl3==cache%ixbl(3))
4453 if (same_cell .and. cache%bcorner_valid)
then
4454 ctx%bcorner_valid=.true.
4455 ctx%bcorner=cache%bcorner
4456 if (trace_spherical_profile_enabled)
then
4457 call trace_spherical_profile_add_count( &
4458 trace_profile_b_corner_hits,1_8)
4461 call trace_spherical_interp_ctx_load_bcorners(ctx,status)
4466 if (trace_spherical_profile_enabled)
then
4468 call trace_spherical_profile_add_count( &
4469 trace_profile_same_cell_hits,1_8)
4471 call trace_spherical_profile_add_count( &
4472 trace_profile_same_grid_hits,1_8)
4474 call trace_spherical_profile_add_time(trace_profile_time_context, &
4475 trace_spherical_profile_time()-t0)
4477 else if (trace_spherical_profile_enabled)
then
4478 call trace_spherical_profile_add_count(trace_profile_context_failures, &
4480 call trace_spherical_profile_add_time(trace_profile_time_context, &
4481 trace_spherical_profile_time()-t0)
4485 else if (cache%valid .and. trace_spherical_profile_enabled)
then
4486 call trace_spherical_profile_add_count(trace_profile_cache_invalidations, &
4490 if (trace_spherical_profile_enabled)
then
4491 call trace_spherical_profile_add_time(trace_profile_time_context, &
4492 trace_spherical_profile_time()-t0)
4494 call trace_spherical_interp_ctx_build(x,igrid,ctx,status)
4497 end subroutine trace_spherical_interp_ctx_build_cached
4499 subroutine trace_spherical_interp_ctx_fill(x,igrid,ixbl^D,xd^D,dxc^D,ctx, &
4501 double precision,
intent(in) :: x(
ndim)
4502 integer,
intent(in) :: igrid,ixbl^
d
4503 double precision,
intent(in) :: xd^
d,dxc^
d
4504 type(trace_sph_interp_ctx),
intent(out) :: ctx
4505 integer,
intent(out) :: status
4507 if (trace_spherical_profile_enabled)
then
4508 call trace_spherical_profile_add_count(trace_profile_hlocal_evals,1_8)
4528 ctx%bcorner_valid=.false.
4531 if (
ndim/=3 .or. geo_coordinate/=geo_spherical .or. igrid<0)
return
4536 ctx%ixbl=(/ixbl1,ixbl2,ixbl3/)
4537 ctx%xd=(/xd1,xd2,xd3/)
4538 ctx%dxc=(/dxc1,dxc2,dxc3/)
4546 ctx%dxloc(1)=min(abs(ps(igrid)%dx(ixbl1,ixbl2,ixbl3,1)), &
4547 abs(ps(igrid)%dx(ixbl1+1,ixbl2,ixbl3,1)))
4548 ctx%dxloc(2)=min(abs(ps(igrid)%dx(ixbl1,ixbl2,ixbl3,2)), &
4549 abs(ps(igrid)%dx(ixbl1,ixbl2+1,ixbl3,2)))
4550 ctx%dxloc(3)=min(abs(ps(igrid)%dx(ixbl1,ixbl2,ixbl3,3)), &
4551 abs(ps(igrid)%dx(ixbl1,ixbl2,ixbl3+1,3)))
4552 ctx%dxloc=max(ctx%dxloc,smalldouble)
4557 ctx%sin_theta=dsin(ctx%theta)
4558 ctx%cos_theta=dcos(ctx%theta)
4559 ctx%sin_phi=dsin(ctx%phi)
4560 ctx%cos_phi=dcos(ctx%phi)
4561 ctx%rsin_theta=ctx%r*ctx%sin_theta
4562 if (ctx%r<=smalldouble .or. abs(ctx%sin_theta)<=smalldouble)
then
4567 ctx%h_local=trace_spherical_cell_scale_from_widths(ctx%r, &
4568 ctx%sin_theta,ctx%dxloc)
4569 ctx%h_local=max(ctx%h_local,smalldouble)
4573 end subroutine trace_spherical_interp_ctx_fill
4575 subroutine trace_spherical_interp_ctx_load_bcorners(ctx,status)
4576 type(trace_sph_interp_ctx),
intent(inout) :: ctx
4577 integer,
intent(out) :: status
4579 integer :: i1,i2,i3,igrid,ix1,ix2,ix3
4582 if (.not.ctx%valid)
return
4583 if (ctx%bcorner_valid)
then
4584 if (trace_spherical_profile_enabled)
then
4585 call trace_spherical_profile_add_count(trace_profile_b_corner_hits, &
4591 if (.not.
b0field .and. .not.
allocated(iw_mag))
return
4602 if (
allocated(iw_mag))
then
4603 ctx%bcorner(i1,i2,i3,1:3)= &
4604 ps(igrid)%w(ix1,ix2,ix3,iw_mag(1:3))
4607 ctx%bcorner(i1,i2,i3,1:3)= &
4608 ctx%bcorner(i1,i2,i3,1:3) &
4609 +ps(igrid)%B0(ix1,ix2,ix3,1:3,0)
4614 ctx%bcorner_valid=.true.
4615 if (trace_spherical_profile_enabled)
then
4616 call trace_spherical_profile_add_count(trace_profile_b_corner_loads, &
4621 end subroutine trace_spherical_interp_ctx_load_bcorners
4623 double precision function trace_spherical_effective_step_ctx(ds,ctx) &
4625 double precision,
intent(in) :: ds
4626 type(trace_sph_interp_ctx),
intent(in) :: ctx
4628 double precision :: step_cap,t0
4630 if (trace_spherical_profile_enabled) t0=trace_spherical_profile_time()
4633 if (.not.ctx%valid)
then
4634 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4635 trace_profile_time_step,trace_spherical_profile_time()-t0)
4639 if (ctx%h_local<=zero)
then
4640 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4641 trace_profile_time_step,trace_spherical_profile_time()-t0)
4644 select case (trace_step_control_mode)
4645 case (trace_step_control_cell_fraction)
4646 ds_eff=min(step_cap,trace_step_fraction*ctx%h_local)
4647 if (trace_step_min>zero) ds_eff=max(ds_eff,min(trace_step_min,step_cap))
4649 ds_eff=min(step_cap,ctx%h_local)
4651 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4652 trace_profile_time_step,trace_spherical_profile_time()-t0)
4653 end function trace_spherical_effective_step_ctx
4655 subroutine trace_spherical_sample_bsph_ctx(ctx,threshold,Bsph,status)
4656 type(trace_sph_interp_ctx),
intent(in) :: ctx
4657 double precision,
intent(in) :: threshold
4658 double precision,
intent(out) :: bsph(3)
4659 integer,
intent(out) :: status
4661 double precision :: b2,weight
4662 double precision :: t0
4663 integer :: i1,i2,i3,j
4665 if (trace_spherical_profile_enabled)
then
4666 call trace_spherical_profile_add_count(trace_profile_b_samples,1_8)
4667 t0=trace_spherical_profile_time()
4672 if (.not.ctx%valid)
then
4673 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4674 trace_profile_time_b_interp,trace_spherical_profile_time()-t0)
4677 if (.not.ctx%bcorner_valid)
then
4678 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4679 trace_profile_time_b_interp,trace_spherical_profile_time()-t0)
4687 weight=ctx%w(i1,1)*ctx%w(i2,2)*ctx%w(i3,3)
4689 bsph(j)=bsph(j)+ctx%bcorner(i1,i2,i3,j)*weight
4695 if (b2<=zero .or. dsqrt(b2)<threshold)
then
4697 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4698 trace_profile_time_b_interp,trace_spherical_profile_time()-t0)
4702 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4703 trace_profile_time_b_interp,trace_spherical_profile_time()-t0)
4705 end subroutine trace_spherical_sample_bsph_ctx
4707 subroutine trace_spherical_sample_b_bhat_cart_ctx(ctx,threshold,Bcart, &
4709 type(trace_sph_interp_ctx),
intent(in) :: ctx
4710 double precision,
intent(in) :: threshold
4711 double precision,
intent(out) :: bcart(3),bhat_cart(3)
4712 integer,
intent(out) :: status
4714 double precision :: bsph(3),bnorm
4718 call trace_spherical_sample_bsph_ctx(ctx,threshold,bsph,status)
4721 bcart(1)=bsph(1)*ctx%sin_theta*ctx%cos_phi &
4722 +bsph(2)*ctx%cos_theta*ctx%cos_phi &
4723 -bsph(3)*ctx%sin_phi
4724 bcart(2)=bsph(1)*ctx%sin_theta*ctx%sin_phi &
4725 +bsph(2)*ctx%cos_theta*ctx%sin_phi &
4726 +bsph(3)*ctx%cos_phi
4727 bcart(3)=bsph(1)*ctx%cos_theta-bsph(2)*ctx%sin_theta
4728 bnorm=dsqrt(sum(bcart**2))
4729 if (bnorm<=zero .or. bnorm<threshold)
then
4733 bhat_cart=bcart/bnorm
4735 end subroutine trace_spherical_sample_b_bhat_cart_ctx
4737 subroutine trace_spherical_sample_cached_curlb_ctx(ctx,curlB,status)
4738 type(trace_sph_interp_ctx),
intent(in) :: ctx
4739 double precision,
intent(out) :: curlb(3)
4740 integer,
intent(out) :: status
4742 double precision :: weight
4743 double precision :: t0
4744 integer :: i1,i2,i3,j,igrid,ix1,ix2,ix3
4746 if (trace_spherical_profile_enabled)
then
4747 call trace_spherical_profile_add_count(trace_profile_curl_samples,1_8)
4748 t0=trace_spherical_profile_time()
4753 if (.not.ctx%valid)
then
4754 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4755 trace_profile_time_curl_interp,trace_spherical_profile_time()-t0)
4758 if (.not.trace_spherical_curl_cache_ready)
then
4759 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4760 trace_profile_time_curl_interp,trace_spherical_profile_time()-t0)
4763 if (.not.
allocated(trace_spherical_curl_cache))
then
4764 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4765 trace_profile_time_curl_interp,trace_spherical_profile_time()-t0)
4769 if (igrid>
size(trace_spherical_curl_cache))
then
4770 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4771 trace_profile_time_curl_interp,trace_spherical_profile_time()-t0)
4774 if (.not.trace_spherical_curl_cache(igrid)%ready)
then
4775 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4776 trace_profile_time_curl_interp,trace_spherical_profile_time()-t0)
4779 if (.not.
allocated(trace_spherical_curl_cache(igrid)%current))
then
4780 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4781 trace_profile_time_curl_interp,trace_spherical_profile_time()-t0)
4792 weight=ctx%w(i1,1)*ctx%w(i2,2)*ctx%w(i3,3)
4794 curlb(j)=curlb(j)+ &
4795 trace_spherical_curl_cache(igrid)%current(ix1,ix2,ix3,j) &
4802 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4803 trace_profile_time_curl_interp,trace_spherical_profile_time()-t0)
4805 end subroutine trace_spherical_sample_cached_curlb_ctx
4807 subroutine trace_spherical_sample_bhat_gradbhat_covariant_ctx(ctx, &
4808 threshold,bhat_cart,grad_bhat_cart,status)
4809 type(trace_sph_interp_ctx),
intent(in) :: ctx
4810 double precision,
intent(in) :: threshold
4811 double precision,
intent(out) :: bhat_cart(3),grad_bhat_cart(3,3)
4812 integer,
intent(out) :: status
4814 double precision :: dw(0:1,3),weight,bnorm,projected
4815 double precision :: bsph(3),bhat_sph(3),dbdq(3,3),dbhatdq(3,3)
4816 double precision :: a_local(3,3),e(3,3)
4817 double precision :: t0
4818 integer :: i1,i2,i3,j
4820 if (trace_spherical_profile_enabled)
then
4821 call trace_spherical_profile_add_count(trace_profile_grad_samples,1_8)
4822 t0=trace_spherical_profile_time()
4828 if (.not.ctx%valid)
then
4829 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4830 trace_profile_time_grad_bhat,trace_spherical_profile_time()-t0)
4833 if (.not.ctx%bcorner_valid)
then
4835 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4836 trace_profile_time_grad_bhat,trace_spherical_profile_time()-t0)
4841 dw(0,1)=-one/ctx%dxc(1)
4842 dw(1,1)= one/ctx%dxc(1)
4843 dw(0,2)=-one/ctx%dxc(2)
4844 dw(1,2)= one/ctx%dxc(2)
4845 dw(0,3)=-one/ctx%dxc(3)
4846 dw(1,3)= one/ctx%dxc(3)
4853 weight=ctx%w(i1,1)*ctx%w(i2,2)*ctx%w(i3,3)
4854 bsph(1:3)=bsph(1:3)+ctx%bcorner(i1,i2,i3,1:3)*weight
4855 dbdq(1:3,1)=dbdq(1:3,1)+ctx%bcorner(i1,i2,i3,1:3)* &
4856 dw(i1,1)*ctx%w(i2,2)*ctx%w(i3,3)
4857 dbdq(1:3,2)=dbdq(1:3,2)+ctx%bcorner(i1,i2,i3,1:3)* &
4858 ctx%w(i1,1)*dw(i2,2)*ctx%w(i3,3)
4859 dbdq(1:3,3)=dbdq(1:3,3)+ctx%bcorner(i1,i2,i3,1:3)* &
4860 ctx%w(i1,1)*ctx%w(i2,2)*dw(i3,3)
4865 bnorm=dsqrt(sum(bsph**2))
4866 if (bnorm<=zero .or. bnorm<threshold)
then
4868 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4869 trace_profile_time_grad_bhat,trace_spherical_profile_time()-t0)
4875 projected=sum(bhat_sph*dbdq(1:3,j))
4876 dbhatdq(1:3,j)=(dbdq(1:3,j)-bhat_sph(1:3)*projected)/bnorm
4879 e(1:3,1)=(/ctx%sin_theta*ctx%cos_phi, &
4880 ctx%sin_theta*ctx%sin_phi,ctx%cos_theta/)
4881 e(1:3,2)=(/ctx%cos_theta*ctx%cos_phi, &
4882 ctx%cos_theta*ctx%sin_phi,-ctx%sin_theta/)
4883 e(1:3,3)=(/-ctx%sin_phi,ctx%cos_phi,zero/)
4884 bhat_cart=bhat_sph(1)*e(1:3,1)+bhat_sph(2)*e(1:3,2) &
4885 +bhat_sph(3)*e(1:3,3)
4887 a_local(1:3,1)=dbhatdq(1:3,1)
4888 a_local(1,2)=(dbhatdq(1,2)-bhat_sph(2))/ctx%r
4889 a_local(2,2)=(dbhatdq(2,2)+bhat_sph(1))/ctx%r
4890 a_local(3,2)= dbhatdq(3,2)/ctx%r
4891 a_local(1,3)=(dbhatdq(1,3)-ctx%sin_theta*bhat_sph(3))/ctx%rsin_theta
4892 a_local(2,3)=(dbhatdq(2,3)-ctx%cos_theta*bhat_sph(3))/ctx%rsin_theta
4893 a_local(3,3)=(dbhatdq(3,3)+ctx%sin_theta*bhat_sph(1) &
4894 +ctx%cos_theta*bhat_sph(2))/ctx%rsin_theta
4896 grad_bhat_cart=matmul(e,matmul(a_local,transpose(e)))
4898 if (trace_spherical_profile_enabled)
then
4899 call trace_spherical_profile_add_count(trace_profile_grad_success,1_8)
4900 call trace_spherical_profile_add_time(trace_profile_time_grad_bhat, &
4901 trace_spherical_profile_time()-t0)
4904 end subroutine trace_spherical_sample_bhat_gradbhat_covariant_ctx
4906 subroutine get_k_spherical_ctx(ctx,K,ftype,b_min,field_ok)
4907 type(trace_sph_interp_ctx),
intent(in) :: ctx
4908 double precision,
intent(out) :: k(
ndim)
4909 character(len=std_len),
intent(in) :: ftype
4910 double precision,
intent(in),
optional :: b_min
4911 logical,
intent(out),
optional :: field_ok
4913 double precision :: b(3),ftotal,field_min
4914 logical :: valid_field
4919 if (ftype/=
'Bfield')
then
4920 if (
present(field_ok)) field_ok=.false.
4923 call trace_spherical_sample_bsph_ctx(ctx,zero,b,status)
4925 if (
present(field_ok)) field_ok=.false.
4928 ftotal=dsqrt(sum(b**2))
4929 field_min=smalldouble
4930 if (
present(b_min)) field_min=max(b_min,zero)
4931 valid_field=ftotal>zero .and. ftotal>=field_min
4932 if (
present(field_ok)) field_ok=valid_field
4933 if (.not.valid_field)
return
4937 k(2)=b(2)/(ctx%r*ftotal)
4938 k(3)=b(3)/(ctx%rsin_theta*ftotal)
4940 end subroutine get_k_spherical_ctx
4942 subroutine trace_spherical_sample_b_bhat_cart(x,igrid,threshold,Bcart, &
4944 double precision,
intent(in) :: x(
ndim),threshold
4945 integer,
intent(in) :: igrid
4946 double precision,
intent(out) :: bcart(3),bhat_cart(3)
4947 integer,
intent(out) :: status
4949 type(trace_sph_interp_ctx) :: ctx
4954 if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
return
4957 call trace_spherical_interp_ctx_build(x,igrid,ctx,status)
4959 call trace_spherical_sample_b_bhat_cart_ctx(ctx,threshold,bcart, &
4962 end subroutine trace_spherical_sample_b_bhat_cart
4964 subroutine trace_spherical_sample_bhat_gradbhat_covariant(x,igrid, &
4965 threshold,bhat_cart,grad_bhat_cart,status)
4966 double precision,
intent(in) :: x(
ndim),threshold
4967 integer,
intent(in) :: igrid
4968 double precision,
intent(out) :: bhat_cart(3),grad_bhat_cart(3,3)
4969 integer,
intent(out) :: status
4971 type(trace_sph_interp_ctx) :: ctx
4976 if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
return
4979 call trace_spherical_interp_ctx_build(x,igrid,ctx,status)
4981 call trace_spherical_sample_bhat_gradbhat_covariant_ctx(ctx,threshold, &
4982 bhat_cart,grad_bhat_cart,status)
4984 end subroutine trace_spherical_sample_bhat_gradbhat_covariant
4986 subroutine trace_spherical_sample_bhat_gradbhat_cartfd(x,igrid,threshold, &
4987 bhat,grad_bhat,status)
4988 double precision,
intent(in) :: x(
ndim),threshold
4989 integer,
intent(in) :: igrid
4990 double precision,
intent(out) :: bhat(3),grad_bhat(3,3)
4991 integer,
intent(out) :: status
4993 double precision :: xcart(3),xplus_cart(3),xminus_cart(3)
4994 double precision :: xplus(
ndim),xminus(
ndim),bplus(3),bminus(3)
4995 double precision :: btmp(3),eps
4996 integer :: j,igrid_plus,igrid_minus,status_plus,status_minus
5001 if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
return
5004 call trace_spherical_sample_b_bhat_cart(x,igrid,threshold,btmp,bhat, &
5007 call trace_spherical_coord_to_cart(x,xcart,status)
5010 eps=max(1.
d-8*max(one,abs(x(1))), &
5011 0.01d0*trace_spherical_physical_cell_scale(x,igrid))
5015 xplus_cart(j)=xplus_cart(j)+eps
5016 xminus_cart(j)=xminus_cart(j)-eps
5019 call trace_cart_to_spherical_coord(xplus_cart,xplus,status_plus)
5021 call trace_locate_point_with_hint(xplus,igrid,igrid_plus,status_plus)
5024 call trace_spherical_sample_b_bhat_cart(xplus,igrid_plus,threshold, &
5025 btmp,bplus,status_plus)
5029 call trace_cart_to_spherical_coord(xminus_cart,xminus,status_minus)
5031 call trace_locate_point_with_hint(xminus,igrid,igrid_minus, &
5035 call trace_spherical_sample_b_bhat_cart(xminus,igrid_minus,threshold, &
5036 btmp,bminus,status_minus)
5041 grad_bhat(:,j)=(bplus-bminus)/(2.d0*eps)
5043 grad_bhat(:,j)=(bplus-bhat)/eps
5045 grad_bhat(:,j)=(bhat-bminus)/eps
5053 end subroutine trace_spherical_sample_bhat_gradbhat_cartfd
5055 subroutine trace_spherical_bhat_cart_to_rhs(x,bhat_cart,kx,status)
5056 double precision,
intent(in) :: x(
ndim),bhat_cart(3)
5057 double precision,
intent(out) :: kx(
ndim)
5058 integer,
intent(out) :: status
5060 double precision :: er(3),etheta(3),ephi(3),r,sint
5064 if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
return
5067 call trace_spherical_basis(x,er,etheta,ephi,status)
5071 if (r<=smalldouble .or. abs(sint)<=smalldouble)
then
5075 kx(1)=sum(bhat_cart*er)
5076 kx(2)=sum(bhat_cart*etheta)/r
5077 kx(3)=sum(bhat_cart*ephi)/(r*sint)
5080 end subroutine trace_spherical_bhat_cart_to_rhs
5082 subroutine trace_spherical_endpoint_b_bhat(x,face_id,igrid,threshold,B, &
5084 double precision,
intent(in) :: x(
ndim),threshold
5085 integer,
intent(in) :: face_id,igrid
5086 double precision,
intent(out) :: b(
ndim),bhat(
ndim)
5087 integer,
intent(out) :: status
5089 double precision :: xprobe(
ndim),bcart(3),bhat_cart(3)
5090 integer :: normal_dim,sample_igrid
5095 if (
ndim/=3 .or. geo_coordinate/=geo_spherical .or. igrid<0)
then
5099 if (.not.trace_face_is_boundary(face_id))
return
5102 select case(face_id)
5120 call trace_spherical_face_probe_coord(face_id,igrid, &
5121 xprobe(normal_dim),status)
5123 xprobe(1)=max(xprobmin1,min(xprobe(1), &
5124 xprobmax1-100.d0*epsilon(one)*max(one,abs(xprobmax1))))
5125 xprobe(2)=max(xprobmin2,min(xprobe(2), &
5126 xprobmax2-100.d0*epsilon(one)*max(one,abs(xprobmax2))))
5127 xprobe(3)=max(xprobmin3,min(xprobe(3), &
5128 xprobmax3-100.d0*epsilon(one)*max(one,abs(xprobmax3))))
5129 call trace_debug_locate_point(xprobe,sample_igrid,status)
5131 call trace_spherical_sample_b_bhat_cart(xprobe,sample_igrid,threshold, &
5132 bcart,bhat_cart,status)
5135 bhat=bhat_cart(1:
ndim)
5138 end subroutine trace_spherical_endpoint_b_bhat
5140 subroutine trace_spherical_face_probe_coord(face_id,igrid,xprobe,status)
5141 integer,
intent(in) :: face_id,igrid
5142 double precision,
intent(out) :: xprobe
5143 integer,
intent(out) :: status
5145 integer :: i1,i2,i3,normal_dim,side
5147 if (trace_spherical_profile_enabled)
then
5148 call trace_spherical_profile_add_count(trace_profile_face_probes,1_8)
5153 if (
ndim/=3 .or. geo_coordinate/=geo_spherical .or. igrid<0)
then
5162 select case(face_id)
5191 xprobe=ps(igrid)%x(i1,i2,i3,normal_dim)
5193 if (xprobe<xprobmin1 .and. normal_dim==1)
return
5194 if (xprobe<xprobmin2 .and. normal_dim==2)
return
5195 if (xprobe<xprobmin3 .and. normal_dim==3)
return
5197 if (xprobe>xprobmax1 .and. normal_dim==1)
return
5198 if (xprobe>xprobmax2 .and. normal_dim==2)
return
5199 if (xprobe>xprobmax3 .and. normal_dim==3)
return
5203 end subroutine trace_spherical_face_probe_coord
5205 double precision function trace_spherical_physical_cell_scale(x,igrid) &
5207 double precision,
intent(in) :: x(
ndim)
5208 integer,
intent(in) :: igrid
5210 double precision :: r,sint,dxloc(
ndim)
5214 if (
ndim/=3 .or. geo_coordinate/=geo_spherical .or. igrid<0)
return
5217 call trace_spherical_local_cell_widths(x,igrid,dxloc,status)
5219 r=max(abs(x(1)),smalldouble)
5220 sint=max(abs(dsin(x(2))),smalldouble)
5221 cell_scale=trace_spherical_cell_scale_from_widths(r,sint,dxloc)
5223 end function trace_spherical_physical_cell_scale
5225 double precision function trace_spherical_cell_scale_from_widths(r,sint, &
5226 dxloc)
result(cell_scale)
5227 double precision,
intent(in) :: r,sint,dxloc(
ndim)
5231 cell_scale=min(abs(dxloc(1)),abs(r)*abs(dxloc(2)))
5232 cell_scale=min(cell_scale,abs(r)*max(abs(sint),smalldouble)* &
5234 cell_scale=max(cell_scale,smalldouble)
5236 end function trace_spherical_cell_scale_from_widths
5239 double precision,
intent(out) :: hmin
5240 integer,
intent(out) :: status
5242 double precision :: dxloc(
ndim),hcell,r,sint
5243 integer :: iigrid,igrid,ix1,ix2,ix3
5247 if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
return
5253 do ix3=ixmlo3,ixmhi3
5254 do ix2=ixmlo2,ixmhi2
5255 do ix1=ixmlo1,ixmhi1
5256 r=ps(igrid)%x(ix1,ix2,ix3,1)
5257 sint=dsin(ps(igrid)%x(ix1,ix2,ix3,2))
5258 if (r<=smalldouble .or. abs(sint)<=smalldouble) cycle
5259 dxloc(1)=abs(ps(igrid)%dx(ix1,ix2,ix3,1))
5260 dxloc(2)=abs(ps(igrid)%dx(ix1,ix2,ix3,2))
5261 dxloc(3)=abs(ps(igrid)%dx(ix1,ix2,ix3,3))
5262 hcell=trace_spherical_cell_scale_from_widths(r,sint,dxloc)
5263 hmin=min(hmin,hcell)
5273 double precision,
intent(out) :: hmin
5274 integer,
intent(out) :: status
5276 double precision :: hlocal,hcell
5277 integer :: iigrid,igrid,ix1,ix2,ix3
5282 if (
ndim/=3 .or. .not.trace_cartesian_like_geometry())
return
5288 do ix3=ixmlo3,ixmhi3
5289 do ix2=ixmlo2,ixmhi2
5290 do ix1=ixmlo1,ixmhi1
5291 hcell=min(abs(ps(igrid)%dx(ix1,ix2,ix3,1)), &
5292 abs(ps(igrid)%dx(ix1,ix2,ix3,2)))
5293 hcell=min(hcell,abs(ps(igrid)%dx(ix1,ix2,ix3,3)))
5294 if (hcell>zero) hlocal=min(hlocal,hcell)
5300 call mpi_allreduce(hlocal,hmin,1,mpi_double_precision,mpi_min, &
5309 logical function trace_cartesian_like_geometry()
result(is_cart_like)
5310 is_cart_like=.false.
5313 select case (geo_coordinate)
5314 case (geo_cartesian,geo_cartesian_stretched)
5318 end function trace_cartesian_like_geometry
5320 logical function trace_rk45_position_integrator()
result(is_rk45)
5324 select case (trace_integrator_mode)
5325 case (trace_integrator_rk45_cartesian)
5326 is_rk45=trace_cartesian_like_geometry()
5327 case (trace_integrator_rk45_spherical)
5328 is_rk45=geo_coordinate==geo_spherical
5331 end function trace_rk45_position_integrator
5333 subroutine trace_interp_weights_block(x,igrid,ixI^L,ixbl^D,xd^D,dxc^D, &
5335 double precision,
intent(in) :: x(
ndim)
5336 integer,
intent(in) :: igrid,ixi^
l
5337 integer,
intent(out) :: ixbl^
d,status
5338 double precision,
intent(out) :: xd^
d,dxc^
d
5347 call trace_interp_index_3d(x(1),igrid,1,ixi^
l,ixbl1,xd1,dxc1,status)
5349 call trace_interp_index_3d(x(2),igrid,2,ixi^
l,ixbl2,xd2,dxc2,status)
5351 call trace_interp_index_3d(x(3),igrid,3,ixi^
l,ixbl3,xd3,dxc3,status)
5353 end subroutine trace_interp_weights_block
5355 subroutine trace_interp_weights_block_near(x,igrid,ixI^L,ixstart,ixbl^D, &
5357 double precision,
intent(in) :: x(
ndim)
5358 integer,
intent(in) :: igrid,ixi^
l
5359 integer,
intent(in) :: ixstart(3)
5360 integer,
intent(out) :: ixbl^
d,status
5361 double precision,
intent(out) :: xd^
d,dxc^
d
5370 call trace_interp_index_3d_near(x(1),igrid,1,ixi^
l,ixstart(1), &
5371 ixbl1,xd1,dxc1,status)
5373 call trace_interp_index_3d_near(x(2),igrid,2,ixi^
l,ixstart(2), &
5374 ixbl2,xd2,dxc2,status)
5376 call trace_interp_index_3d_near(x(3),igrid,3,ixi^
l,ixstart(3), &
5377 ixbl3,xd3,dxc3,status)
5379 end subroutine trace_interp_weights_block_near
5381 subroutine trace_interp_index_3d(xval,igrid,idim,ixI^L,ixlo,frac,dxc, &
5383 double precision,
intent(in) :: xval
5384 integer,
intent(in) :: igrid,idim,ixi^
l
5385 integer,
intent(out) :: ixlo,status
5386 double precision,
intent(out) :: frac,dxc
5388 double precision :: xlo,xhi,tol
5400 do i=iximin1,iximax1-1
5401 xlo=ps(igrid)%x(i,iximin2,iximin3,1)
5402 xhi=ps(igrid)%x(i+1,iximin2,iximin3,1)
5404 tol=100.d0*epsilon(one)*max(one,max(abs(xlo),abs(xhi)))
5405 if (abs(dxc)<=smalldouble) cycle
5406 if (xval>=min(xlo,xhi)-tol .and. &
5407 xval<=max(xlo,xhi)+tol)
then
5409 frac=max(zero,min(one,(xval-xlo)/dxc))
5415 do i=iximin2,iximax2-1
5416 xlo=ps(igrid)%x(iximin1,i,iximin3,2)
5417 xhi=ps(igrid)%x(iximin1,i+1,iximin3,2)
5419 tol=100.d0*epsilon(one)*max(one,max(abs(xlo),abs(xhi)))
5420 if (abs(dxc)<=smalldouble) cycle
5421 if (xval>=min(xlo,xhi)-tol .and. &
5422 xval<=max(xlo,xhi)+tol)
then
5424 frac=max(zero,min(one,(xval-xlo)/dxc))
5430 do i=iximin3,iximax3-1
5431 xlo=ps(igrid)%x(iximin1,iximin2,i,3)
5432 xhi=ps(igrid)%x(iximin1,iximin2,i+1,3)
5434 tol=100.d0*epsilon(one)*max(one,max(abs(xlo),abs(xhi)))
5435 if (abs(dxc)<=smalldouble) cycle
5436 if (xval>=min(xlo,xhi)-tol .and. &
5437 xval<=max(xlo,xhi)+tol)
then
5439 frac=max(zero,min(one,(xval-xlo)/dxc))
5446 end subroutine trace_interp_index_3d
5448 subroutine trace_interp_index_3d_near(xval,igrid,idim,ixI^L,ixstart, &
5449 ixlo,frac,dxc,status)
5450 double precision,
intent(in) :: xval
5451 integer,
intent(in) :: igrid,idim,ixi^
l,ixstart
5452 integer,
intent(out) :: ixlo,status
5453 double precision,
intent(out) :: frac,dxc
5455 double precision :: xlo,xhi,tol
5456 integer :: i,ilo,ihi,idir
5479 i=max(ilo,min(ixstart,ihi))
5483 xlo=ps(igrid)%x(i,iximin2,iximin3,1)
5484 xhi=ps(igrid)%x(i+1,iximin2,iximin3,1)
5486 xlo=ps(igrid)%x(iximin1,i,iximin3,2)
5487 xhi=ps(igrid)%x(iximin1,i+1,iximin3,2)
5489 xlo=ps(igrid)%x(iximin1,iximin2,i,3)
5490 xhi=ps(igrid)%x(iximin1,iximin2,i+1,3)
5493 tol=100.d0*epsilon(one)*max(one,max(abs(xlo),abs(xhi)))
5494 if (abs(dxc)>smalldouble .and. &
5495 xval>=min(xlo,xhi)-tol .and. &
5496 xval<=max(xlo,xhi)+tol)
then
5498 frac=max(zero,min(one,(xval-xlo)/dxc))
5503 if (abs(dxc)<=smalldouble)
then
5505 else if (xval<min(xlo,xhi)-tol)
then
5512 if (i<ilo .or. i>ihi)
exit
5515 end subroutine trace_interp_index_3d_near
5517 subroutine trace_spherical_local_cell_widths(x,igrid,dxloc,status)
5518 double precision,
intent(in) :: x(
ndim)
5519 integer,
intent(in) :: igrid
5520 double precision,
intent(out) :: dxloc(
ndim)
5521 integer,
intent(out) :: status
5523 type(trace_sph_interp_ctx) :: ctx
5527 if (
ndim/=3 .or. geo_coordinate/=geo_spherical .or. igrid<0)
return
5530 call trace_spherical_interp_ctx_build(x,igrid,ctx,status)
5532 dxloc(1:3)=ctx%dxloc(1:3)
5534 end subroutine trace_spherical_local_cell_widths
5536 subroutine trace_debug_locate_point(x,igrid,status)
5539 double precision,
intent(in) :: x(
ndim)
5540 integer,
intent(out) :: igrid,status
5542 double precision :: x3d(3)
5543 integer :: indomain,ipe,j
5548 {
if (x(^db)>=xprobmin^db .and. x(^db)<xprobmax^db) indomain=indomain+1\}
5549 if (indomain/=
ndim)
then
5559 if (igrid<0 .or. ipe/=
mype)
then
5562 end subroutine trace_debug_locate_point
5564 subroutine trace_locate_point_with_hint(x,igrid_hint,igrid,status)
5565 double precision,
intent(in) :: x(
ndim)
5566 integer,
intent(in) :: igrid_hint
5567 integer,
intent(out) :: igrid,status
5569 double precision :: xbmin^
d,xbmax^
d
5574 if (igrid_hint>=0)
then
5578 {
if (x(^db)>xbmin^db .and. x(^db)<xbmax^db) inblock=inblock+1\}
5579 if (inblock==
ndim)
then
5585 call trace_debug_locate_point(x,igrid,status)
5586 end subroutine trace_locate_point_with_hint
5588 subroutine trace_tangent_rhs(x,u,v,igrid,threshold,kx,ku,kv,status, &
5590 double precision,
intent(in) :: x(
ndim),u(
ndim),v(
ndim),threshold
5591 integer,
intent(in) :: igrid
5592 double precision,
intent(out) :: kx(
ndim),ku(
ndim),kv(
ndim)
5593 integer,
intent(out) :: status
5594 double precision,
intent(in),
optional :: p(
ndim),q(
ndim)
5595 double precision,
intent(out),
optional :: kp(
ndim),kq(
ndim)
5596 type(trace_sph_interp_ctx),
intent(in),
optional :: sph_ctx
5598 double precision :: bhat(3),grad_bhat(3,3)
5599 double precision :: u3(3),v3(3),p3(3),q3(3)
5600 double precision :: ku3(3),kv3(3),kp3(3),kq3(3)
5606 if (
present(kp)) kp=zero
5607 if (
present(kq)) kq=zero
5610 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_rhs()
5613 if (geo_coordinate==geo_spherical)
then
5615 if (
present(sph_ctx))
then
5616 use_ctx=sph_ctx%valid .and. sph_ctx%igrid==igrid .and. &
5617 maxval(abs(sph_ctx%x(1:3)-x(1:3))) <= &
5618 100.d0*epsilon(one)*max(one,maxval(abs(x(1:3))))
5621 call trace_spherical_sample_bhat_gradbhat_covariant_ctx(sph_ctx, &
5622 threshold,bhat,grad_bhat,status)
5624 call trace_spherical_sample_bhat_gradbhat_covariant(x,igrid, &
5625 threshold,bhat,grad_bhat,status)
5628 if (trace_spherical_profile_enabled)
then
5629 call trace_spherical_profile_add_count(trace_profile_grad_fallbacks, &
5632 call trace_spherical_sample_bhat_gradbhat_cartfd(x,igrid,threshold, &
5633 bhat,grad_bhat,status)
5636 call trace_spherical_bhat_cart_to_rhs(x,bhat,kx,status)
5639 call sample_bhat_gradbhat_at_point(x,igrid,threshold,bhat,grad_bhat,status)
5649 ku3=matmul(grad_bhat,u3)
5650 kv3=matmul(grad_bhat,v3)
5653 if (
present(p) .and.
present(q) .and.
present(kp) .and. &
5659 kp3=matmul(grad_bhat,p3)
5660 kq3=matmul(grad_bhat,q3)
5665 end subroutine trace_tangent_rhs
5667 subroutine trace_advance_tangent_state_rk2(x,u,v,igrid,h,threshold,status)
5668 double precision,
intent(inout) :: x(
ndim),u(
ndim),v(
ndim)
5669 integer,
intent(inout) :: igrid
5670 double precision,
intent(in) :: h,threshold
5671 integer,
intent(out) :: status
5674 integer :: igrid_mid,igrid_new
5676 call trace_tangent_rk2_trial(x,u,v,igrid,h,threshold,xnew,unew,vnew, &
5680 call trace_debug_locate_point(xnew,igrid_new,status)
5687 end subroutine trace_advance_tangent_state_rk2
5689 subroutine trace_tangent_rk2_trial(x,u,v,igrid,h,threshold,xnew,unew, &
5691 double precision,
intent(in) :: x(
ndim),u(
ndim),v(
ndim),h,threshold
5692 integer,
intent(in) :: igrid
5693 double precision,
intent(out) :: xnew(
ndim),unew(
ndim),vnew(
ndim)
5694 integer,
intent(out) :: status
5698 call trace_tangent_rhs(x,u,v,igrid,threshold,kx1,ku1,kv1,status)
5701 call trace_tangent_rk2_trial_from_rhs(x,u,v,igrid,h,threshold, &
5702 kx1,ku1,kv1,xnew,unew,vnew,status)
5703 end subroutine trace_tangent_rk2_trial
5705 subroutine trace_tangent_rk2_trial_from_rhs(x,u,v,igrid,h,threshold, &
5706 kx1,ku1,kv1,xnew,unew,vnew,status,p,q,kp1,kq1,pnew,qnew, &
5707 sph_cache,clamp_stage)
5708 double precision,
intent(in) :: x(
ndim),u(
ndim),v(
ndim),h,threshold
5709 double precision,
intent(in) :: kx1(
ndim),ku1(
ndim),kv1(
ndim)
5710 integer,
intent(in) :: igrid
5711 double precision,
intent(out) :: xnew(
ndim),unew(
ndim),vnew(
ndim)
5712 integer,
intent(out) :: status
5713 double precision,
intent(in),
optional :: p(
ndim),q(
ndim)
5714 double precision,
intent(in),
optional :: kp1(
ndim),kq1(
ndim)
5715 double precision,
intent(out),
optional :: pnew(
ndim),qnew(
ndim)
5716 type(trace_sph_interp_ctx),
intent(inout),
optional :: sph_cache
5717 logical,
intent(in),
optional :: clamp_stage
5720 double precision :: xmid(
ndim),xmid_sample(
ndim)
5722 type(trace_sph_interp_ctx) :: ctx_mid
5723 integer :: igrid_mid
5724 integer :: ctx_status
5725 logical :: use_clamped_stage
5730 use_clamped_stage=.false.
5731 if (
present(clamp_stage)) use_clamped_stage=clamp_stage
5733 if (use_clamped_stage)
then
5734 ^
d&xmid_sample(^
d)=max(xprobmin^
d,min(xmid_sample(^
d), &
5735 xprobmax^
d-100.d0*epsilon(one)*max(one,abs(xprobmax^
d))));
5737 call trace_locate_point_with_hint(xmid_sample,igrid,igrid_mid,status)
5740 if (geo_coordinate==geo_spherical)
then
5741 if (
present(sph_cache))
then
5742 call trace_spherical_interp_ctx_build_cached(xmid_sample,igrid_mid, &
5743 sph_cache,ctx_mid,ctx_status)
5745 call trace_spherical_interp_ctx_build(xmid_sample,igrid_mid,ctx_mid, &
5750 if (
present(p) .and.
present(q) .and.
present(kp1) .and. &
5751 present(kq1) .and.
present(pnew) .and.
present(qnew))
then
5755 call trace_tangent_rhs(xmid_sample,umid,vmid,igrid_mid,threshold,kx2,ku2, &
5756 kv2,status,pmid,qmid,kp2,kq2,sph_ctx=ctx_mid)
5758 call trace_tangent_rhs(xmid_sample,umid,vmid,igrid_mid,threshold,kx2,ku2, &
5759 kv2,status,pmid,qmid,kp2,kq2)
5763 call trace_tangent_rhs(xmid_sample,umid,vmid,igrid_mid,threshold,kx2,ku2, &
5764 kv2,status,sph_ctx=ctx_mid)
5766 call trace_tangent_rhs(xmid_sample,umid,vmid,igrid_mid,threshold,kx2,ku2, &
5775 if (
present(pnew) .and.
present(qnew))
then
5779 end subroutine trace_tangent_rk2_trial_from_rhs
5781 subroutine trace_project_to_perp_bhat(vec,bhat,vec_perp)
5782 double precision,
intent(in) :: vec(
ndim),bhat(
ndim)
5783 double precision,
intent(out) :: vec_perp(
ndim)
5785 vec_perp=vec-sum(vec*bhat)*bhat
5786 end subroutine trace_project_to_perp_bhat
5788 subroutine trace_endpoint_b_bhat(x,face_id,igrid,threshold,B,bhat,status)
5789 double precision,
intent(in) :: x(
ndim),threshold
5790 integer,
intent(in) :: face_id,igrid
5791 double precision,
intent(out) :: b(
ndim),bhat(
ndim)
5792 integer,
intent(out) :: status
5794 double precision :: b3(3),bhat3(3)
5795 integer :: sample_igrid
5799 if (geo_coordinate==geo_spherical)
then
5800 call trace_spherical_endpoint_b_bhat(x,face_id,igrid,threshold,b,bhat, &
5804 call trace_locate_face_limit_grid(x,face_id,igrid,sample_igrid,status)
5806 call trace_sample_b_on_domain_face_limit(x,face_id,sample_igrid,threshold, &
5812 end subroutine trace_endpoint_b_bhat
5814 subroutine trace_locate_face_limit_grid(x,face_id,igrid_in,igrid_out, &
5816 double precision,
intent(in) :: x(
ndim)
5817 integer,
intent(in) :: face_id,igrid_in
5818 integer,
intent(out) :: igrid_out,status
5820 double precision :: xprobe(
ndim),xface
5822 integer :: normal_dim,side
5826 if (
ndim/=3 .or. .not.trace_cartesian_like_geometry() .or. &
5831 if (.not.trace_face_is_boundary(face_id))
return
5834 select case(face_id)
5865 select case(normal_dim)
5868 xprobe(normal_dim)=ps(igrid_in)%x(ixomin1,ixomin2,ixomin3,1)
5870 xprobe(normal_dim)=ps(igrid_in)%x(ixomax1,ixomin2,ixomin3,1)
5874 xprobe(normal_dim)=ps(igrid_in)%x(ixomin1,ixomin2,ixomin3,2)
5876 xprobe(normal_dim)=ps(igrid_in)%x(ixomin1,ixomax2,ixomin3,2)
5880 xprobe(normal_dim)=ps(igrid_in)%x(ixomin1,ixomin2,ixomin3,3)
5882 xprobe(normal_dim)=ps(igrid_in)%x(ixomin1,ixomin2,ixomax3,3)
5885 call trace_debug_locate_point(xprobe,igrid_out,status)
5887 end subroutine trace_locate_face_limit_grid
5889 subroutine trace_sample_b_on_domain_face_limit(xhit,face_id,igrid, &
5890 threshold,B,bhat,status)
5894 double precision,
intent(in) :: xhit(
ndim),threshold
5895 integer,
intent(in) :: face_id,igrid
5896 double precision,
intent(out) :: b(3),bhat(3)
5897 integer,
intent(out) :: status
5899 double precision :: bnear(3),binner(3)
5900 double precision :: xface,xnear,xinner
5901 double precision :: xnear_pt(
ndim),xinner_pt(
ndim)
5902 double precision :: bnorm
5904 integer :: normal_dim,side
5905 integer :: igrid_near,igrid_inner
5910 if (
ndim/=3 .or. .not.trace_cartesian_like_geometry() .or. igrid<0)
then
5914 if (.not.trace_face_is_boundary(face_id))
return
5917 select case(face_id)
5947 select case(normal_dim)
5950 xnear=ps(igrid)%x(ixomin1,ixomin2,ixomin3,1)
5951 xinner=ps(igrid)%x(ixomin1+1,ixomin2,ixomin3,1)
5953 xnear=ps(igrid)%x(ixomax1,ixomin2,ixomin3,1)
5954 xinner=ps(igrid)%x(ixomax1-1,ixomin2,ixomin3,1)
5958 xnear=ps(igrid)%x(ixomin1,ixomin2,ixomin3,2)
5959 xinner=ps(igrid)%x(ixomin1,ixomin2+1,ixomin3,2)
5961 xnear=ps(igrid)%x(ixomin1,ixomax2,ixomin3,2)
5962 xinner=ps(igrid)%x(ixomin1,ixomax2-1,ixomin3,2)
5966 xnear=ps(igrid)%x(ixomin1,ixomin2,ixomin3,3)
5967 xinner=ps(igrid)%x(ixomin1,ixomin2,ixomin3+1,3)
5969 xnear=ps(igrid)%x(ixomin1,ixomin2,ixomax3,3)
5970 xinner=ps(igrid)%x(ixomin1,ixomin2,ixomax3-1,3)
5975 xnear_pt(normal_dim)=xnear
5976 xinner_pt(normal_dim)=xinner
5978 call trace_debug_locate_point(xnear_pt,igrid_near,status)
5980 call sample_b_at_point(xnear_pt,igrid_near,threshold,bnear,status)
5982 call trace_debug_locate_point(xinner_pt,igrid_inner,status)
5984 call sample_b_at_point(xinner_pt,igrid_inner,threshold,binner,status)
5987 b=bnear+(bnear-binner)/(xnear-xinner)*(xface-xnear)
5988 bnorm=dsqrt(sum(b**2))
5989 if (bnorm<=zero .or. bnorm<threshold)
then
5996 end subroutine trace_sample_b_on_domain_face_limit
5998 subroutine trace_face_normal(face_id,normal,ok)
5999 integer,
intent(in) :: face_id
6000 double precision,
intent(out) :: normal(
ndim)
6001 logical,
intent(out) :: ok
6005 select case(face_id)
6035 end subroutine trace_face_normal
6037 subroutine trace_project_to_boundary_face(vec,bhat,face_id,vec_face)
6038 double precision,
intent(in) :: vec(
ndim),bhat(
ndim)
6039 integer,
intent(in) :: face_id
6040 double precision,
intent(out) :: vec_face(
ndim)
6042 double precision :: normal(
ndim),bn
6046 call trace_face_normal(face_id,normal,ok)
6049 if (abs(bn)<=smalldouble)
return
6050 vec_face=vec-sum(vec*normal)/bn*bhat
6051 end subroutine trace_project_to_boundary_face
6053 subroutine trace_make_perp_basis(bhat,u0,v0,status)
6054 double precision,
intent(in) :: bhat(3)
6055 double precision,
intent(out) :: u0(
ndim),v0(
ndim)
6056 integer,
intent(out) :: status
6058 double precision :: ref(3),u3(3),v3(3),b3(3),unorm,bnorm
6070 bnorm=dsqrt(sum(b3**2))
6071 if (bnorm<=zero)
then
6078 if (abs(b3(2))<abs(b3(iref))) iref=2
6079 if (abs(b3(3))<abs(b3(iref))) iref=3
6083 u3=ref-sum(ref*b3)*b3
6084 unorm=dsqrt(sum(u3**2))
6085 if (unorm<=smalldouble)
then
6091 v3(1)=b3(2)*u3(3)-b3(3)*u3(2)
6092 v3(2)=b3(3)*u3(1)-b3(1)*u3(3)
6093 v3(3)=b3(1)*u3(2)-b3(2)*u3(1)
6094 v3=v3/dsqrt(sum(v3**2))
6098 end subroutine trace_make_perp_basis
6100 double precision function trace_debug_nan()
6101 trace_debug_nan=ieee_value(0.d0,ieee_quiet_nan)
6102 end function trace_debug_nan
6104 subroutine trace_summary_seed(seed,dL,max_steps,result,b_min)
6105 double precision,
intent(in) :: seed(
ndim),dl
6106 integer,
intent(in) :: max_steps
6108 double precision,
intent(in),
optional :: b_min
6110 double precision :: field_min
6111 integer :: common_status,igrid
6113 call trace_summary_validate(dl,max_steps,common_status)
6115 call trace_summary_init_result(seed,result,common_status)
6119 field_min=smalldouble
6120 if (
present(b_min)) field_min=max(b_min,zero)
6122 call trace_summary_locate_seed(seed,result,igrid)
6124 call trace_summary_trace_seed(igrid,dl,max_steps,field_min,result)
6125 end subroutine trace_summary_seed
6127 subroutine trace_summary_twist_seed(seed,dL,max_steps,result,b_min)
6128 double precision,
intent(in) :: seed(
ndim),dl
6129 integer,
intent(in) :: max_steps
6131 double precision,
intent(in),
optional :: b_min
6133 double precision :: field_min
6134 integer :: common_status,igrid
6136 call trace_summary_validate(dl,max_steps,common_status)
6141 call trace_summary_init_twist_result(seed,result,common_status)
6145 field_min=smalldouble
6146 if (
present(b_min)) field_min=max(b_min,zero)
6148 call trace_summary_locate_seed(seed,result%line,igrid)
6149 result%forward_twist=zero
6150 result%backward_twist=zero
6151 result%total_twist=zero
6152 result%valid_twist=.false.
6153 result%status_twist=result%line%forward_status
6155 call trace_summary_trace_twist_seed(igrid,dl,max_steps,field_min,result)
6156 end subroutine trace_summary_twist_seed
6158 subroutine trace_summary_mapping_seed(seed,dL,max_steps,result,b_min, &
6160 double precision,
intent(in) :: seed(
ndim),dl
6161 integer,
intent(in) :: max_steps
6163 double precision,
intent(in),
optional :: b_min
6164 double precision,
intent(in),
optional :: source_normal(3)
6166 type(trace_summary_state) :: forward_state,backward_state
6168 double precision :: field_min,normal(3)
6169 integer :: common_status,igrid
6170 logical :: have_normal
6172 call trace_summary_validate(dl,max_steps,common_status)
6177 call trace_summary_init_mapping_result(seed,result,common_status)
6181 field_min=smalldouble
6182 if (
present(b_min)) field_min=max(b_min,zero)
6184 have_normal=
present(source_normal)
6185 if (have_normal) normal=source_normal
6187 call trace_summary_locate_seed(seed,located,igrid)
6188 call trace_summary_init_mapping_result(seed,result,located%forward_status)
6191 call trace_summary_init_state(seed,igrid,.true.,1,.false.,forward_state)
6192 call trace_summary_trace_state_to_end(forward_state,dl,max_steps,field_min)
6193 call trace_summary_init_state(seed,igrid,.false.,1,.false.,backward_state)
6194 call trace_summary_trace_state_to_end(backward_state,dl,max_steps,field_min)
6195 call trace_summary_fill_mapping(seed,igrid,forward_state,backward_state, &
6196 field_min,have_normal,normal,result)
6197 end subroutine trace_summary_mapping_seed
6199 subroutine trace_summary_multi(seeds,nseed,dL,max_steps,results,field_min)
6200 integer,
intent(in) :: nseed,max_steps
6201 double precision,
intent(in) :: seeds(nseed,
ndim),dl,field_min
6204 type(trace_summary_state),
allocatable :: states(:)
6205 double precision :: seed_local(
ndim)
6206 integer :: common_status,iseed,igrid,iforward,ibackward
6208 if (nseed<=0)
return
6210 call trace_summary_validate(dl,max_steps,common_status)
6213 seed_local=seeds(iseed,:)
6214 call trace_summary_init_result(seed_local,results(iseed),common_status)
6219 allocate(states(2*nseed))
6221 seed_local=seeds(iseed,:)
6222 call trace_summary_locate_seed(seed_local,results(iseed),igrid)
6225 call trace_summary_init_state(seed_local,igrid,.true.,iseed,.false., &
6227 call trace_summary_init_state(seed_local,igrid,.false.,iseed,.false., &
6230 states(iforward)%status=results(iseed)%forward_status
6231 states(iforward)%active=.false.
6232 states(ibackward)%status=results(iseed)%backward_status
6233 states(ibackward)%active=.false.
6237 call trace_summary_trace_states_grouped(states,2*nseed,dl,max_steps, &
6243 results(iseed)%forward_footpoint=states(iforward)%footpoint
6244 results(iseed)%forward_length=states(iforward)%length
6245 results(iseed)%forward_nstep=states(iforward)%nstep
6246 results(iseed)%forward_status=states(iforward)%status
6247 results(iseed)%backward_footpoint=states(ibackward)%footpoint
6248 results(iseed)%backward_length=states(ibackward)%length
6249 results(iseed)%backward_nstep=states(ibackward)%nstep
6250 results(iseed)%backward_status=states(ibackward)%status
6251 results(iseed)%total_length=results(iseed)%forward_length &
6252 +results(iseed)%backward_length
6255 end subroutine trace_summary_multi
6257 subroutine trace_summary_twist_multi(seeds,nseed,dL,max_steps,results, &
6259 integer,
intent(in) :: nseed,max_steps
6260 double precision,
intent(in) :: seeds(nseed,
ndim),dl,field_min
6263 type(trace_summary_state),
allocatable :: states(:)
6264 double precision :: seed_local(
ndim)
6265 integer :: common_status,iseed,igrid,iforward,ibackward
6267 if (nseed<=0)
return
6269 call trace_summary_validate(dl,max_steps,common_status)
6275 seed_local=seeds(iseed,:)
6276 call trace_summary_init_twist_result(seed_local,results(iseed), &
6282 allocate(states(2*nseed))
6284 seed_local=seeds(iseed,:)
6285 call trace_summary_locate_seed(seed_local,results(iseed)%line,igrid)
6286 results(iseed)%forward_twist=zero
6287 results(iseed)%backward_twist=zero
6288 results(iseed)%total_twist=zero
6289 results(iseed)%valid_twist=.false.
6290 results(iseed)%status_twist=results(iseed)%line%forward_status
6293 call trace_summary_init_state(seed_local,igrid,.true.,iseed,.true., &
6295 call trace_summary_init_state(seed_local,igrid,.false.,iseed,.true., &
6298 states(iforward)%status=results(iseed)%line%forward_status
6299 states(iforward)%active=.false.
6300 states(ibackward)%status=results(iseed)%line%backward_status
6301 states(ibackward)%active=.false.
6305 call trace_summary_trace_states_grouped(states,2*nseed,dl,max_steps, &
6311 results(iseed)%line%forward_footpoint=states(iforward)%footpoint
6312 results(iseed)%line%forward_length=states(iforward)%length
6313 results(iseed)%line%forward_nstep=states(iforward)%nstep
6314 results(iseed)%line%forward_status=states(iforward)%status
6315 results(iseed)%line%backward_footpoint=states(ibackward)%footpoint
6316 results(iseed)%line%backward_length=states(ibackward)%length
6317 results(iseed)%line%backward_nstep=states(ibackward)%nstep
6318 results(iseed)%line%backward_status=states(ibackward)%status
6319 results(iseed)%line%total_length=results(iseed)%line%forward_length &
6320 +results(iseed)%line%backward_length
6321 results(iseed)%forward_twist=states(iforward)%twist
6322 results(iseed)%backward_twist=states(ibackward)%twist
6323 results(iseed)%total_twist=results(iseed)%forward_twist &
6324 +results(iseed)%backward_twist
6325 results(iseed)%status_twist=trace_summary_twist_status_from_states( &
6326 states(iforward),states(ibackward))
6327 results(iseed)%valid_twist=results(iseed)%status_twist &
6331 end subroutine trace_summary_twist_multi
6333 subroutine trace_summary_mapping_multi(seeds,nseed,dL,max_steps,results, &
6334 field_min,have_source_normal,source_normal)
6335 integer,
intent(in) :: nseed,max_steps
6336 double precision,
intent(in) :: seeds(nseed,
ndim),dl,field_min
6337 logical,
intent(in) :: have_source_normal
6338 double precision,
intent(in) :: source_normal(3)
6341 type(trace_summary_state),
allocatable :: states(:)
6342 integer,
allocatable :: source_igrids(:)
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)
6355 seed_local=seeds(iseed,:)
6356 call trace_summary_init_mapping_result(seed_local,results(iseed), &
6362 allocate(states(2*nseed))
6363 allocate(source_igrids(nseed))
6366 seed_local=seeds(iseed,:)
6367 call trace_summary_locate_seed(seed_local,located,igrid)
6368 source_igrids(iseed)=igrid
6369 call trace_summary_init_mapping_result(seed_local,results(iseed), &
6370 located%forward_status)
6373 call trace_summary_init_state(seed_local,igrid,.true.,iseed,.false., &
6375 call trace_summary_init_state(seed_local,igrid,.false.,iseed,.false., &
6378 states(iforward)%status=located%forward_status
6379 states(iforward)%active=.false.
6380 states(ibackward)%status=located%backward_status
6381 states(ibackward)%active=.false.
6385 call trace_summary_trace_states_grouped(states,2*nseed,dl,max_steps, &
6391 if (source_igrids(iseed)>=0)
then
6392 call trace_summary_fill_mapping(results(iseed)%seed, &
6393 source_igrids(iseed),states(iforward),states(ibackward), &
6394 field_min,have_source_normal,source_normal,results(iseed))
6397 deallocate(source_igrids,states)
6398 end subroutine trace_summary_mapping_multi
6400 subroutine trace_summary_topology_multi(seeds,nseed,dL,max_steps,results, &
6401 field_min,need_twist,need_mapping,have_source_normal,source_normal)
6402 integer,
intent(in) :: nseed,max_steps
6403 double precision,
intent(in) :: seeds(nseed,
ndim),dl,field_min
6404 logical,
intent(in) :: need_twist,need_mapping,have_source_normal
6405 double precision,
intent(in) :: source_normal(3)
6408 type(trace_summary_state),
allocatable :: states(:)
6409 type(trace_summary_state),
allocatable :: map_states(:)
6410 integer,
allocatable :: source_igrids(:)
6413 double precision :: seed_local(
ndim)
6414 integer :: common_status,iseed,igrid,iforward,ibackward,idim
6416 if (nseed<=0)
return
6418 call trace_summary_validate(dl,max_steps,common_status)
6420 (need_twist .or. need_mapping) .and.
ndim/=3)
then
6426 seed_local(idim)=seeds(iseed,idim)
6428 call trace_summary_init_topology_result(seed_local,results(iseed), &
6429 common_status,need_twist,need_mapping)
6434 allocate(states(2*nseed))
6437 if (need_mapping .and. need_twist)
allocate(map_states(2*nseed))
6438 allocate(source_igrids(nseed))
6442 seed_local(idim)=seeds(iseed,idim)
6444 call trace_summary_locate_seed(seed_local,located,igrid)
6445 source_igrids(iseed)=igrid
6446 call trace_summary_init_topology_result(seed_local,results(iseed), &
6447 located%forward_status,need_twist,need_mapping)
6450 call trace_summary_init_state(seed_local,igrid,.true.,iseed, &
6451 need_twist,states(iforward))
6452 call trace_summary_init_state(seed_local,igrid,.false.,iseed, &
6453 need_twist,states(ibackward))
6454 if (
allocated(map_states))
then
6455 call trace_summary_init_state(seed_local,igrid,.true.,iseed, &
6456 .false.,map_states(iforward))
6457 call trace_summary_init_state(seed_local,igrid,.false.,iseed, &
6458 .false.,map_states(ibackward))
6461 states(iforward)%status=located%forward_status
6462 states(iforward)%active=.false.
6463 states(ibackward)%status=located%backward_status
6464 states(ibackward)%active=.false.
6465 if (
allocated(map_states))
then
6466 map_states(iforward)%status=located%forward_status
6467 map_states(iforward)%active=.false.
6468 map_states(ibackward)%status=located%backward_status
6469 map_states(ibackward)%active=.false.
6474 call trace_summary_trace_states_grouped(states,2*nseed,dl,max_steps, &
6476 if (
allocated(map_states))
then
6477 call trace_summary_trace_states_grouped(map_states,2*nseed,dl, &
6478 max_steps,field_min)
6484 results(iseed)%forward_endpoint=states(iforward)%footpoint
6485 results(iseed)%backward_endpoint=states(ibackward)%footpoint
6486 results(iseed)%length_forward=states(iforward)%length
6487 results(iseed)%length_backward=states(ibackward)%length
6488 results(iseed)%length_total=results(iseed)%length_forward &
6489 +results(iseed)%length_backward
6490 results(iseed)%forward_nstep=states(iforward)%nstep
6491 results(iseed)%backward_nstep=states(ibackward)%nstep
6492 results(iseed)%forward_face=states(iforward)%face
6493 results(iseed)%backward_face=states(ibackward)%face
6494 results(iseed)%forward_status=states(iforward)%status
6495 results(iseed)%backward_status=states(ibackward)%status
6496 if (need_twist)
then
6497 results(iseed)%twist_forward=states(iforward)%twist
6498 results(iseed)%twist_backward=states(ibackward)%twist
6499 results(iseed)%twist_total=results(iseed)%twist_forward &
6500 +results(iseed)%twist_backward
6501 results(iseed)%status_twist=trace_summary_twist_status_from_states( &
6502 states(iforward),states(ibackward))
6503 results(iseed)%valid_twist=results(iseed)%status_twist &
6510 results(iseed)%valid=.true.
6512 results(iseed)%valid=.false.
6514 results(iseed)%status=states(iforward)%status
6516 results(iseed)%status=states(ibackward)%status
6520 if (need_mapping .and. source_igrids(iseed)>=0)
then
6521 if (
allocated(map_states))
then
6522 call trace_summary_fill_mapping(results(iseed)%seed, &
6523 source_igrids(iseed),map_states(iforward), &
6524 map_states(ibackward),field_min,have_source_normal, &
6525 source_normal,mapping)
6527 call trace_summary_fill_mapping(results(iseed)%seed, &
6528 source_igrids(iseed),states(iforward),states(ibackward), &
6529 field_min,have_source_normal,source_normal,mapping)
6531 results(iseed)%source_B=mapping%source_B
6532 results(iseed)%forward_B=mapping%forward_B
6533 results(iseed)%backward_B=mapping%backward_B
6534 results(iseed)%source_Bn=mapping%source_Bn
6535 results(iseed)%forward_Bn=mapping%forward_Bn
6536 results(iseed)%backward_Bn=mapping%backward_Bn
6537 results(iseed)%map_forward_endpoint=mapping%forward_footpoint
6538 results(iseed)%map_backward_endpoint=mapping%backward_footpoint
6539 results(iseed)%map_forward_length=mapping%forward_length
6540 results(iseed)%map_backward_length=mapping%backward_length
6541 results(iseed)%map_forward_face=mapping%forward_face
6542 results(iseed)%map_backward_face=mapping%backward_face
6543 results(iseed)%map_forward_status=mapping%forward_status
6544 results(iseed)%map_backward_status=mapping%backward_status
6545 results(iseed)%forward_status=mapping%forward_status
6546 results(iseed)%backward_status=mapping%backward_status
6547 results(iseed)%valid=mapping%valid
6548 if (mapping%valid)
then
6551 results(iseed)%status=mapping%forward_status
6553 results(iseed)%status=mapping%backward_status
6557 if (
allocated(map_states))
deallocate(map_states)
6558 deallocate(source_igrids,states)
6559 end subroutine trace_summary_topology_multi
6561 subroutine trace_summary_validate(dL,max_steps,status)
6562 double precision,
intent(in) :: dl
6563 integer,
intent(in) :: max_steps
6564 integer,
intent(out) :: status
6569 else if (dl<=zero .or. max_steps<0)
then
6571 else if (.not.trace_is_supported_summary_geometry())
then
6574 end subroutine trace_summary_validate
6576 logical function trace_is_supported_summary_geometry()
result(is_supported)
6577 is_supported=.false.
6580 select case (geo_coordinate)
6581 case (geo_cartesian,geo_cartesian_stretched)
6583 case (geo_spherical)
6589 end function trace_is_supported_summary_geometry
6591 subroutine trace_summary_init_result(seed,result,status)
6592 double precision,
intent(in) :: seed(
ndim)
6594 integer,
intent(in) :: status
6597 result%forward_footpoint=seed
6598 result%backward_footpoint=seed
6599 result%forward_length=zero
6600 result%backward_length=zero
6601 result%total_length=zero
6602 result%forward_nstep=0
6603 result%backward_nstep=0
6604 result%forward_status=status
6605 result%backward_status=status
6606 end subroutine trace_summary_init_result
6608 subroutine trace_summary_init_twist_result(seed,result,status)
6609 double precision,
intent(in) :: seed(
ndim)
6611 integer,
intent(in) :: status
6613 call trace_summary_init_result(seed,result%line,status)
6614 result%forward_twist=zero
6615 result%backward_twist=zero
6616 result%total_twist=zero
6617 result%valid_twist=.false.
6618 result%status_twist=status
6619 end subroutine trace_summary_init_twist_result
6621 subroutine trace_summary_init_mapping_result(seed,result,status)
6622 double precision,
intent(in) :: seed(
ndim)
6624 integer,
intent(in) :: status
6627 result%source_B=zero
6628 result%forward_footpoint=seed
6629 result%backward_footpoint=seed
6630 result%forward_B=zero
6631 result%backward_B=zero
6632 result%forward_length=zero
6633 result%backward_length=zero
6634 result%source_Bn=zero
6635 result%forward_Bn=zero
6636 result%backward_Bn=zero
6639 result%forward_status=status
6640 result%backward_status=status
6641 result%valid=.false.
6642 end subroutine trace_summary_init_mapping_result
6644 subroutine trace_summary_init_topology_result(seed,result,status, &
6645 need_twist,need_mapping)
6646 double precision,
intent(in) :: seed(
ndim)
6648 integer,
intent(in) :: status
6649 logical,
intent(in) :: need_twist,need_mapping
6652 result%length_forward=zero
6653 result%length_backward=zero
6654 result%length_total=zero
6655 result%twist_forward=zero
6656 result%twist_backward=zero
6657 result%twist_total=zero
6658 result%forward_endpoint=seed
6659 result%backward_endpoint=seed
6660 result%forward_nstep=0
6661 result%backward_nstep=0
6664 result%forward_status=status
6665 result%backward_status=status
6666 result%map_forward_endpoint=seed
6667 result%map_backward_endpoint=seed
6668 result%map_forward_length=zero
6669 result%map_backward_length=zero
6672 result%map_forward_status=status
6673 result%map_backward_status=status
6674 result%source_B=zero
6675 result%forward_B=zero
6676 result%backward_B=zero
6677 result%source_Bn=zero
6678 result%forward_Bn=zero
6679 result%backward_Bn=zero
6680 result%has_twist=need_twist
6681 result%has_mapping=need_mapping
6682 result%valid_twist=.false.
6683 result%valid=.false.
6684 result%status_twist=status
6685 result%status=status
6686 end subroutine trace_summary_init_topology_result
6688 subroutine trace_summary_locate_seed(seed,result,igrid)
6691 double precision,
intent(in) :: seed(
ndim)
6693 integer,
intent(out) :: igrid
6695 double precision :: x3d(3),domain_min(
ndim),domain_max(
ndim),tol
6696 integer :: indomain,ipe,j
6701 ^
d&domain_min(^
d)=xprobmin^
d;
6702 ^
d&domain_max(^
d)=xprobmax^
d;
6703 tol=100.d0*epsilon(one)*max(one,maxval(abs(domain_max-domain_min)))
6705 if (seed(j)>=domain_min(j)-tol .and. &
6706 seed(j)<=domain_max(j)+tol) indomain=indomain+1
6708 if (indomain/=
ndim)
then
6716 x3d(j)=min(max(seed(j),domain_min(j)+tol),domain_max(j)-tol)
6719 if (igrid<0 .or. ipe/=
mype)
then
6724 end subroutine trace_summary_locate_seed
6726 subroutine trace_summary_trace_seed(igrid,dL,max_steps,field_min,result)
6727 integer,
intent(in) :: igrid,max_steps
6728 double precision,
intent(in) :: dl,field_min
6731 type(trace_summary_state) :: forward_state,backward_state
6733 call trace_summary_init_state(result%seed,igrid,.true.,1,.false.,forward_state)
6734 call trace_summary_trace_state_to_end(forward_state,dl,max_steps,field_min)
6735 call trace_summary_init_state(result%seed,igrid,.false.,1,.false.,backward_state)
6736 call trace_summary_trace_state_to_end(backward_state,dl,max_steps,field_min)
6738 result%forward_footpoint=forward_state%footpoint
6739 result%forward_length=forward_state%length
6740 result%forward_nstep=forward_state%nstep
6741 result%forward_status=forward_state%status
6742 result%backward_footpoint=backward_state%footpoint
6743 result%backward_length=backward_state%length
6744 result%backward_nstep=backward_state%nstep
6745 result%backward_status=backward_state%status
6746 result%total_length=result%forward_length+result%backward_length
6747 end subroutine trace_summary_trace_seed
6749 subroutine trace_summary_trace_twist_seed(igrid,dL,max_steps,field_min, &
6751 integer,
intent(in) :: igrid,max_steps
6752 double precision,
intent(in) :: dl,field_min
6755 type(trace_summary_state) :: forward_state,backward_state
6757 call trace_summary_init_state(result%line%seed,igrid,.true.,1,.true., &
6759 call trace_summary_trace_state_to_end(forward_state,dl,max_steps,field_min)
6760 call trace_summary_init_state(result%line%seed,igrid,.false.,1,.true., &
6762 call trace_summary_trace_state_to_end(backward_state,dl,max_steps,field_min)
6764 result%line%forward_footpoint=forward_state%footpoint
6765 result%line%forward_length=forward_state%length
6766 result%line%forward_nstep=forward_state%nstep
6767 result%line%forward_status=forward_state%status
6768 result%line%backward_footpoint=backward_state%footpoint
6769 result%line%backward_length=backward_state%length
6770 result%line%backward_nstep=backward_state%nstep
6771 result%line%backward_status=backward_state%status
6772 result%line%total_length=result%line%forward_length &
6773 +result%line%backward_length
6774 result%forward_twist=forward_state%twist
6775 result%backward_twist=backward_state%twist
6776 result%total_twist=result%forward_twist+result%backward_twist
6777 result%status_twist=trace_summary_twist_status_from_states( &
6778 forward_state,backward_state)
6780 end subroutine trace_summary_trace_twist_seed
6782 subroutine trace_summary_init_state(xseed,igrid,forward,seed_id, &
6783 accumulate_twist,state)
6784 double precision,
intent(in) :: xseed(
ndim)
6785 integer,
intent(in) :: igrid,seed_id
6786 logical,
intent(in) :: forward,accumulate_twist
6787 type(trace_summary_state),
intent(out) :: state
6790 state%footpoint=xseed
6797 state%seed_id=seed_id
6799 state%forward=forward
6801 state%accumulate_twist=accumulate_twist
6803 state%sph_cache%valid=.false.
6804 if (trace_rk45_position_integrator())
then
6805 call trace_rk45_stats_note_direction()
6807 if (trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical) &
6808 call trace_spherical_profile_add_count(trace_profile_directions,1_8)
6809 end subroutine trace_summary_init_state
6811 subroutine trace_summary_trace_state_to_end(state,ds,max_nstep,threshold)
6812 type(trace_summary_state),
intent(inout) :: state
6813 double precision,
intent(in) :: ds,threshold
6814 integer,
intent(in) :: max_nstep
6816 do while(state%active .and. state%nstep<max_nstep)
6817 call trace_summary_advance_state(state,ds,threshold)
6820 if (state%active)
then
6822 state%active=.false.
6824 state%footpoint=state%x
6825 if (trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical) &
6826 call trace_spherical_profile_note_trace_steps(state%nstep)
6827 end subroutine trace_summary_trace_state_to_end
6829 subroutine trace_summary_trace_states_grouped(states,nstate,ds,max_nstep,threshold)
6830 integer,
intent(in) :: nstate,max_nstep
6831 type(trace_summary_state),
intent(inout) :: states(nstate)
6832 double precision,
intent(in) :: ds,threshold
6834 logical,
allocatable :: processed(:)
6835 integer :: istate,jstate,target_grid
6836 logical :: any_active
6838 allocate(processed(nstate))
6842 if (states(istate)%active)
then
6847 if (.not.any_active)
exit
6851 if (.not.states(istate)%active .or. processed(istate)) cycle
6852 target_grid=states(istate)%igrid
6854 if (.not.states(jstate)%active .or. processed(jstate)) cycle
6855 if (states(jstate)%igrid/=target_grid) cycle
6856 call trace_summary_advance_state_in_grid(states(jstate),target_grid, &
6857 ds,max_nstep,threshold)
6858 processed(jstate)=.true.
6862 deallocate(processed)
6863 end subroutine trace_summary_trace_states_grouped
6865 subroutine trace_summary_advance_state_in_grid(state,igrid,ds,max_nstep,threshold)
6866 type(trace_summary_state),
intent(inout) :: state
6867 integer,
intent(in) :: igrid,max_nstep
6868 double precision,
intent(in) :: ds,threshold
6870 do while(state%active .and. state%igrid==igrid .and. &
6871 state%nstep<max_nstep)
6872 call trace_summary_advance_state(state,ds,threshold)
6875 if (state%active .and. state%nstep>=max_nstep)
then
6877 state%active=.false.
6878 state%footpoint=state%x
6879 if (trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical) &
6880 call trace_spherical_profile_note_trace_steps(state%nstep)
6882 end subroutine trace_summary_advance_state_in_grid
6884 subroutine trace_summary_advance_state(state,ds,threshold)
6885 type(trace_summary_state),
intent(inout) :: state
6886 double precision,
intent(in) :: ds,threshold
6888 double precision :: xnext(
ndim),xhit(
ndim),ds_actual,segment_length
6889 double precision :: alpha_hit
6890 double precision :: xbmin^
d,xbmax^
d
6891 double precision :: domain_min(
ndim),domain_max(
ndim)
6892 double precision :: near_tol,best_dist,face_dist
6893 integer :: igrid_next,ipe_next,inblock,step_status,face_id
6894 integer :: idim,best_dim,best_side
6895 integer :: point_domain
6896 double precision :: rk45_twist_increment
6897 integer :: rk45_twist_status
6898 logical :: newpe,stop_trace,hit_ok
6899 logical :: rk45_step,rk45_twist_integrated
6901 if (.not.state%active)
return
6904 rk45_twist_increment=zero
6906 rk45_twist_integrated=.false.
6907 if (trace_integrator_mode==trace_integrator_rk45_cartesian .and. &
6908 trace_cartesian_like_geometry())
then
6910 call trace_summary_rk45_cartesian_step(state%x,state%igrid,ds, &
6911 state%forward,threshold,state%rk45_h,xnext,ds_actual, &
6912 step_status,state%accumulate_twist,rk45_twist_increment, &
6913 rk45_twist_status,rk45_twist_integrated)
6914 else if (trace_integrator_mode==trace_integrator_rk45_spherical .and. &
6915 geo_coordinate==geo_spherical)
then
6917 call trace_summary_rk45_spherical_step(state%x,state%igrid,ds, &
6918 state%forward,threshold,state%rk45_h,state%sph_cache,xnext, &
6919 ds_actual,step_status,state%accumulate_twist, &
6920 rk45_twist_increment,rk45_twist_status,rk45_twist_integrated)
6922 call trace_summary_rk2_step(state%x,state%igrid,ds,state%forward, &
6923 threshold,xnext,ds_actual,step_status,sph_cache=state%sph_cache)
6927 trace_rk45_position_integrator())
then
6928 call trace_boundary_face_at_point(state%x,state%face,hit_ok)
6929 if (.not.hit_ok)
then
6930 ^
d&domain_min(^
d)=xprobmin^
d;
6931 ^
d&domain_max(^
d)=xprobmax^
d;
6932 near_tol=max(100.d0*epsilon(one)* &
6933 max(one,maxval(abs(domain_max-domain_min))), &
6934 1.
d-5*max(one,abs(ds)))
6939 face_dist=abs(state%x(idim)-domain_min(idim))
6940 if (face_dist<best_dist)
then
6945 face_dist=abs(state%x(idim)-domain_max(idim))
6946 if (face_dist<best_dist)
then
6952 if (best_dim>0 .and. best_dist<=near_tol)
then
6953 if (best_side<0)
then
6954 state%x(best_dim)=domain_min(best_dim)
6956 state%x(best_dim)=domain_max(best_dim)
6958 state%footpoint=state%x
6959 state%face=trace_face_from_dim_side(best_dim,best_side)
6965 state%active=.false.
6969 state%status=step_status
6970 state%active=.false.
6975 {
if (xnext(^db)>=xprobmin^db .and. xnext(^db)<xprobmax^db) point_domain=point_domain+1\}
6976 if (point_domain/=
ndim)
then
6977 call trace_intersect_domain(state%x,xnext,xhit,hit_ok,face_id, &
6980 if (trace_rk45_position_integrator() .and. &
6982 segment_length=abs(ds_actual)
6984 segment_length=trace_segment_length(state%x,xhit,ds_actual, &
6987 if (state%accumulate_twist .and. &
6989 if (rk45_step .and. rk45_twist_integrated)
then
6990 state%twist=state%twist+rk45_twist_increment
6992 state%twist_status=rk45_twist_status
6994 call trace_summary_accumulate_twist(state,xhit,segment_length, &
6995 threshold,step_status)
6997 state%twist_status=step_status
7001 state%length=state%length+segment_length
7003 state%nstep=state%nstep+1
7004 if (trace_spherical_profile_enabled .and. &
7005 geo_coordinate==geo_spherical)
then
7006 call trace_spherical_profile_add_count(trace_profile_steps,1_8)
7009 state%footpoint=state%x
7012 if (trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical) &
7013 call trace_spherical_profile_add_count(trace_profile_boundary_events, &
7016 state%active=.false.
7017 if (trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical) &
7018 call trace_spherical_profile_note_trace_steps(state%nstep)
7022 if (state%accumulate_twist .and. &
7024 if (rk45_step .and. rk45_twist_integrated)
then
7025 state%twist=state%twist+rk45_twist_increment
7027 state%twist_status=rk45_twist_status
7029 call trace_summary_accumulate_twist(state,xnext,ds_actual,threshold, &
7032 state%twist_status=step_status
7037 state%length=state%length+abs(ds_actual)
7039 state%length=state%length+trace_segment_length(state%x,xnext, &
7042 state%nstep=state%nstep+1
7043 if (trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical) &
7044 call trace_spherical_profile_add_count(trace_profile_steps,1_8)
7046 state%footpoint=state%x
7051 {
if (state%x(^db)>=xbmin^db .and. state%x(^db)<xbmax^db) inblock=inblock+1\}
7052 if (inblock==
ndim)
return
7054 igrid_next=state%igrid
7058 call find_next_grid(state%igrid,igrid_next,ipe_next,state%x,newpe,stop_trace)
7059 if (stop_trace)
then
7061 state%active=.false.
7062 if (trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical) &
7063 call trace_spherical_profile_add_count(trace_profile_boundary_events, &
7065 if (trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical) &
7066 call trace_spherical_profile_note_trace_steps(state%nstep)
7069 if (newpe .or. ipe_next/=
mype)
then
7070 if (trace_rk45_position_integrator())
then
7071 call trace_boundary_face_at_point(state%x,state%face,hit_ok)
7072 if (.not.hit_ok)
then
7073 ^
d&domain_min(^
d)=xprobmin^
d;
7074 ^
d&domain_max(^
d)=xprobmax^
d;
7075 near_tol=max(100.d0*epsilon(one)* &
7076 max(one,maxval(abs(domain_max-domain_min))), &
7077 1.
d-6*max(one,abs(ds_actual)))
7082 face_dist=abs(state%x(idim)-domain_min(idim))
7083 if (face_dist<best_dist)
then
7088 face_dist=abs(state%x(idim)-domain_max(idim))
7089 if (face_dist<best_dist)
then
7095 if (best_dim>0 .and. best_dist<=near_tol)
then
7096 if (best_side<0)
then
7097 state%x(best_dim)=domain_min(best_dim)
7099 state%x(best_dim)=domain_max(best_dim)
7101 state%footpoint=state%x
7102 state%face=trace_face_from_dim_side(best_dim,best_side)
7108 state%active=.false.
7113 state%active=.false.
7114 if (trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical) &
7115 call trace_spherical_profile_note_trace_steps(state%nstep)
7118 state%igrid=igrid_next
7119 end subroutine trace_summary_advance_state
7121 subroutine trace_summary_accumulate_twist(state,xend,segment_length, &
7123 type(trace_summary_state),
intent(inout) :: state
7124 double precision,
intent(in) :: xend(
ndim),segment_length,threshold
7125 integer,
intent(out) :: status
7127 double precision :: xmid(
ndim),b(3),curlb(3),b2,twist_density
7130 if (segment_length<=zero)
return
7132 xmid=half*(state%x+xend)
7133 call sample_b_curlb_at_point(xmid,state%igrid,threshold,b,curlb,status, &
7134 sph_cache=state%sph_cache)
7138 twist_density=sum(curlb*b)/(4.d0*dpi*b2)
7140 state%twist=state%twist+twist_density*segment_length
7141 end subroutine trace_summary_accumulate_twist
7143 subroutine trace_twist_density_at_point(x,igrid,threshold,twist_density, &
7145 double precision,
intent(in) :: x(
ndim),threshold
7146 integer,
intent(in) :: igrid
7147 double precision,
intent(out) :: twist_density
7148 integer,
intent(out) :: status
7149 type(trace_sph_interp_ctx),
intent(inout),
optional :: sph_cache
7151 double precision :: b(3),curlb(3),b2
7154 call sample_b_curlb_at_point(x,igrid,threshold,b,curlb,status, &
7155 sph_cache=sph_cache)
7163 twist_density=sum(curlb*b)/(4.d0*dpi*b2)
7164 end subroutine trace_twist_density_at_point
7166 subroutine trace_tangent_accumulate_twist(state,xend,segment_length, &
7168 type(trace_tangent_state),
intent(inout) :: state
7169 double precision,
intent(in) :: xend(
ndim),segment_length,threshold
7171 double precision :: xmid(
ndim),twist_density
7173 if (.not.state%accumulate_twist)
return
7175 if (segment_length<=zero)
return
7176 xmid=half*(state%x+xend)
7177 call trace_twist_density_at_point(xmid,state%igrid,threshold, &
7178 twist_density,state%twist_status,sph_cache=state%sph_cache)
7180 state%twist=state%twist+twist_density*segment_length
7181 end subroutine trace_tangent_accumulate_twist
7183 integer function trace_summary_twist_status_from_states(forward_state, &
7184 backward_state)
result(status_twist)
7185 type(trace_summary_state),
intent(in) :: forward_state,backward_state
7189 status_twist=forward_state%status
7191 status_twist=backward_state%status
7193 status_twist=forward_state%twist_status
7195 status_twist=backward_state%twist_status
7197 end function trace_summary_twist_status_from_states
7199 subroutine trace_tangent_fill_twist_result(seed,forward_state, &
7200 backward_state,result)
7201 double precision,
intent(in) :: seed(
ndim)
7202 type(trace_tangent_state),
intent(in) :: forward_state,backward_state
7205 result%line%seed=seed
7206 result%line%forward_footpoint=forward_state%endpoint
7207 result%line%backward_footpoint=backward_state%endpoint
7208 result%line%forward_length=forward_state%length
7209 result%line%backward_length=backward_state%length
7210 result%line%total_length=forward_state%length+backward_state%length
7211 result%line%forward_nstep=forward_state%nstep
7212 result%line%backward_nstep=backward_state%nstep
7213 result%line%forward_status=forward_state%status
7214 result%line%backward_status=backward_state%status
7215 result%forward_twist=forward_state%twist
7216 result%backward_twist=backward_state%twist
7217 result%total_twist=forward_state%twist+backward_state%twist
7220 result%status_twist=forward_state%status
7222 result%status_twist=backward_state%status
7224 result%status_twist=forward_state%twist_status
7226 result%status_twist=backward_state%twist_status
7229 end subroutine trace_tangent_fill_twist_result
7231 subroutine trace_total_b_at_cell(igrid,ix1,ix2,ix3,B,status)
7232 integer,
intent(in) :: igrid,ix1,ix2,ix3
7233 double precision,
intent(out) :: b(3)
7234 integer,
intent(out) :: status
7238 if (
ndim/=3 .or. igrid<0)
return
7241 if (.not.
b0field .and. .not.
allocated(iw_mag))
return
7242 if (
allocated(iw_mag))
then
7243 b(1:3)=ps(igrid)%w(ix1,ix2,ix3,iw_mag(1:3))
7246 b(1:3)=b(1:3)+ps(igrid)%B0(ix1,ix2,ix3,1:3,0)
7250 end subroutine trace_total_b_at_cell
7252 subroutine trace_bhat_at_cell(igrid,ix1,ix2,ix3,threshold,bhat,status)
7253 integer,
intent(in) :: igrid,ix1,ix2,ix3
7254 double precision,
intent(in) :: threshold
7255 double precision,
intent(out) :: bhat(3)
7256 integer,
intent(out) :: status
7258 double precision :: b(3),bnorm
7261 call trace_total_b_at_cell(igrid,ix1,ix2,ix3,b,status)
7264 bnorm=dsqrt(sum(b**2))
7265 if (bnorm<=zero .or. bnorm<threshold)
then
7270 end subroutine trace_bhat_at_cell
7272 subroutine sample_bhat_gradbhat_at_point(x,igrid,threshold,bhat, &
7275 double precision,
intent(in) :: x(
ndim),threshold
7276 integer,
intent(in) :: igrid
7277 double precision,
intent(out) :: bhat(3),grad_bhat(3,3)
7278 integer,
intent(out) :: status
7280 call sample_bhat_gradbhat_interpderiv_at_point(x,igrid,threshold,bhat, &
7282 end subroutine sample_bhat_gradbhat_at_point
7284 subroutine sample_bhat_gradbhat_cellfd_at_point(x,igrid,threshold,bhat, &
7287 double precision,
intent(in) :: x(
ndim),threshold
7288 integer,
intent(in) :: igrid
7289 double precision,
intent(out) :: bhat(3),grad_bhat(3,3)
7290 integer,
intent(out) :: status
7292 double precision :: dxb^
d,dxc^
d,xd^
d
7293 double precision :: bhat_cell(0:1^
d&,3)
7294 double precision :: grad_cell(0:1^
d&,3,3)
7295 double precision :: factor(0:1^
d&)
7296 double precision :: bhat_center(3),bhat_plus(3),bhat_minus(3)
7297 integer :: ixi^
l,ixbl^
d,ix^
d,j,k
7302 if (
ndim/=3 .or. igrid<0)
return
7307 ^
d&ixbl^
d=floor((x(^
d)-ps(igrid)%x(iximin^dd,^
d))/dxb^
d)+iximin^
d;
7308 ^
d&xd^
d=(x(^
d)-ps(igrid)%x(ixbl^dd,^
d))/dxb^
d;
7310 if (ixbl1-1<iximin1 .or. ixbl1+2>iximax1 .or. &
7311 ixbl2-1<iximin2 .or. ixbl2+2>iximax2 .or. &
7312 ixbl3-1<iximin3 .or. ixbl3+2>iximax3)
return
7317 call trace_bhat_at_cell(igrid,ixbl1+ix1,ixbl2+ix2, &
7318 ixbl3+ix3,threshold,bhat_center,status)
7320 bhat_cell(ix^
d,1:3)=bhat_center
7322 call trace_bhat_at_cell(igrid,ixbl1+ix1+1,ixbl2+ix2, &
7323 ixbl3+ix3,threshold,bhat_plus,status)
7325 call trace_bhat_at_cell(igrid,ixbl1+ix1-1,ixbl2+ix2, &
7326 ixbl3+ix3,threshold,bhat_minus,status)
7328 grad_cell(ix^
d,1:3,1)=(bhat_plus-bhat_minus)/(2.d0*dxb1)
7330 call trace_bhat_at_cell(igrid,ixbl1+ix1,ixbl2+ix2+1, &
7331 ixbl3+ix3,threshold,bhat_plus,status)
7333 call trace_bhat_at_cell(igrid,ixbl1+ix1,ixbl2+ix2-1, &
7334 ixbl3+ix3,threshold,bhat_minus,status)
7336 grad_cell(ix^
d,1:3,2)=(bhat_plus-bhat_minus)/(2.d0*dxb2)
7338 call trace_bhat_at_cell(igrid,ixbl1+ix1,ixbl2+ix2, &
7339 ixbl3+ix3+1,threshold,bhat_plus,status)
7341 call trace_bhat_at_cell(igrid,ixbl1+ix1,ixbl2+ix2, &
7342 ixbl3+ix3-1,threshold,bhat_minus,status)
7344 grad_cell(ix^
d,1:3,3)=(bhat_plus-bhat_minus)/(2.d0*dxb3)
7348 factor(ix^
d)={abs(1-ix^
d-xd^
d)*}
7352 bhat(j)=bhat(j)+bhat_cell(ix^
d,j)*factor(ix^
d)
7354 grad_bhat(j,k)=grad_bhat(j,k)+grad_cell(ix^
d,j,k)*factor(ix^
d)
7361 end subroutine sample_bhat_gradbhat_cellfd_at_point
7363 subroutine sample_bhat_gradbhat_xeps_at_point(x,eps,threshold,bhat, &
7366 double precision,
intent(in) :: x(
ndim),eps,threshold
7367 double precision,
intent(out) :: bhat(3),grad_bhat(3,3)
7368 integer,
intent(out) :: status
7370 double precision :: xp(
ndim),xm(
ndim)
7371 double precision :: b(3),bp(3),bm(3),bhat_p(3),bhat_m(3)
7372 double precision :: bnorm,bpnorm,bmnorm
7373 integer :: igrid,idir,point_domain
7387 call trace_debug_locate_point(x,igrid,status)
7389 call sample_b_at_point(x,igrid,threshold,b,status)
7391 bnorm=dsqrt(sum(b**2))
7392 if (bnorm<=zero .or. bnorm<threshold)
then
7401 xp(idir)=xp(idir)+eps
7402 xm(idir)=xm(idir)-eps
7405 {
if (xp(^db)>=xprobmin^db .and. xp(^db)<xprobmax^db) point_domain=point_domain+1\}
7406 if (point_domain/=
ndim)
then
7410 call trace_debug_locate_point(xp,igrid,status)
7412 call sample_b_at_point(xp,igrid,threshold,bp,status)
7414 bpnorm=dsqrt(sum(bp**2))
7415 if (bpnorm<=zero .or. bpnorm<threshold)
then
7422 {
if (xm(^db)>=xprobmin^db .and. xm(^db)<xprobmax^db) point_domain=point_domain+1\}
7423 if (point_domain/=
ndim)
then
7427 call trace_debug_locate_point(xm,igrid,status)
7429 call sample_b_at_point(xm,igrid,threshold,bm,status)
7431 bmnorm=dsqrt(sum(bm**2))
7432 if (bmnorm<=zero .or. bmnorm<threshold)
then
7438 grad_bhat(1:3,idir)=(bhat_p-bhat_m)/(2.d0*eps)
7442 end subroutine sample_bhat_gradbhat_xeps_at_point
7444 subroutine sample_bhat_gradbhat_interpderiv_at_point(x,igrid,threshold, &
7445 bhat,grad_bhat,status)
7447 double precision,
intent(in) :: x(
ndim),threshold
7448 integer,
intent(in) :: igrid
7449 double precision,
intent(out) :: bhat(3),grad_bhat(3,3)
7450 integer,
intent(out) :: status
7452 double precision :: dxb^
d,dxc^
d,xd^
d
7453 double precision :: field(0:1^
d&,3)
7454 double precision :: b(3),dbdx(3,3)
7455 double precision :: wx(0:1),wy(0:1),wz(0:1)
7456 double precision :: dwx(0:1),dwy(0:1),dwz(0:1)
7457 double precision :: weight,bnorm,projected
7458 integer :: ixi^
l,ixbl^
d,ix^
d,j
7463 if (
ndim/=3 .or. .not.trace_cartesian_like_geometry() .or. igrid<0)
then
7470 call trace_interp_weights_block(x,igrid,ixi^
l,ixbl^
d,xd^
d,dxc^
d, &
7474 if (ixbl1<iximin1 .or. ixbl1+1>iximax1 .or. &
7475 ixbl2<iximin2 .or. ixbl2+1>iximax2 .or. &
7476 ixbl3<iximin3 .or. ixbl3+1>iximax3)
return
7479 if (.not.
b0field .and. .not.
allocated(iw_mag))
return
7483 if (
allocated(iw_mag))
then
7484 field(ix^
d,1:3)=ps(igrid)%w(ixbl1+ix1,ixbl2+ix2, &
7485 ixbl3+ix3,iw_mag(1:3))
7488 field(ix^
d,1:3)=field(ix^
d,1:3) &
7489 +ps(igrid)%B0(ixbl1+ix1,ixbl2+ix2,ixbl3+ix3,1:3,0)
7509 weight=wx(ix1)*wy(ix2)*wz(ix3)
7510 b(1:3)=b(1:3)+field(ix^
d,1:3)*weight
7511 dbdx(1:3,1)=dbdx(1:3,1)+field(ix^
d,1:3)* &
7512 dwx(ix1)*wy(ix2)*wz(ix3)
7513 dbdx(1:3,2)=dbdx(1:3,2)+field(ix^
d,1:3)* &
7514 wx(ix1)*dwy(ix2)*wz(ix3)
7515 dbdx(1:3,3)=dbdx(1:3,3)+field(ix^
d,1:3)* &
7516 wx(ix1)*wy(ix2)*dwz(ix3)
7519 bnorm=dsqrt(sum(b**2))
7520 if (bnorm<=zero .or. bnorm<threshold)
then
7527 projected=sum(bhat*dbdx(1:3,j))
7528 grad_bhat(1:3,j)=(dbdx(1:3,j)-bhat(1:3)*projected)/bnorm
7533 end subroutine sample_bhat_gradbhat_interpderiv_at_point
7535 subroutine sample_b_curlb_at_point(x,igrid,threshold,B,curlB,status, &
7538 double precision,
intent(in) :: x(
ndim),threshold
7539 integer,
intent(in) :: igrid
7540 double precision,
intent(out) :: b(3),curlb(3)
7541 integer,
intent(out) :: status
7542 type(trace_sph_interp_ctx),
intent(inout),
optional :: sph_cache
7544 double precision :: dxb^
d,dxc^
d,xd^
d
7545 double precision :: field(0:1^
d&,3),current(0:1^D&,3)
7546 double precision :: factor(0:1^
d&),B2
7547 double precision :: dx1c,dx2c,dx3c
7548 integer :: ixi^
l,ixj^
l,ixbl^
d,ix^
d,j
7555 if (geo_coordinate==geo_spherical)
then
7556 if (
present(sph_cache))
then
7557 call sample_b_curlb_spherical_at_point(x,igrid,threshold,b,curlb, &
7558 status,sph_cache=sph_cache)
7560 call sample_b_curlb_spherical_at_point(x,igrid,threshold,b,curlb, &
7569 call trace_interp_weights_block(x,igrid,ixi^
l,ixbl^
d,xd^
d,dxc^
d, &
7573 if (ixbl1-1<iximin1 .or. ixbl1+2>iximax1 .or. &
7574 ixbl2-1<iximin2 .or. ixbl2+2>iximax2 .or. &
7575 ixbl3-1<iximin3 .or. ixbl3+2>iximax3)
return
7577 if (ixbl1<ixjmin1 .or. ixbl1+1>ixjmax1 .or. &
7578 ixbl2<ixjmin2 .or. ixbl2+1>ixjmax2 .or. &
7579 ixbl3<ixjmin3 .or. ixbl3+1>ixjmax3)
return
7582 if (.not.
b0field .and. .not.
allocated(iw_mag))
return
7587 if (
allocated(iw_mag))
then
7588 field(ix^
d,1:3)=ps(igrid)%w(ixbl1+ix1,ixbl2+ix2, &
7589 ixbl3+ix3,iw_mag(1:3))
7592 field(ix^
d,1:3)=field(ix^
d,1:3) &
7593 +ps(igrid)%B0(ixbl1+ix1,ixbl2+ix2,ixbl3+ix3,1:3,0)
7595 if (
allocated(iw_mag))
then
7596 dx1c=ps(igrid)%x(ixbl1+ix1+1,ixbl2+ix2,ixbl3+ix3,1) &
7597 -ps(igrid)%x(ixbl1+ix1-1,ixbl2+ix2,ixbl3+ix3,1)
7598 dx2c=ps(igrid)%x(ixbl1+ix1,ixbl2+ix2+1,ixbl3+ix3,2) &
7599 -ps(igrid)%x(ixbl1+ix1,ixbl2+ix2-1,ixbl3+ix3,2)
7600 dx3c=ps(igrid)%x(ixbl1+ix1,ixbl2+ix2,ixbl3+ix3+1,3) &
7601 -ps(igrid)%x(ixbl1+ix1,ixbl2+ix2,ixbl3+ix3-1,3)
7602 if (abs(dx1c)<=smalldouble .or. abs(dx2c)<=smalldouble .or. &
7603 abs(dx3c)<=smalldouble)
then
7607 current(ix^
d,1)=half*( &
7608 (ps(igrid)%w(ixbl1+ix1,ixbl2+ix2+1,ixbl3+ix3,iw_mag(3)) &
7609 -ps(igrid)%w(ixbl1+ix1,ixbl2+ix2-1,ixbl3+ix3,iw_mag(3)))/dx2c &
7610 -(ps(igrid)%w(ixbl1+ix1,ixbl2+ix2,ixbl3+ix3+1,iw_mag(2)) &
7611 -ps(igrid)%w(ixbl1+ix1,ixbl2+ix2,ixbl3+ix3-1,iw_mag(2)))/dx3c)
7612 current(ix^
d,2)=half*( &
7613 (ps(igrid)%w(ixbl1+ix1,ixbl2+ix2,ixbl3+ix3+1,iw_mag(1)) &
7614 -ps(igrid)%w(ixbl1+ix1,ixbl2+ix2,ixbl3+ix3-1,iw_mag(1)))/dx3c &
7615 -(ps(igrid)%w(ixbl1+ix1+1,ixbl2+ix2,ixbl3+ix3,iw_mag(3)) &
7616 -ps(igrid)%w(ixbl1+ix1-1,ixbl2+ix2,ixbl3+ix3,iw_mag(3)))/dx1c)
7617 current(ix^
d,3)=half*( &
7618 (ps(igrid)%w(ixbl1+ix1+1,ixbl2+ix2,ixbl3+ix3,iw_mag(2)) &
7619 -ps(igrid)%w(ixbl1+ix1-1,ixbl2+ix2,ixbl3+ix3,iw_mag(2)))/dx1c &
7620 -(ps(igrid)%w(ixbl1+ix1,ixbl2+ix2+1,ixbl3+ix3,iw_mag(1)) &
7621 -ps(igrid)%w(ixbl1+ix1,ixbl2+ix2-1,ixbl3+ix3,iw_mag(1)))/dx2c)
7624 current(ix^
d,1:3)=current(ix^
d,1:3) &
7625 +ps(igrid)%J0(ixbl^
d+ix^
d,1:3)
7630 factor(ix^
d)={abs(1-ix^
d-xd^
d)*}
7634 b(j)=b(j)+field(ix^
d,j)*factor(ix^
d)
7635 curlb(j)=curlb(j)+current(ix^
d,j)*factor(ix^
d)
7640 if (b2<=zero .or. dsqrt(b2)<threshold)
then
7646 end subroutine sample_b_curlb_at_point
7648 subroutine sample_b_curlb_spherical_at_point(x,igrid,threshold,B,curlB, &
7652 double precision,
intent(in) :: x(
ndim),threshold
7653 integer,
intent(in) :: igrid
7654 double precision,
intent(out) :: b(3),curlb(3)
7655 integer,
intent(out) :: status
7656 type(trace_sph_interp_ctx),
intent(inout),
optional :: sph_cache
7658 double precision :: dxb^
d,dxc^
d,xd^
d
7659 double precision :: bvec(ixg^t,1:3),current(ixg^t,1:3)
7660 double precision :: factor(0:1^
d&),B2
7661 type(trace_sph_interp_ctx) :: ctx
7662 integer :: ixi^
l,ixo^
l,ixa^
l,ixj^
l,ixbl^
d,ix^
d,j,idirmin
7667 if (
ndim/=3 .or. geo_coordinate/=geo_spherical .or. igrid<0)
return
7670 if (
present(sph_cache))
then
7671 call trace_spherical_interp_ctx_build_cached(x,igrid,sph_cache,ctx, &
7674 call trace_spherical_interp_ctx_build(x,igrid,ctx,status)
7677 call trace_spherical_sample_bsph_ctx(ctx,threshold,b,status)
7679 if (trace_spherical_curl_cache_ready)
then
7680 call trace_spherical_sample_cached_curlb_ctx(ctx,curlb,status)
7683 if (b2<=zero .or. dsqrt(b2)<threshold)
then
7694 ^
d&dxc^
d=ctx%dxc(^
d);
7696 ^
d&ixbl^
d=ctx%ixbl(^
d);
7698 ^
d&ixomax^
d=ixbl^
d+1;
7702 if (iximin1>ixamin1 .or. iximax1<ixamax1 .or. &
7703 iximin2>ixamin2 .or. iximax2<ixamax2 .or. &
7704 iximin3>ixamin3 .or. iximax3<ixamax3)
return
7706 if (ixjmin1>ixomin1 .or. ixjmax1<ixomax1 .or. &
7707 ixjmin2>ixomin2 .or. ixjmax2<ixomax2 .or. &
7708 ixjmin3>ixomin3 .or. ixjmax3<ixomax3)
return
7711 if (.not.
b0field .and. .not.
allocated(iw_mag))
return
7715 if (
allocated(iw_mag))
then
7716 bvec(ixa^s,1:3)=ps(igrid)%w(ixa^s,iw_mag(1:3))
7722 current(ixo^s,1:3)=current(ixo^s,1:3)+ps(igrid)%J0(ixo^s,1:3)
7726 factor(ix^
d)={abs(1-ix^
d-xd^
d)*}
7730 curlb(j)=curlb(j)+current(ixbl^
d+ix^
d,j)*factor(ix^
d)
7735 if (b2<=zero .or. dsqrt(b2)<threshold)
then
7741 end subroutine sample_b_curlb_spherical_at_point
7743 subroutine sample_b_at_point(x,igrid,threshold,B,status)
7745 double precision,
intent(in) :: x(
ndim),threshold
7746 integer,
intent(in) :: igrid
7747 double precision,
intent(out) :: b(3)
7748 integer,
intent(out) :: status
7750 double precision :: dxb^
d,dxc^
d,xd^
d
7751 double precision :: field(0:1^
d&,3),factor(0:1^D&),B2
7752 double precision :: bcell(3)
7753 type(trace_sph_interp_ctx) :: ctx
7754 integer :: ixi^
l,ixbl^
d,ix^
d,j
7758 if (
ndim/=3 .or. igrid<0)
return
7762 if (geo_coordinate==geo_spherical)
then
7763 call trace_spherical_interp_ctx_build(x,igrid,ctx,status)
7765 call trace_spherical_sample_bsph_ctx(ctx,threshold,b,status)
7768 call trace_interp_weights_block(x,igrid,ixi^
l,ixbl^
d,xd^
d,dxc^
d, &
7773 if (ixbl1<iximin1 .or. ixbl1+1>iximax1 .or. &
7774 ixbl2<iximin2 .or. ixbl2+1>iximax2 .or. &
7775 ixbl3<iximin3 .or. ixbl3+1>iximax3)
return
7778 call trace_total_b_at_cell(igrid,ixbl1+ix1,ixbl2+ix2, &
7779 ixbl3+ix3,bcell,status)
7781 field(ix^
d,1:3)=bcell
7785 factor(ix^
d)={abs(1-ix^
d-xd^
d)*}
7789 b(j)=b(j)+field(ix^
d,j)*factor(ix^
d)
7794 if (b2<=zero .or. dsqrt(b2)<threshold)
then
7800 end subroutine sample_b_at_point
7802 subroutine trace_summary_fill_mapping(seed,source_igrid,forward_state, &
7803 backward_state,threshold,have_source_normal,source_normal,result)
7804 double precision,
intent(in) :: seed(
ndim),threshold,source_normal(3)
7805 integer,
intent(in) :: source_igrid
7806 logical,
intent(in) :: have_source_normal
7807 type(trace_summary_state),
intent(in) :: forward_state,backward_state
7814 result%forward_footpoint=forward_state%footpoint
7815 result%backward_footpoint=backward_state%footpoint
7816 result%forward_length=forward_state%length
7817 result%backward_length=backward_state%length
7818 result%forward_face=forward_state%face
7819 result%backward_face=backward_state%face
7820 result%forward_status=forward_state%status
7821 result%backward_status=backward_state%status
7823 call sample_b_at_point(seed,source_igrid,threshold,result%source_B,status)
7825 result%forward_status=status
7826 result%backward_status=status
7827 result%valid=.false.
7830 if (have_source_normal)
then
7831 result%source_Bn=sum(result%source_B*source_normal)
7835 call sample_b_at_point(forward_state%footpoint,forward_state%igrid, &
7836 threshold,result%forward_B,status)
7840 call sample_b_at_point(backward_state%footpoint,backward_state%igrid, &
7841 threshold,result%backward_B,status)
7845 result%forward_Bn=trace_face_bn(result%forward_face,result%forward_B)
7846 result%backward_Bn=trace_face_bn(result%backward_face,result%backward_B)
7849 trace_face_is_boundary(result%forward_face) .and. &
7850 trace_face_is_boundary(result%backward_face)
7851 end subroutine trace_summary_fill_mapping
7853 double precision function trace_face_bn(face_id,B)
result(Bn)
7854 integer,
intent(in) :: face_id
7855 double precision,
intent(in) :: b(3)
7858 select case(face_id)
7872 end function trace_face_bn
7874 logical function trace_face_is_boundary(face_id)
result(is_boundary)
7875 integer,
intent(in) :: face_id
7878 end function trace_face_is_boundary
7880 subroutine trace_boundary_face_at_point(x,face_id,on_boundary)
7881 double precision,
intent(in) :: x(
ndim)
7882 integer,
intent(out) :: face_id
7883 logical,
intent(out) :: on_boundary
7885 double precision :: domain_min(
ndim),domain_max(
ndim),tol
7886 integer :: idim,nface,candidate_face
7888 ^
d&domain_min(^
d)=xprobmin^
d;
7889 ^
d&domain_max(^
d)=xprobmax^
d;
7890 tol=100.d0*epsilon(one)*max(one,maxval(abs(domain_max-domain_min)))
7894 if (abs(x(idim)-domain_min(idim))<=tol)
then
7895 candidate_face=trace_face_from_dim_side(idim,-1)
7898 face_id=candidate_face
7899 else if (candidate_face/=face_id)
then
7903 if (abs(x(idim)-domain_max(idim))<=tol)
then
7904 candidate_face=trace_face_from_dim_side(idim,1)
7907 face_id=candidate_face
7908 else if (candidate_face/=face_id)
then
7914 end subroutine trace_boundary_face_at_point
7916 subroutine trace_intersect_domain(xinside,xoutside,xhit,hit_ok,face_id, &
7918 double precision,
intent(in) :: xinside(
ndim),xoutside(
ndim)
7919 double precision,
intent(out) :: xhit(
ndim)
7920 logical,
intent(out) :: hit_ok
7921 integer,
intent(out) :: face_id
7922 double precision,
intent(out),
optional :: alpha_out
7924 double precision :: alpha,alpha_hit,alpha_tol,delta
7925 double precision :: domain_min(
ndim),domain_max(
ndim)
7926 integer :: idim,hit_dim,hit_side,candidate_face
7928 ^
d&domain_min(^
d)=xprobmin^
d;
7929 ^
d&domain_max(^
d)=xprobmax^
d;
7931 alpha_tol=100.d0*epsilon(one)
7936 delta=xoutside(idim)-xinside(idim)
7937 if (xoutside(idim)<domain_min(idim) .and. abs(delta)>smalldouble)
then
7938 alpha=(domain_min(idim)-xinside(idim))/delta
7939 if (alpha>=zero .and. alpha<=one)
then
7940 candidate_face=trace_face_from_dim_side(idim,-1)
7941 if (alpha<alpha_hit-alpha_tol)
then
7945 face_id=candidate_face
7946 else if (abs(alpha-alpha_hit)<=alpha_tol .and. &
7947 candidate_face/=face_id)
then
7951 else if (xoutside(idim)>=domain_max(idim) .and. &
7952 abs(delta)>smalldouble)
then
7953 alpha=(domain_max(idim)-xinside(idim))/delta
7954 if (alpha>=zero .and. alpha<=one)
then
7955 candidate_face=trace_face_from_dim_side(idim,1)
7956 if (alpha<alpha_hit-alpha_tol)
then
7960 face_id=candidate_face
7961 else if (abs(alpha-alpha_hit)<=alpha_tol .and. &
7962 candidate_face/=face_id)
then
7971 if (
present(alpha_out)) alpha_out=zero
7972 if (.not.hit_ok)
return
7974 xhit=xinside+alpha_hit*(xoutside-xinside)
7976 xhit(idim)=min(max(xhit(idim),domain_min(idim)),domain_max(idim))
7978 if (hit_side<0)
then
7979 xhit(hit_dim)=domain_min(hit_dim)
7981 xhit(hit_dim)=domain_max(hit_dim)
7983 if (
present(alpha_out)) alpha_out=alpha_hit
7984 end subroutine trace_intersect_domain
7986 integer function trace_face_from_dim_side(idim,side)
result(face_id)
7987 integer,
intent(in) :: idim,side
8010 end function trace_face_from_dim_side
8012 subroutine trace_cartesian_local_cell_size(x,igrid,hcell,status)
8013 double precision,
intent(in) :: x(
ndim)
8014 integer,
intent(in) :: igrid
8015 double precision,
intent(out) :: hcell
8016 integer,
intent(out) :: status
8018 double precision :: dxc^
d,xd^
d
8019 integer :: ixi^
l,ixbl^
d
8023 if (.not.trace_cartesian_like_geometry() .or. igrid<0)
return
8027 call trace_interp_weights_block(x,igrid,ixi^
l,ixbl^
d,xd^
d,dxc^
d, &
8030 hcell=min(abs(dxc1),abs(dxc2))
8031 hcell=min(hcell,abs(dxc3))
8034 end subroutine trace_cartesian_local_cell_size
8036 subroutine trace_cartesian_rhs_bhat(x,igrid_hint,threshold,bhat,igrid, &
8038 double precision,
intent(in) :: x(
ndim),threshold
8039 integer,
intent(in) :: igrid_hint
8040 double precision,
intent(out) :: bhat(
ndim)
8041 integer,
intent(out) :: igrid,status
8043 double precision :: dxc^
d,xd^
d
8044 double precision :: field(0:1^
d&,3),factor(0:1^D&)
8045 double precision :: bcell(3),b(3),bnorm
8046 integer :: ixi^
l,ixbl^
d,ix^
d,j
8051 if (.not.trace_cartesian_like_geometry())
return
8054 call trace_locate_point_with_hint(x,igrid_hint,igrid,status)
8058 call trace_interp_weights_block(x,igrid,ixi^
l,ixbl^
d,xd^
d,dxc^
d, &
8064 call trace_total_b_at_cell(igrid,ixbl1+ix1,ixbl2+ix2, &
8065 ixbl3+ix3,bcell,status)
8067 field(ix^
d,1:3)=bcell
8071 factor(ix^
d)={abs(1-ix^
d-xd^
d)*}
8077 b(j)=b(j)+field(ix^
d,j)*factor(ix^
d)
8081 bnorm=dsqrt(sum(b**2))
8082 if (bnorm<=zero .or. bnorm<threshold)
then
8086 bhat=b(1:
ndim)/bnorm
8089 end subroutine trace_cartesian_rhs_bhat
8091 subroutine trace_rk45_try_boundary_finish(xnow,xstage,hfloor,xnext, &
8092 ds_actual,h_suggest,status,finished)
8093 double precision,
intent(in) :: xnow(
ndim),xstage(
ndim),hfloor
8094 double precision,
intent(out) :: xnext(
ndim),ds_actual
8095 double precision,
intent(inout) :: h_suggest
8096 integer,
intent(out) :: status
8097 logical,
intent(out) :: finished
8099 double precision :: xhit(
ndim)
8104 call trace_intersect_domain(xnow,xstage,xhit,hit_ok,face_id)
8105 if (.not.hit_ok)
return
8108 ds_actual=dsqrt(sum((xnext-xnow)**2))
8111 call trace_rk45_stats_note_attempt(.true.,.true.,ds_actual)
8113 end subroutine trace_rk45_try_boundary_finish
8115 subroutine trace_summary_rk45_cartesian_step(xnow,igrid,ds,forward, &
8116 threshold,h_suggest,xnext,ds_actual,status,accumulate_twist, &
8117 twist_increment,twist_status,twist_integrated)
8118 double precision,
intent(in) :: xnow(
ndim),ds,threshold
8119 integer,
intent(in) :: igrid
8120 logical,
intent(in) :: forward
8121 double precision,
intent(inout) :: h_suggest
8122 double precision,
intent(out) :: xnext(
ndim),ds_actual
8123 integer,
intent(out) :: status
8124 logical,
intent(in) :: accumulate_twist
8125 double precision,
intent(out) :: twist_increment
8126 integer,
intent(out) :: twist_status
8127 logical,
intent(out) :: twist_integrated
8129 double precision,
parameter :: b21=1.d0/5.d0
8130 double precision,
parameter :: b31=3.d0/40.d0,b32=9.d0/40.d0
8131 double precision,
parameter :: b41=3.d0/10.d0,b42=-9.d0/10.d0, &
8133 double precision,
parameter :: b51=-11.d0/54.d0,b52=5.d0/2.d0, &
8134 b53=-70.d0/27.d0,b54=35.d0/27.d0
8135 double precision,
parameter :: b61=1631.d0/55296.d0, &
8136 b62=175.d0/512.d0,b63=575.d0/13824.d0, &
8137 b64=44275.d0/110592.d0,b65=253.d0/4096.d0
8138 double precision,
parameter :: c1=37.d0/378.d0,c3=250.d0/621.d0, &
8139 c4=125.d0/594.d0,c6=512.d0/1771.d0
8140 double precision,
parameter :: cs1=2825.d0/27648.d0, &
8141 cs3=18575.d0/48384.d0,cs4=13525.d0/55296.d0, &
8142 cs5=277.d0/14336.d0,cs6=one/4.d0
8147 double precision :: h,hmax,hfloor,hcell,tol,err,grow,sgn
8148 double precision :: tw1,tw3,tw4,tw6
8149 double precision :: domain_min(
ndim),domain_max(
ndim)
8150 integer :: igrid1,igrid2,igrid3,igrid4,igrid5,igrid6
8151 integer :: iter,point_domain,face_id
8152 integer :: reject_reason
8153 logical :: hit_ok,boundary_limited,boundary_finished
8158 twist_increment=zero
8160 twist_integrated=.false.
8161 if (.not.trace_cartesian_like_geometry())
then
8167 if (hmax<=zero)
then
8174 hfloor=max(trace_step_min,100.d0*epsilon(one)*max(one,hmax))
8177 if (.not.forward) sgn=-one
8178 ^
d&domain_min(^
d)=xprobmin^
d;
8179 ^
d&domain_max(^
d)=xprobmax^
d;
8182 h=max(hfloor,min(h,hmax))
8183 call trace_cartesian_rhs_bhat(xnow,igrid,threshold,k1,igrid1,status)
8186 x2=xnow+sgn*h*b21*k1
8187 call trace_cartesian_rhs_bhat(x2,igrid1,threshold,k2,igrid2,status)
8192 call trace_rk45_try_boundary_finish(xnow,x2,hfloor,xnext, &
8193 ds_actual,h_suggest,status,boundary_finished)
8194 if (boundary_finished)
return
8196 reject_reason=trace_rk45_reject_stage_failure
8199 reject_reason=trace_rk45_reject_stage_outside
8200 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
8202 if (h<=hfloor*(one+epsilon(one)))
exit
8203 h=max(hfloor,half*h)
8207 x3=xnow+sgn*h*(b31*k1+b32*k2)
8208 call trace_cartesian_rhs_bhat(x3,igrid2,threshold,k3,igrid3,status)
8213 call trace_rk45_try_boundary_finish(xnow,x3,hfloor,xnext, &
8214 ds_actual,h_suggest,status,boundary_finished)
8215 if (boundary_finished)
return
8217 reject_reason=trace_rk45_reject_stage_failure
8220 reject_reason=trace_rk45_reject_stage_outside
8221 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
8223 if (h<=hfloor*(one+epsilon(one)))
exit
8224 h=max(hfloor,half*h)
8228 x4=xnow+sgn*h*(b41*k1+b42*k2+b43*k3)
8229 call trace_cartesian_rhs_bhat(x4,igrid3,threshold,k4,igrid4,status)
8234 call trace_rk45_try_boundary_finish(xnow,x4,hfloor,xnext, &
8235 ds_actual,h_suggest,status,boundary_finished)
8236 if (boundary_finished)
return
8238 reject_reason=trace_rk45_reject_stage_failure
8241 reject_reason=trace_rk45_reject_stage_outside
8242 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
8244 if (h<=hfloor*(one+epsilon(one)))
exit
8245 h=max(hfloor,half*h)
8249 x5s=xnow+sgn*h*(b51*k1+b52*k2+b53*k3+b54*k4)
8250 call trace_cartesian_rhs_bhat(x5s,igrid4,threshold,k5,igrid5,status)
8255 call trace_rk45_try_boundary_finish(xnow,x5s,hfloor,xnext, &
8256 ds_actual,h_suggest,status,boundary_finished)
8257 if (boundary_finished)
return
8259 reject_reason=trace_rk45_reject_stage_failure
8262 reject_reason=trace_rk45_reject_stage_outside
8263 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
8265 if (h<=hfloor*(one+epsilon(one)))
exit
8266 h=max(hfloor,half*h)
8270 x6=xnow+sgn*h*(b61*k1+b62*k2+b63*k3+b64*k4+b65*k5)
8271 call trace_cartesian_rhs_bhat(x6,igrid5,threshold,k6,igrid6,status)
8276 call trace_rk45_try_boundary_finish(xnow,x6,hfloor,xnext, &
8277 ds_actual,h_suggest,status,boundary_finished)
8278 if (boundary_finished)
return
8280 reject_reason=trace_rk45_reject_stage_failure
8283 reject_reason=trace_rk45_reject_stage_outside
8284 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
8286 if (h<=hfloor*(one+epsilon(one)))
exit
8287 h=max(hfloor,half*h)
8291 x5=xnow+sgn*h*(c1*k1+c3*k3+c4*k4+c6*k6)
8292 x4err=xnow+sgn*h*(cs1*k1+cs3*k3+cs4*k4+cs5*k5+cs6*k6)
8295 {
if (x5(^db)>=domain_min(^db) .and. x5(^db)<domain_max(^db)) point_domain=point_domain+1\}
8296 if (point_domain/=
ndim)
then
8297 call trace_intersect_domain(xnow,x5,xhit,hit_ok,face_id)
8300 ds_actual=dsqrt(sum((xnext-xnow)**2))
8303 call trace_rk45_stats_note_attempt(.true.,.true.,ds_actual)
8306 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
8307 trace_rk45_reject_boundary)
8312 call trace_cartesian_local_cell_size(xnow,igrid1,hcell,status)
8314 err=dsqrt(sum((x5-x4err)**2))
8315 tol=trace_rk45_atol+trace_rk45_rtol*max(h,hcell)
8316 if (err<=tol .or. h<=hfloor*(one+epsilon(one)))
then
8319 if (accumulate_twist)
then
8320 call trace_twist_density_at_point(xnow,igrid1,threshold,tw1, &
8323 call trace_twist_density_at_point(x3,igrid3,threshold,tw3, &
8326 call trace_twist_density_at_point(x4,igrid4,threshold,tw4, &
8329 call trace_twist_density_at_point(x6,igrid6,threshold,tw6, &
8332 twist_increment=h*(c1*tw1+c3*tw3+c4*tw4+c6*tw6)
8333 twist_integrated=.true.
8336 if (err>zero .and. tol>zero)
then
8337 grow=trace_rk45_safety*(tol/err)**0.2d0
8338 grow=max(trace_rk45_min_shrink,min(trace_rk45_max_grow,grow))
8340 grow=trace_rk45_max_grow
8342 h_suggest=min(hmax,max(hfloor,h*grow))
8343 call trace_rk45_stats_note_attempt(.true.,.false.,h)
8348 grow=trace_rk45_safety*(tol/max(err,smalldouble))**0.25d0
8349 grow=max(trace_rk45_min_shrink,min(one,grow))
8350 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
8351 trace_rk45_reject_error)
8352 h=max(hfloor,h*grow)
8355 call trace_intersect_domain(xnow,xnow+sgn*h*k1,xhit,hit_ok,face_id)
8357 boundary_limited=.true.
8359 ds_actual=dsqrt(sum((xnext-xnow)**2))
8361 call trace_rk45_stats_note_attempt(.true.,boundary_limited,ds_actual)
8366 end subroutine trace_summary_rk45_cartesian_step
8368 subroutine trace_summary_rk45_spherical_step(xnow,igrid,ds,forward, &
8369 threshold,h_suggest,sph_cache,xnext,ds_actual,status, &
8370 accumulate_twist,twist_increment,twist_status,twist_integrated)
8371 double precision,
intent(in) :: xnow(
ndim),ds,threshold
8372 integer,
intent(in) :: igrid
8373 logical,
intent(in) :: forward
8374 double precision,
intent(inout) :: h_suggest
8375 type(trace_sph_interp_ctx),
intent(inout) :: sph_cache
8376 double precision,
intent(out) :: xnext(
ndim),ds_actual
8377 integer,
intent(out) :: status
8378 logical,
intent(in) :: accumulate_twist
8379 double precision,
intent(out) :: twist_increment
8380 integer,
intent(out) :: twist_status
8381 logical,
intent(out) :: twist_integrated
8383 double precision,
parameter :: b21=1.d0/5.d0
8384 double precision,
parameter :: b31=3.d0/40.d0,b32=9.d0/40.d0
8385 double precision,
parameter :: b41=3.d0/10.d0,b42=-9.d0/10.d0, &
8387 double precision,
parameter :: b51=-11.d0/54.d0,b52=5.d0/2.d0, &
8388 b53=-70.d0/27.d0,b54=35.d0/27.d0
8389 double precision,
parameter :: b61=1631.d0/55296.d0, &
8390 b62=175.d0/512.d0,b63=575.d0/13824.d0, &
8391 b64=44275.d0/110592.d0,b65=253.d0/4096.d0
8392 double precision,
parameter :: c1=37.d0/378.d0,c3=250.d0/621.d0, &
8393 c4=125.d0/594.d0,c6=512.d0/1771.d0
8394 double precision,
parameter :: cs1=2825.d0/27648.d0, &
8395 cs3=18575.d0/48384.d0,cs4=13525.d0/55296.d0, &
8396 cs5=277.d0/14336.d0,cs6=one/4.d0
8401 double precision :: h,hmax,hfloor,hcell,tol,err,grow,sgn
8402 double precision :: tw1,tw3,tw4,tw6
8403 double precision :: r_metric,sin_theta_metric,alpha_hit
8404 double precision :: domain_min(
ndim),domain_max(
ndim)
8405 type(trace_sph_interp_ctx) :: ctx1,ctx2,ctx3,ctx4,ctx5,ctx6
8406 integer :: igrid1,igrid2,igrid3,igrid4,igrid5,igrid6
8407 integer :: iter,point_domain,face_id,ctx_status
8408 integer :: reject_reason
8409 logical :: hit_ok,field_ok
8410 character(len=std_len) :: field_type
8415 twist_increment=zero
8417 twist_integrated=.false.
8418 if (geo_coordinate/=geo_spherical)
then
8424 if (hmax<=zero)
then
8431 hfloor=max(trace_step_min,100.d0*epsilon(one)*max(one,hmax))
8434 if (.not.forward) sgn=-one
8436 ^
d&domain_min(^
d)=xprobmin^
d;
8437 ^
d&domain_max(^
d)=xprobmax^
d;
8440 h=max(hfloor,min(h,hmax))
8441 call trace_spherical_interp_ctx_build_cached(xnow,igrid,sph_cache, &
8447 call get_k_spherical_ctx(ctx1,k1,field_type,threshold,field_ok)
8448 if (.not.field_ok)
then
8455 x2=xnow+sgn*h*b21*k1
8456 call trace_spherical_interp_ctx_build_cached(x2,igrid1,sph_cache, &
8459 reject_reason=trace_rk45_reject_stage_failure
8462 reject_reason=trace_rk45_reject_stage_outside
8463 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
8465 if (h<=hfloor*(one+epsilon(one)))
exit
8466 h=max(hfloor,half*h)
8469 call get_k_spherical_ctx(ctx2,k2,field_type,threshold,field_ok)
8470 if (.not.field_ok)
then
8476 x3=xnow+sgn*h*(b31*k1+b32*k2)
8477 call trace_spherical_interp_ctx_build_cached(x3,igrid2,sph_cache, &
8480 reject_reason=trace_rk45_reject_stage_failure
8483 reject_reason=trace_rk45_reject_stage_outside
8484 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
8486 if (h<=hfloor*(one+epsilon(one)))
exit
8487 h=max(hfloor,half*h)
8490 call get_k_spherical_ctx(ctx3,k3,field_type,threshold,field_ok)
8491 if (.not.field_ok)
then
8497 x4=xnow+sgn*h*(b41*k1+b42*k2+b43*k3)
8498 call trace_spherical_interp_ctx_build_cached(x4,igrid3,sph_cache, &
8501 reject_reason=trace_rk45_reject_stage_failure
8504 reject_reason=trace_rk45_reject_stage_outside
8505 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
8507 if (h<=hfloor*(one+epsilon(one)))
exit
8508 h=max(hfloor,half*h)
8511 call get_k_spherical_ctx(ctx4,k4,field_type,threshold,field_ok)
8512 if (.not.field_ok)
then
8518 x5s=xnow+sgn*h*(b51*k1+b52*k2+b53*k3+b54*k4)
8519 call trace_spherical_interp_ctx_build_cached(x5s,igrid4,sph_cache, &
8522 reject_reason=trace_rk45_reject_stage_failure
8525 reject_reason=trace_rk45_reject_stage_outside
8526 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
8528 if (h<=hfloor*(one+epsilon(one)))
exit
8529 h=max(hfloor,half*h)
8532 call get_k_spherical_ctx(ctx5,k5,field_type,threshold,field_ok)
8533 if (.not.field_ok)
then
8539 x6=xnow+sgn*h*(b61*k1+b62*k2+b63*k3+b64*k4+b65*k5)
8540 call trace_spherical_interp_ctx_build_cached(x6,igrid5,sph_cache, &
8543 reject_reason=trace_rk45_reject_stage_failure
8546 reject_reason=trace_rk45_reject_stage_outside
8547 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
8549 if (h<=hfloor*(one+epsilon(one)))
exit
8550 h=max(hfloor,half*h)
8553 call get_k_spherical_ctx(ctx6,k6,field_type,threshold,field_ok)
8554 if (.not.field_ok)
then
8559 x5=xnow+sgn*h*(c1*k1+c3*k3+c4*k4+c6*k6)
8560 x4err=xnow+sgn*h*(cs1*k1+cs3*k3+cs4*k4+cs5*k5+cs6*k6)
8563 {
if (x5(^db)>=domain_min(^db) .and. x5(^db)<domain_max(^db)) point_domain=point_domain+1\}
8564 if (point_domain/=
ndim)
then
8565 call trace_intersect_domain(xnow,x5,xhit,hit_ok,face_id, &
8569 ds_actual=max(zero,min(one,alpha_hit))*h
8572 call trace_rk45_stats_note_attempt(.true.,.true.,ds_actual)
8575 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
8576 trace_rk45_reject_boundary)
8583 r_metric=max(abs(xnow(1)),smalldouble)
8584 sin_theta_metric=max(abs(dsin(xnow(2))),smalldouble)
8585 err=dsqrt((x5(1)-x4err(1))**2+ &
8586 (r_metric*(x5(2)-x4err(2)))**2+ &
8587 (r_metric*sin_theta_metric*(x5(3)-x4err(3)))**2)
8589 if (hcell<=zero) hcell=hmax
8590 tol=trace_rk45_atol+trace_rk45_rtol*max(h,hcell)
8591 if (err<=tol .or. h<=hfloor*(one+epsilon(one)))
then
8594 if (accumulate_twist)
then
8595 call trace_twist_density_at_point(xnow,ctx1%igrid,threshold,tw1, &
8596 twist_status,sph_cache)
8598 call trace_twist_density_at_point(x3,ctx3%igrid,threshold,tw3, &
8599 twist_status,sph_cache)
8601 call trace_twist_density_at_point(x4,ctx4%igrid,threshold,tw4, &
8602 twist_status,sph_cache)
8604 call trace_twist_density_at_point(x6,ctx6%igrid,threshold,tw6, &
8605 twist_status,sph_cache)
8607 twist_increment=h*(c1*tw1+c3*tw3+c4*tw4+c6*tw6)
8608 twist_integrated=.true.
8611 if (err>zero .and. tol>zero)
then
8612 grow=trace_rk45_safety*(tol/err)**0.2d0
8613 grow=max(trace_rk45_min_shrink,min(trace_rk45_max_grow,grow))
8615 grow=trace_rk45_max_grow
8617 h_suggest=min(hmax,max(hfloor,h*grow))
8618 call trace_rk45_stats_note_attempt(.true.,.false.,h)
8623 grow=trace_rk45_safety*(tol/max(err,smalldouble))**0.25d0
8624 grow=max(trace_rk45_min_shrink,min(one,grow))
8625 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
8626 trace_rk45_reject_error)
8627 h=max(hfloor,h*grow)
8631 end subroutine trace_summary_rk45_spherical_step
8633 subroutine trace_summary_rk2_step(xnow,igrid,ds,forward,threshold, &
8634 xnext,ds_actual,status,sph_cache)
8635 double precision,
intent(in) :: xnow(
ndim),ds,threshold
8636 integer,
intent(in) :: igrid
8637 logical,
intent(in) :: forward
8638 double precision,
intent(out) :: xnext(
ndim),ds_actual
8639 integer,
intent(out) :: status
8640 type(trace_sph_interp_ctx),
intent(inout),
optional :: sph_cache
8643 double precision :: ds_step
8644 double precision :: dxb^
d
8645 type(trace_sph_interp_ctx) :: ctx_now,ctx_stage
8647 integer :: igrid_stage
8648 integer :: ctx_status
8650 character(len=std_len) :: field_type
8659 if (geo_coordinate==geo_spherical)
then
8660 if (
present(sph_cache))
then
8661 call trace_spherical_interp_ctx_build_cached(xnow,igrid,sph_cache, &
8664 call trace_spherical_interp_ctx_build(xnow,igrid,ctx_now,ctx_status)
8670 ds_step=trace_spherical_effective_step_ctx(ds,ctx_now)
8671 call get_k_spherical_ctx(ctx_now,k1,field_type,threshold,field_ok)
8673 ds_step=trace_effective_step(xnow,ds,igrid,dxb^
d)
8674 call get_k(xnow,igrid,k1,ixi^
l,dxb^
d,field_type,threshold,field_ok)
8676 if (.not.field_ok)
then
8682 xstage=xnow+ds_step*k1
8684 xstage=xnow-ds_step*k1
8686 xstage_sample=xstage
8687 ^
d&xstage_sample(^
d)=max(xprobmin^
d,min(xstage_sample(^
d), &
8688 xprobmax^
d-100.d0*epsilon(one)*max(one,abs(xprobmax^
d))));
8689 call trace_locate_point_with_hint(xstage_sample,igrid,igrid_stage,status)
8692 if (geo_coordinate==geo_spherical)
then
8693 if (
present(sph_cache))
then
8694 call trace_spherical_interp_ctx_build_cached(xstage_sample, &
8695 igrid_stage,sph_cache,ctx_stage,ctx_status)
8697 call trace_spherical_interp_ctx_build(xstage_sample,igrid_stage, &
8698 ctx_stage,ctx_status)
8704 call get_k_spherical_ctx(ctx_stage,k2,field_type,threshold,field_ok)
8706 call get_k(xstage_sample,igrid_stage,k2,ixi^
l,dxb^
d,field_type, &
8709 if (.not.field_ok)
then
8715 xnext=xnow+ds_step*(half*k1+half*k2)
8717 xnext=xnow-ds_step*(half*k1+half*k2)
8719 if (geo_coordinate==geo_spherical)
then
8720 ds_actual=abs(ds_step)
8722 ds_actual=dsqrt(sum((xnext-xnow)**2))
8724 end subroutine trace_summary_rk2_step
8726 double precision function trace_effective_step(x,ds,igrid,dxb^D) &
8728 double precision,
intent(in) :: x(
ndim),ds
8729 integer,
intent(in) :: igrid
8730 double precision,
intent(in) :: dxb^
d
8732 double precision :: r,sin_theta,cell_scale,dxloc(
ndim),step_cap,hcell
8733 type(trace_sph_interp_ctx) :: ctx
8737 if (trace_cartesian_like_geometry())
then
8738 if (trace_step_control_mode==trace_step_control_cell_fraction)
then
8740 call trace_cartesian_local_cell_size(x,igrid,hcell,status)
8742 ds_eff=dsign(min(step_cap,trace_step_fraction*hcell),ds)
8743 if (trace_step_min>zero)
then
8744 ds_eff=dsign(max(abs(ds_eff),min(trace_step_min,step_cap)),ds)
8746 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_step_limit(step_cap, &
8747 trace_step_fraction*hcell,abs(ds_eff))
8752 if (geo_coordinate/=geo_spherical)
return
8755 call trace_spherical_interp_ctx_build(x,igrid,ctx,status)
8757 ds_eff=trace_spherical_effective_step_ctx(ds,ctx)
8762 call trace_spherical_local_cell_widths(x,igrid,dxloc,status)
8764 r=max(abs(x(1)),smalldouble)
8765 sin_theta=abs(dsin(x(2)))
8766 cell_scale=min(abs(dxloc(1)),r*abs(dxloc(2)))
8767 cell_scale=min(cell_scale,r*max(sin_theta,smalldouble)*abs(dxloc(3)))
8768 if (cell_scale>zero)
then
8769 select case (trace_step_control_mode)
8770 case (trace_step_control_cell_fraction)
8771 ds_eff=min(step_cap,trace_step_fraction*cell_scale)
8772 if (trace_step_min>zero) ds_eff=max(ds_eff,min(trace_step_min,step_cap))
8774 ds_eff=min(step_cap,cell_scale)
8778 end function trace_effective_step
8780 logical function trace_spherical_metric_ok(x)
result(is_ok)
8781 double precision,
intent(in) :: x(
ndim)
8783 double precision :: metric_tol
8788 metric_tol=100.d0*epsilon(one)
8789 is_ok=x(1)>metric_tol .and. abs(dsin(x(2)))>metric_tol
8791 end function trace_spherical_metric_ok
8793 double precision function trace_segment_length(xa,xb,ds_full,alpha) &
8795 double precision,
intent(in) :: xa(
ndim),xb(
ndim),ds_full
8796 double precision,
intent(in),
optional :: alpha
8798 if (geo_coordinate==geo_spherical)
then
8799 if (
present(alpha))
then
8800 length=max(zero,min(one,alpha))*abs(ds_full)
8805 length=dsqrt(sum((xb-xa)**2))
8807 end function trace_segment_length
8811 integer,
intent(in) :: nseed,max_steps
8812 double precision,
intent(in) :: seeds(nseed,
ndim),dl
8814 double precision,
intent(in),
optional :: b_min
8816 double precision :: field_min
8818 field_min=smalldouble
8819 if (
present(b_min)) field_min=max(b_min,zero)
8820 call trace_summary_multi(seeds,nseed,dl,max_steps,results,field_min)
8825 integer,
intent(in) :: nseed,max_steps
8826 double precision,
intent(in) :: seeds(nseed,
ndim),dl
8828 double precision,
intent(in),
optional :: b_min
8830 double precision :: field_min
8832 field_min=smalldouble
8833 if (
present(b_min)) field_min=max(b_min,zero)
8834 call trace_summary_twist_multi(seeds,nseed,dl,max_steps,results,field_min)
8838 b_min,source_normal)
8840 integer,
intent(in) :: nseed,max_steps
8841 double precision,
intent(in) :: seeds(nseed,
ndim),dl
8843 double precision,
intent(in),
optional :: b_min
8844 double precision,
intent(in),
optional :: source_normal(3)
8846 double precision :: field_min,normal(3)
8847 logical :: have_normal
8849 field_min=smalldouble
8850 if (
present(b_min)) field_min=max(b_min,zero)
8852 have_normal=
present(source_normal)
8853 if (have_normal) normal=source_normal
8854 call trace_summary_mapping_multi(seeds,nseed,dl,max_steps,results, &
8855 field_min,have_normal,normal)
8859 need_twist,need_mapping,b_min,source_normal)
8861 integer,
intent(in) :: nseed,max_steps
8862 double precision,
intent(in) :: seeds(nseed,
ndim),dl
8864 logical,
intent(in),
optional :: need_twist,need_mapping
8865 double precision,
intent(in),
optional :: b_min
8866 double precision,
intent(in),
optional :: source_normal(3)
8868 double precision :: field_min,normal(3)
8869 logical :: do_twist,do_mapping,have_normal
8871 field_min=smalldouble
8872 if (
present(b_min)) field_min=max(b_min,zero)
8875 if (
present(need_twist)) do_twist=need_twist
8876 if (
present(need_mapping)) do_mapping=need_mapping
8878 have_normal=
present(source_normal)
8879 if (have_normal) normal=source_normal
8881 call trace_summary_topology_multi(seeds,nseed,dl,max_steps,results, &
8882 field_min,do_twist,do_mapping,have_normal,normal)
8888 integer,
intent(in) :: nseed,max_steps
8889 double precision,
intent(in) :: seeds(nseed,
ndim),dl
8891 double precision,
intent(in),
optional :: b_min
8894 type(trace_tangent_state),
allocatable :: states(:)
8895 double precision :: field_min
8896 double precision :: seed_local(
ndim),zero_vec(
ndim)
8897 integer :: common_status,iseed,idim,igrid,iforward,ibackward
8898 integer :: seed_status
8901 if (nseed<=0)
return
8903 field_min=smalldouble
8904 if (
present(b_min)) field_min=max(b_min,zero)
8906 do_twist=
present(twist_results)
8911 else if (
ndim/=3 .or. .not.trace_cartesian_like_geometry())
then
8913 else if (dl<=zero .or. max_steps<=0)
then
8919 seed_local(idim)=seeds(iseed,idim)
8921 call trace_init_qperp_result(seed_local,results(iseed))
8922 results(iseed)%status=common_status
8923 if (do_twist)
call trace_summary_init_twist_result(seed_local, &
8924 twist_results(iseed),common_status)
8929 allocate(states(2*nseed))
8932 seed_local(idim)=seeds(iseed,idim)
8934 call trace_qperp_prepare_seed_result(seed_local,field_min, &
8935 results(iseed),igrid,seed_status)
8939 call trace_tangent_state_init(seed_local,results(iseed)%u0, &
8940 results(iseed)%v0,igrid,iseed,1,states(iforward), &
8941 accumulate_twist=do_twist)
8942 call trace_tangent_state_init(seed_local,results(iseed)%u0, &
8943 results(iseed)%v0,igrid,iseed,-1,states(ibackward), &
8944 accumulate_twist=do_twist)
8945 if (trace_integrator_mode==trace_integrator_rk45_cartesian .or. &
8946 trace_integrator_mode==trace_integrator_rk45_spherical)
then
8947 call trace_rk45_stats_note_direction()
8948 call trace_rk45_stats_note_direction()
8949 else if (trace_integrator_mode==trace_integrator_rk2)
then
8950 call trace_rk2_stats_note_direction()
8951 call trace_rk2_stats_note_direction()
8954 call trace_tangent_state_init(seed_local,zero_vec,zero_vec,igrid, &
8955 iseed,1,states(iforward),accumulate_twist=do_twist)
8956 call trace_tangent_state_init(seed_local,zero_vec,zero_vec,igrid, &
8957 iseed,-1,states(ibackward),accumulate_twist=do_twist)
8958 states(iforward)%active=.false.
8959 states(ibackward)%active=.false.
8960 states(iforward)%status=seed_status
8961 states(ibackward)%status=seed_status
8965 select case (trace_integrator_mode)
8966 case (trace_integrator_rk45_cartesian)
8967 call trace_tangent_trace_states_grouped(states,2*nseed,dl,max_steps, &
8968 field_min,trace_mode=trace_tangent_group_rk45_cartesian)
8969 case (trace_integrator_rk45_spherical)
8970 call trace_tangent_trace_states_grouped_rk45_spherical(states, &
8971 2*nseed,dl,max_steps,field_min)
8973 call trace_tangent_trace_states_grouped(states,2*nseed,dl,max_steps, &
8981 call trace_qperp_finalize_from_states(states(iforward), &
8982 states(ibackward),results(iseed),field_min)
8984 if (do_twist)
call trace_tangent_fill_twist_result(seeds(iseed,:), &
8985 states(iforward),states(ibackward),twist_results(iseed))
8991 max_steps,results,b_min,twist_results)
8996 integer,
intent(in) :: nseed,max_steps
8997 double precision,
intent(in) :: seeds(nseed,
ndim),dl
8999 double precision,
intent(in),
optional :: b_min
9002 type(trace_tangent_state),
allocatable :: states(:)
9003 double precision :: field_min
9004 double precision :: seed_local(
ndim),zero_vec(
ndim)
9005 integer :: common_status,iseed,idim,igrid,iforward,ibackward
9006 integer :: seed_status
9009 if (nseed<=0)
return
9011 field_min=smalldouble
9012 if (
present(b_min)) field_min=max(b_min,zero)
9014 do_twist=
present(twist_results)
9019 else if (
ndim/=3 .or. .not.trace_cartesian_like_geometry())
then
9021 else if (dl<=zero .or. max_steps<=0)
then
9027 seed_local(idim)=seeds(iseed,idim)
9029 call trace_init_qperp_result(seed_local,results(iseed))
9030 results(iseed)%status=common_status
9031 results(iseed)%status_q0=common_status
9032 if (do_twist)
call trace_summary_init_twist_result(seed_local, &
9033 twist_results(iseed),common_status)
9038 allocate(states(2*nseed))
9041 seed_local(idim)=seeds(iseed,idim)
9043 call trace_qperp_prepare_seed_result(seed_local,field_min, &
9044 results(iseed),igrid,seed_status)
9048 call trace_tangent_state_init(seed_local,results(iseed)%u0, &
9049 results(iseed)%v0,igrid,iseed,1,states(iforward), &
9050 accumulate_twist=do_twist)
9051 call trace_tangent_state_init(seed_local,results(iseed)%u0, &
9052 results(iseed)%v0,igrid,iseed,-1,states(ibackward), &
9053 accumulate_twist=do_twist)
9054 call trace_rk45_stats_note_direction()
9055 call trace_rk45_stats_note_direction()
9057 call trace_tangent_state_init(seed_local,zero_vec,zero_vec,igrid, &
9058 iseed,1,states(iforward),accumulate_twist=do_twist)
9059 call trace_tangent_state_init(seed_local,zero_vec,zero_vec,igrid, &
9060 iseed,-1,states(ibackward),accumulate_twist=do_twist)
9061 states(iforward)%active=.false.
9062 states(ibackward)%active=.false.
9063 states(iforward)%status=seed_status
9064 states(ibackward)%status=seed_status
9065 results(iseed)%status_q0=seed_status
9069 call trace_tangent_trace_states_grouped(states,2*nseed,dl,max_steps, &
9070 field_min,trace_mode=trace_tangent_group_rk45_cartesian)
9076 call trace_q0_finalize_from_states(states(iforward), &
9077 states(ibackward),results(iseed),field_min)
9079 if (do_twist)
call trace_tangent_fill_twist_result(seeds(iseed,:), &
9080 states(iforward),states(ibackward),twist_results(iseed))
9086 max_steps,results,b_min)
9087 integer,
intent(in) :: nseed,max_steps
9088 double precision,
intent(in) :: seeds(nseed,
ndim),dl
9090 double precision,
intent(in),
optional :: b_min
9092 if (
present(b_min))
then
9102 results,b_min,twist_results)
9104 integer,
intent(in) :: nseed,max_steps
9105 double precision,
intent(in) :: seeds(nseed,
ndim),dl
9107 double precision,
intent(in),
optional :: b_min
9110 type(trace_tangent_state),
allocatable :: states(:)
9111 double precision :: field_min
9112 double precision :: seed_local(
ndim),zero_vec(
ndim)
9113 integer :: common_status,iseed,idim,igrid,iforward,ibackward
9114 integer :: seed_status
9117 if (nseed<=0)
return
9118 if (trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical) &
9119 call trace_spherical_profile_add_count(trace_profile_q_tangent_systems, &
9120 int(2*nseed,kind=8))
9122 field_min=smalldouble
9123 if (
present(b_min)) field_min=max(b_min,zero)
9125 do_twist=
present(twist_results)
9130 else if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
then
9132 else if (dl<=zero .or. max_steps<=0)
then
9138 seed_local(idim)=seeds(iseed,idim)
9140 call trace_init_qperp_result(seed_local,results(iseed))
9141 results(iseed)%status=common_status
9142 results(iseed)%status_q0=common_status
9143 if (do_twist)
call trace_summary_init_twist_result(seed_local, &
9144 twist_results(iseed),common_status)
9149 allocate(states(2*nseed))
9152 seed_local(idim)=seeds(iseed,idim)
9154 call trace_spherical_rmin_q_prepare_seed_result(seed_local,field_min, &
9155 results(iseed),igrid,seed_status)
9159 call trace_tangent_state_init(seed_local,results(iseed)%u0, &
9160 results(iseed)%v0,igrid,iseed,1,states(iforward), &
9161 accumulate_twist=do_twist)
9162 call trace_tangent_state_init(seed_local,results(iseed)%u0, &
9163 results(iseed)%v0,igrid,iseed,-1,states(ibackward), &
9164 accumulate_twist=do_twist)
9165 if (trace_integrator_mode==trace_integrator_rk45_spherical)
then
9166 call trace_rk45_stats_note_direction()
9167 call trace_rk45_stats_note_direction()
9168 else if (trace_integrator_mode==trace_integrator_rk2)
then
9169 call trace_rk2_stats_note_direction()
9170 call trace_rk2_stats_note_direction()
9173 call trace_tangent_state_init(seed_local,zero_vec,zero_vec,igrid, &
9174 iseed,1,states(iforward),accumulate_twist=do_twist)
9175 call trace_tangent_state_init(seed_local,zero_vec,zero_vec,igrid, &
9176 iseed,-1,states(ibackward),accumulate_twist=do_twist)
9177 states(iforward)%active=.false.
9178 states(ibackward)%active=.false.
9179 states(iforward)%status=seed_status
9180 states(ibackward)%status=seed_status
9184 if (trace_integrator_mode==trace_integrator_rk45_spherical)
then
9185 call trace_tangent_trace_states_grouped_rk45_spherical(states, &
9186 2*nseed,dl,max_steps,field_min)
9188 call trace_tangent_trace_states_grouped(states,2*nseed,dl,max_steps, &
9196 call trace_spherical_rmin_q_finalize_from_states(states(iforward), &
9197 states(ibackward),results(iseed),field_min)
9199 if (do_twist)
call trace_tangent_fill_twist_result(seeds(iseed,:), &
9200 states(iforward),states(ibackward),twist_results(iseed))
9206 max_steps,results,b_min,twist_results)
9209 integer,
intent(in) :: nseed,max_steps
9210 double precision,
intent(in) :: seeds(nseed,
ndim),dl
9212 double precision,
intent(in),
optional :: b_min
9215 type(trace_tangent_state),
allocatable :: states(:)
9216 double precision :: field_min
9217 double precision :: seed_local(
ndim),zero_vec(
ndim)
9218 integer :: common_status,iseed,idim,igrid,iforward,ibackward
9219 integer :: seed_status
9220 logical :: do_twist,is_spherical
9222 if (nseed<=0)
return
9224 field_min=smalldouble
9225 if (
present(b_min)) field_min=max(b_min,zero)
9227 do_twist=
present(twist_results)
9228 is_spherical=(geo_coordinate==geo_spherical)
9233 else if (
ndim/=3)
then
9235 else if (geo_coordinate==geo_cartesian .and. .not.
slab_uniform)
then
9237 else if (geo_coordinate/=geo_cartesian .and. &
9238 geo_coordinate/=geo_spherical)
then
9240 else if (dl<=zero .or. max_steps<=0)
then
9246 seed_local(idim)=seeds(iseed,idim)
9248 call trace_init_qperp_result(seed_local,results(iseed))
9249 results(iseed)%status=common_status
9250 results(iseed)%status_q0=common_status
9251 if (do_twist)
call trace_summary_init_twist_result(seed_local, &
9252 twist_results(iseed),common_status)
9257 allocate(states(2*nseed))
9260 seed_local(idim)=seeds(iseed,idim)
9262 if (is_spherical)
then
9263 call trace_spherical_rmin_q_prepare_seed_result(seed_local,field_min, &
9264 results(iseed),igrid,seed_status)
9266 call trace_qperp_prepare_seed_result(seed_local,field_min, &
9267 results(iseed),igrid,seed_status)
9272 call trace_tangent_state_init(seed_local,results(iseed)%u0, &
9273 results(iseed)%v0,igrid,iseed,1,states(iforward), &
9274 accumulate_twist=do_twist)
9275 call trace_tangent_state_init(seed_local,results(iseed)%u0, &
9276 results(iseed)%v0,igrid,iseed,-1,states(ibackward), &
9277 accumulate_twist=do_twist)
9278 if (trace_integrator_mode==trace_integrator_rk45_spherical)
then
9279 call trace_rk45_stats_note_direction()
9280 call trace_rk45_stats_note_direction()
9281 else if (trace_integrator_mode==trace_integrator_rk2)
then
9282 call trace_rk2_stats_note_direction()
9283 call trace_rk2_stats_note_direction()
9286 call trace_tangent_state_init(seed_local,zero_vec,zero_vec,igrid, &
9287 iseed,1,states(iforward),accumulate_twist=do_twist)
9288 call trace_tangent_state_init(seed_local,zero_vec,zero_vec,igrid, &
9289 iseed,-1,states(ibackward),accumulate_twist=do_twist)
9290 states(iforward)%active=.false.
9291 states(ibackward)%active=.false.
9292 states(iforward)%status=seed_status
9293 states(ibackward)%status=seed_status
9294 results(iseed)%status_q0=seed_status
9298 call trace_tangent_trace_states_grouped(states,2*nseed,dl,max_steps, &
9299 field_min,trace_mode=trace_tangent_group_rk2_short_boundary)
9305 if (is_spherical)
then
9306 call trace_spherical_rmin_q_finalize_from_states(states(iforward), &
9307 states(ibackward),results(iseed),field_min)
9309 call trace_q0_finalize_from_states(states(iforward), &
9310 states(ibackward),results(iseed),field_min)
9313 if (do_twist)
call trace_tangent_fill_twist_result(seeds(iseed,:), &
9314 states(iforward),states(ibackward),twist_results(iseed))
9320 results,b_min,twist_results)
9322 integer,
intent(in) :: nseed,max_steps
9323 double precision,
intent(in) :: seeds(nseed,
ndim),dl
9325 double precision,
intent(in),
optional :: b_min
9328 type(trace_tangent_state),
allocatable :: states(:)
9329 double precision :: field_min
9330 double precision :: seed_local(
ndim),zero_vec(
ndim)
9331 integer :: common_status,iseed,idim,igrid,iforward,ibackward
9332 integer :: seed_status
9333 integer :: cache_status
9336 if (nseed<=0)
return
9337 if (trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical) &
9338 call trace_spherical_profile_add_count( &
9339 trace_profile_qperp_tangent_systems,int(2*nseed,kind=8))
9341 field_min=smalldouble
9342 if (
present(b_min)) field_min=max(b_min,zero)
9344 do_twist=
present(twist_results)
9349 else if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
then
9351 else if (dl<=zero .or. max_steps<=0)
then
9357 seed_local(idim)=seeds(iseed,idim)
9359 call trace_init_qperp_result(seed_local,results(iseed))
9360 results(iseed)%status=common_status
9361 results(iseed)%status_qperp0=common_status
9362 if (do_twist)
call trace_summary_init_twist_result(seed_local, &
9363 twist_results(iseed),common_status)
9373 seed_local(idim)=seeds(iseed,idim)
9375 call trace_init_qperp_result(seed_local,results(iseed))
9376 results(iseed)%status=cache_status
9377 results(iseed)%status_qperp0=cache_status
9378 call trace_summary_init_twist_result(seed_local, &
9379 twist_results(iseed),cache_status)
9385 allocate(states(2*nseed))
9388 seed_local(idim)=seeds(iseed,idim)
9390 call trace_spherical_qperp_prepare_seed_result(seed_local,field_min, &
9391 results(iseed),igrid,seed_status)
9395 call trace_tangent_state_init(seed_local,results(iseed)%u0, &
9396 results(iseed)%v0,igrid,iseed,1,states(iforward), &
9397 accumulate_twist=do_twist)
9398 call trace_tangent_state_init(seed_local,results(iseed)%u0, &
9399 results(iseed)%v0,igrid,iseed,-1,states(ibackward), &
9400 accumulate_twist=do_twist)
9401 if (trace_integrator_mode==trace_integrator_rk45_spherical)
then
9402 call trace_rk45_stats_note_direction()
9403 call trace_rk45_stats_note_direction()
9404 else if (trace_integrator_mode==trace_integrator_rk2)
then
9405 call trace_rk2_stats_note_direction()
9406 call trace_rk2_stats_note_direction()
9409 call trace_tangent_state_init(seed_local,zero_vec,zero_vec,igrid, &
9410 iseed,1,states(iforward),accumulate_twist=do_twist)
9411 call trace_tangent_state_init(seed_local,zero_vec,zero_vec,igrid, &
9412 iseed,-1,states(ibackward),accumulate_twist=do_twist)
9413 states(iforward)%active=.false.
9414 states(ibackward)%active=.false.
9415 states(iforward)%status=seed_status
9416 states(ibackward)%status=seed_status
9420 if (trace_integrator_mode==trace_integrator_rk45_spherical)
then
9421 call trace_tangent_trace_states_grouped_rk45_spherical(states, &
9422 2*nseed,dl,max_steps,field_min)
9424 call trace_tangent_trace_states_grouped(states,2*nseed,dl,max_steps, &
9432 call trace_spherical_qperp_finalize_from_states(states(iforward), &
9433 states(ibackward),results(iseed),field_min)
9435 if (do_twist)
call trace_tangent_fill_twist_result(seeds(iseed,:), &
9436 states(iforward),states(ibackward),twist_results(iseed))
9443 max_steps,q_results,qperp_results,b_min,twist_results)
9445 integer,
intent(in) :: nseed,max_steps
9446 double precision,
intent(in) :: seeds(nseed,
ndim),dl
9449 double precision,
intent(in),
optional :: b_min
9452 type(trace_tangent_state),
allocatable :: states(:)
9453 type(trace_tangent_state) :: qperp_forward_state,qperp_backward_state
9454 double precision :: field_min
9455 double precision :: seed_local(
ndim),zero_vec(
ndim)
9456 integer :: common_status,iseed,idim,igrid_q,igrid_qperp
9457 integer :: iforward,ibackward,seed_status_q,seed_status_qperp
9460 if (nseed<=0)
return
9461 if (trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical)
then
9462 call trace_spherical_profile_add_count(trace_profile_q_tangent_systems, &
9463 int(2*nseed,kind=8))
9464 call trace_spherical_profile_add_count( &
9465 trace_profile_qperp_tangent_systems,int(2*nseed,kind=8))
9466 call trace_spherical_profile_add_count( &
9467 trace_profile_combined_tangent_systems,int(2*nseed,kind=8))
9470 field_min=smalldouble
9471 if (
present(b_min)) field_min=max(b_min,zero)
9473 do_twist=
present(twist_results)
9478 else if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
then
9480 else if (dl<=zero .or. max_steps<=0)
then
9486 seed_local(idim)=seeds(iseed,idim)
9488 call trace_init_qperp_result(seed_local,q_results(iseed))
9489 q_results(iseed)%status=common_status
9490 q_results(iseed)%status_q0=common_status
9491 call trace_init_qperp_result(seed_local,qperp_results(iseed))
9492 qperp_results(iseed)%status=common_status
9493 qperp_results(iseed)%status_qperp0=common_status
9494 if (do_twist)
call trace_summary_init_twist_result(seed_local, &
9495 twist_results(iseed),common_status)
9500 allocate(states(2*nseed))
9503 seed_local(idim)=seeds(iseed,idim)
9505 call trace_spherical_rmin_q_prepare_seed_result(seed_local,field_min, &
9506 q_results(iseed),igrid_q,seed_status_q)
9507 call trace_spherical_qperp_prepare_seed_result(seed_local,field_min, &
9508 qperp_results(iseed),igrid_qperp,seed_status_qperp)
9514 call trace_tangent_state_init(seed_local,q_results(iseed)%u0, &
9515 q_results(iseed)%v0,igrid_q,iseed,1,states(iforward), &
9516 accumulate_twist=do_twist)
9517 call trace_tangent_state_init(seed_local,q_results(iseed)%u0, &
9518 q_results(iseed)%v0,igrid_q,iseed,-1,states(ibackward), &
9519 accumulate_twist=do_twist)
9520 states(iforward)%has_extra=.true.
9521 states(ibackward)%has_extra=.true.
9522 states(iforward)%p=qperp_results(iseed)%u0
9523 states(iforward)%q=qperp_results(iseed)%v0
9524 states(ibackward)%p=qperp_results(iseed)%u0
9525 states(ibackward)%q=qperp_results(iseed)%v0
9526 if (trace_integrator_mode==trace_integrator_rk45_spherical)
then
9527 call trace_rk45_stats_note_direction()
9528 call trace_rk45_stats_note_direction()
9529 else if (trace_integrator_mode==trace_integrator_rk2)
then
9530 call trace_rk2_stats_note_direction()
9531 call trace_rk2_stats_note_direction()
9534 call trace_tangent_state_init(seed_local,zero_vec,zero_vec,igrid_q, &
9535 iseed,1,states(iforward),accumulate_twist=do_twist)
9536 call trace_tangent_state_init(seed_local,zero_vec,zero_vec,igrid_q, &
9537 iseed,-1,states(ibackward),accumulate_twist=do_twist)
9538 states(iforward)%active=.false.
9539 states(ibackward)%active=.false.
9541 states(iforward)%status=seed_status_q
9542 states(ibackward)%status=seed_status_q
9544 states(iforward)%status=seed_status_qperp
9545 states(ibackward)%status=seed_status_qperp
9550 if (trace_integrator_mode==trace_integrator_rk45_spherical)
then
9551 call trace_tangent_trace_states_grouped_rk45_spherical(states, &
9552 2*nseed,dl,max_steps,field_min)
9554 call trace_tangent_trace_states_grouped(states,2*nseed,dl,max_steps, &
9562 call trace_spherical_rmin_q_finalize_from_states(states(iforward), &
9563 states(ibackward),q_results(iseed),field_min)
9566 qperp_forward_state=states(iforward)
9567 qperp_backward_state=states(ibackward)
9568 qperp_forward_state%u_perp=states(iforward)%p_perp
9569 qperp_forward_state%v_perp=states(iforward)%q_perp
9570 qperp_backward_state%u_perp=states(ibackward)%p_perp
9571 qperp_backward_state%v_perp=states(ibackward)%q_perp
9572 call trace_spherical_qperp_finalize_from_states(qperp_forward_state, &
9573 qperp_backward_state,qperp_results(iseed),field_min)
9575 if (do_twist)
call trace_tangent_fill_twist_result(seeds(iseed,:), &
9576 states(iforward),states(ibackward),twist_results(iseed))
9581 subroutine trace_field_multi(xfm,wPm,wLm,dL,numL,numP,nwP,nwL,forwardm,ftype,tcondi)
9609 integer,
intent(in) :: numL,numP,nwP,nwL
9610 double precision,
intent(inout) :: xfm(numL,numP,ndim),wPm(numL,numP,nwP),wLm(numL,1+nwL)
9611 double precision,
intent(in) :: dL
9612 logical,
intent(in) :: forwardm(numL)
9613 character(len=std_len),
intent(in) :: ftype,tcondi
9615 double precision :: x3d(3),statusF(4+ndim),statusL(numL,4+ndim+nwL),statusS(numL,4+ndim+nwL)
9616 double precision :: xf(numP,ndim),wP(numP,nwP),wL(1+nwL)
9617 double precision,
allocatable :: data_send(:,:,:),data_recv(:,:,:)
9618 integer :: indomain,ipe_now,igrid_now,igrid,j,iL
9619 integer :: ipoint_in,ipoint_out,numSend,nRT,nRTmax
9620 integer :: ipointm(numL),igridm(numL)
9621 logical :: continueL(numL),myL(numL)
9622 logical :: stopT,forward
9624 if (tcondi/=
'TRAC')
then
9630 xfm(1:numl,2:nump,:)=zero
9640 {
if (xfm(il,1,^db)>=xprobmin^db .and. xfm(il,1,^db)<xprobmax^db) indomain=indomain+1\}
9641 if (indomain==ndim)
then
9642 if (tcondi/=
'TRAC') wlm(il,1)=1
9643 continuel(il)=.true.
9652 igridm(il)=igrid_now
9653 if (
mype==ipe_now)
then
9659 continuel(il)=.false.
9664 do while(stopt .eqv. .false.)
9668 if (myl(il) .and. continuel(il))
then
9670 ipoint_in=ipointm(il)
9671 xf(ipoint_in,:)=xfm(il,ipoint_in,:)
9673 forward=forwardm(il)
9675 call find_points_in_pe(igrid,ipoint_in,xf,wp,wl,dl,nump,nwp,nwl,forward,ftype,tcondi,statusf)
9676 ipoint_out=int(statusf(1))
9677 xfm(il,ipoint_in:ipoint_out-1,:)=xf(ipoint_in:ipoint_out-1,:)
9678 wpm(il,ipoint_in:ipoint_out-1,:)=wp(ipoint_in:ipoint_out-1,:)
9688 statuss(il,1:4+ndim)=statusf(1:4+ndim)
9689 statuss(il,4+ndim+1:4+ndim+nwl)=wl(2:1+nwl)
9690 if (tcondi==
'TRAC') wlm(il,1)=ipoint_out-1
9695 numsend=numl*(4+ndim+nwl)
9696 call mpi_allreduce(statuss,statusl,numsend,mpi_double_precision,&
9703 if (continuel(il))
then
9704 ipointm(il)=int(statusl(il,1))
9705 if (
mype==int(statusl(il,2))) myl(il)=.true.
9706 igridm(il)=int(statusl(il,3))
9710 continuel(il)=.false.
9712 if (myl(il)) xfm(il,ipointm(il),1:ndim)=statusl(il,4+1:4+ndim)
9713 if (tcondi/=
'TRAC')
then
9715 wlm(il,1)=ipointm(il)
9717 wlm(il,1)=ipointm(il)-1
9720 wlm(il,2:1+nwl)=statusl(il,4+ndim+1:4+ndim+nwl)
9726 if (tcondi/=
'TRAC')
then
9729 if (nrtmax<int(wlm(il,1))) nrtmax=int(wlm(il,1))
9731 numsend=numl*nrtmax*(ndim+nwp)
9733 allocate(data_send(numl,nrtmax,ndim+nwp),data_recv(numl,nrtmax,ndim+nwp))
9734 data_send(:,:,:)=zero
9737 data_send(il,1:nrt,1:ndim)=xfm(il,1:nrt,1:ndim)
9738 if (nwp>0) data_send(il,1:nrt,1+ndim:ndim+nwp)=wpm(il,1:nrt,1:nwp)
9740 call mpi_allreduce(data_send,data_recv,numsend,mpi_double_precision,&
9744 xfm(il,1:nrt,1:ndim)=data_recv(il,1:nrt,1:ndim)
9745 if (nwp>0) wpm(il,1:nrt,1:nwp)=data_recv(il,1:nrt,1+ndim:ndim+nwp)
9747 deallocate(data_send,data_recv)
9780 integer,
intent(in) :: numP,nwP,nwL
9781 double precision,
intent(inout) :: xf(numP,ndim),wP(numP,nwP),wL(1+nwL)
9782 double precision,
intent(in) :: dL
9783 logical,
intent(in) :: forward
9784 character(len=std_len),
intent(in) :: ftype,tcondi
9786 double precision :: x3d(3),statusF(4+ndim),status_bcast(4+ndim+nwL)
9787 double precision,
allocatable :: data_send(:,:),data_recv(:,:)
9788 integer :: indomain,ipoint_in,ipe_now,igrid_now,igrid,j
9789 integer :: ipoint_out,ipe_next,igrid_next,numRT
9800 {
if (xf(1,^db)>=xprobmin^db .and. xf(1,^db)<xprobmax^db) indomain=indomain+1\}
9801 if (indomain==ndim)
then
9812 if (
mype/=ipe_now) xf(1,:)=zero
9815 call mpistop(
'Field tracing error: given point is not in simulation box!')
9821 do while(stopt .eqv. .false.)
9823 if (
mype==ipe_now)
then
9826 call find_points_in_pe(igrid,ipoint_in,xf,wp,wl,dl,nump,nwp,nwl,forward,ftype,tcondi,statusf)
9827 status_bcast(1:4+ndim)=statusf(1:4+ndim)
9828 status_bcast(4+ndim+1:4+ndim+nwl)=wl(2:1+nwl)
9831 call mpi_bcast(status_bcast,4+ndim+nwl,mpi_double_precision,ipe_now,
icomm,
ierrmpi)
9832 statusf(1:4+ndim)=status_bcast(1:4+ndim)
9833 wl(2:1+nwl)=status_bcast(4+ndim+1:4+ndim+nwl)
9836 ipoint_out=int(statusf(1))
9837 ipe_next=int(statusf(2))
9838 igrid_next=int(statusf(3))
9847 if (
mype==ipe_next)
then
9849 xf(ipoint_out,j)=statusf(4+j)
9852 xf(ipoint_out,:)=zero
9857 igrid_now=igrid_next
9858 ipoint_in=ipoint_out
9861 if (tcondi/=
'TRAC')
then
9863 allocate(data_send(numrt,ndim+nwp),data_recv(numrt,ndim+nwp))
9866 data_send(1:numrt,1:ndim)=xf(1:numrt,1:ndim)
9867 if (nwp>0) data_send(1:numrt,1+ndim:ndim+nwp)=wp(1:numrt,1:nwp)
9868 call mpi_allreduce(data_send,data_recv,numrt*(ndim+nwp),mpi_double_precision,&
9870 xf(1:numrt,1:ndim)=data_recv(1:numrt,1:ndim)
9871 if (nwp>0) wp(1:numrt,1:nwp)=data_recv(1:numrt,1+ndim:ndim+nwp)
9872 deallocate(data_send,data_recv)
9877 subroutine find_points_in_pe(igrid,ipoint_in,xf,wP,wL,dL,numP,nwP,nwL,forward,ftype,tcondi,statusF)
9879 integer,
intent(inout) :: igrid
9880 integer,
intent(in) :: ipoint_in,numP,nwP,nwL
9881 double precision,
intent(inout) :: xf(numP,ndim),wP(numP,nwP),wL(1+nwL)
9882 double precision,
intent(in) :: dL
9883 logical,
intent(in) :: forward
9884 character(len=std_len),
intent(in) :: ftype,tcondi
9885 double precision,
intent(inout) :: statusF(4+ndim)
9887 double precision :: xfout(ndim)
9888 integer :: ipe_next,igrid_next,ip_in,ip_out,j,indomain,trace_status
9889 logical :: newpe,stopT
9897 do while(newpe .eqv. .false.)
9900 dl,forward,ftype,tcondi,trace_status)
9909 {
if (xf(ip_out,^db)>=xprobmin^db .and. xf(ip_out,^db)<=xprobmax^db) indomain=indomain+1\}
9910 if (ip_out<nump .and. indomain==ndim)
then
9911 if (tcondi/=
'TRAC')
then
9931 if (ip_out>=nump)
then
9942 statusf(3)=igrid_next
9944 if (stopt) statusf(4)=trace_status
9946 statusf(4+j)=xf(ip_out,j)
9950 if (newpe .eqv. .false.) igrid=igrid_next
9961 integer,
intent(inout) :: igrid,igrid_next,ipe_next
9962 double precision,
intent(in) :: xf1(ndim)
9963 logical,
intent(inout) :: newpe,stopT
9965 double precision :: dxb^D,xb^L,xbmid^D
9966 double precision :: xbn^L
9967 integer :: idn^D,my_neighbor_type,inblock
9968 integer :: ic^D,inc^D,ipe_neighbor,igrid_neighbor
9979 {
if (xf1(^d)<=xbmin^d) idn^d=-1\}
9980 {
if (xf1(^d)>=xbmax^d) idn^d=1\}
9982 igrid_neighbor=
neighbor(1,idn^d,igrid)
9983 ipe_neighbor=
neighbor(2,idn^d,igrid)
9986 select case(my_neighbor_type)
9994 igrid_next=igrid_neighbor
9995 ipe_next=ipe_neighbor
9996 if (
mype==ipe_neighbor)
then
10004 igrid_next=igrid_neighbor
10005 ipe_next=ipe_neighbor
10006 if (
mype==ipe_neighbor)
then
10014 {xbmid^d=(xbmin^d+xbmax^d)/2.d0\}
10016 {
if (xf1(^d)<=xbmin^d) inc^d=0\}
10017 {
if (xf1(^d)>xbmin^d .and. xf1(^d)<=xbmid^d) inc^d=1\}
10018 {
if (xf1(^d)>xbmid^d .and. xf1(^d)<xbmax^d) inc^d=2\}
10019 {
if (xf1(^d)>=xbmax^d) inc^d=3\}
10022 if (
mype==ipe_next)
then
10032 dL,forward,ftype,tcondi,trace_status)
10036 integer,
intent(in) :: igrid,ip_in,numP,nwP,nwL
10037 integer,
intent(inout) :: ip_out
10038 double precision,
intent(inout) :: xf(numP,ndim),wP(numP,nwP),wL(1+nwL)
10039 double precision,
intent(in) :: dL
10040 logical,
intent(in) :: forward
10041 character(len=std_len),
intent(in) :: ftype,tcondi
10042 integer,
intent(out) :: trace_status
10044 double precision :: dxb^D,xb^L
10045 double precision :: field(ixg^T,ndir)
10046 double precision :: xs1(ndim),xs2(ndim),K1(ndim),K2(ndim)
10047 double precision :: xfpre(ndim),xfnow(ndim),xfnext(ndim)
10048 double precision :: Tpre,Tnow,Tnext,dTds,Lt,Lr,ds,T_bott,trac_delta
10049 integer :: ip,inblock,ixI^L,ixO^L,j
10050 logical :: field_ok
10060 if (tcondi/=
'TRAC')
then
10069 mainloop:
do ip=ip_in,nump-1
10073 call get_k(xs1,igrid,k1,ixi^l,dxb^d,ftype,smalldouble,field_ok)
10074 if (.not.field_ok)
then
10080 xs2(:)=xf(ip,:)+ds*k1(:)
10082 xs2(:)=xf(ip,:)-ds*k1(:)
10084 call get_k(xs2,igrid,k2,ixi^l,dxb^d,ftype,smalldouble,field_ok)
10085 if (.not.field_ok)
then
10091 xf(ip+1,:)=xf(ip,:)+ds*(0.5*k1(:)+0.5*k2(:))
10093 xf(ip+1,:)=xf(ip,:)-ds*(0.5*k1(:)+0.5*k2(:))
10098 if (tcondi/=
'TRAC')
then
10100 call usr_set_field_w(igrid,ip,xf,wp,wl,nump,nwp,nwl,dl,forward,ftype,tcondi)
10105 if (ip==ip_in)
then
10107 xfpre(:)=xf(ip,:)-ds*k1(:)
10109 xfpre(:)=xf(ip,:)+ds*k1(:)
10112 xfnext(:)=xf(ip+1,:)
10119 xfnext(:)=xf(ip+1,:)
10124 dtds=abs(tnext-tpre)/(2*ds)
10131 if (dtds>0.d0)
then
10135 if(lr>trac_delta*lt)
then
10136 if (tnow>wl(2)) wl(2)=tnow
10139 if (tnow>wl(3)) wl(3)=tnow
10145 {
if (xf(ip+1,^db)>=xbmin^db .and. xf(ip+1,^db)<xbmax^db) inblock=inblock+1\}
10146 if (tcondi==
'TRAC' .and. xf(ip+1,ndim)>
phys_trac_mask) inblock=0
10147 if (inblock/=ndim)
exit mainloop
10153 subroutine get_k(xfn,igrid,K,ixI^L,dxb^D,ftype,b_min,field_ok)
10156 integer :: ixI^L,igrid
10157 double precision :: dxb^D
10158 double precision :: xfn(ndim),K(ndim)
10159 character(len=std_len) :: ftype
10160 double precision,
intent(in),
optional :: b_min
10161 logical,
intent(out),
optional :: field_ok
10163 double precision :: dxc^D,xd^D
10164 double precision :: field(0:1^D&,ndir),Fx(ndim),factor(0:1^D&)
10165 double precision :: Ftotal,field_min
10166 double precision :: w_stencil(0:1^D&,1:nw)
10167 double precision :: x_stencil(0:1^D&,1:ndim)
10168 double precision :: vector_stencil(0:1^D&,1:ndir)
10169 logical :: valid_field
10170 integer :: ixb^D,ix^D,ixbl^D,j,status_interp
10173 if (geo_coordinate==geo_spherical)
then
10174 call trace_interp_weights_block(xfn,igrid,ixi^l,ixbl^d,xd^d,dxc^d, &
10177 if (
present(field_ok)) field_ok=.false.
10182 ^d&ixbl^d=floor((xfn(^d)-ps(igrid)%x(iximin^dd,^d))/dxb^d)+iximin^d;
10183 ^d&xd^d=(xfn(^d)-ps(igrid)%x(ixbl^dd,^d))/dxb^d;
10187 if(ftype==
'Bfield')
then
10189 if(
allocated(iw_mag))
then
10191 field(ix^d,1:ndir)=ps(igrid)%w(ixbl^d+ix^d,iw_mag(1:ndir)) &
10192 +ps(igrid)%B0(ixbl^d+ix^d,1:ndir,0)
10196 field(ix^d,1:ndir)=ps(igrid)%B0(ixbl^d+ix^d,1:ndir,0)
10201 field(ix^d,1:ndir)=ps(igrid)%w(ixbl^d+ix^d,iw_mag(1:ndir))
10204 else if (ftype==
'Vfield')
then
10209 w_stencil(ixs^s,1:nw)=ps(igrid)%w(ixbl^d:ixbl^d+1^d&,1:nw)
10210 x_stencil(ixs^s,1:ndim)=ps(igrid)%x(ixbl^d:ixbl^d+1^d&,1:ndim)
10211 call phys_get_v(w_stencil,x_stencil,ixs^l,ixs^l,vector_stencil)
10213 field(ix^d,1:ndir)=vector_stencil(ix^d,1:ndir)
10217 factor(ix^d)={abs(1-ix^d-xd^d)*}
10220 if (ftype==
'Bfield' .or. ftype==
'Vfield')
then
10224 fx(j)=fx(j)+field(ix^d,j)*factor(ix^d)
10230 call mpistop(
'Field tracing error: wrong field type!')
10235 ftotal=ftotal+(fx(j))**2
10237 ftotal=dsqrt(ftotal)
10239 field_min=smalldouble
10240 if (
present(b_min)) field_min=max(b_min,zero)
10241 valid_field=ftotal>zero .and. ftotal>=field_min
10242 if (
present(field_ok)) field_ok=valid_field
10245 if (valid_field)
then
10246 select case (geo_coordinate)
10247 case (geo_spherical)
10249 if (.not.trace_spherical_metric_ok(xfn))
then
10250 valid_field=.false.
10251 if (
present(field_ok)) field_ok=.false.
10255 k(2)=fx(2)/(xfn(1)*ftotal)
10256 k(3)=fx(3)/(xfn(1)*dsin(xfn(2))*ftotal)
10259 k(1:ndim)=fx(1:ndim)/ftotal
10263 end subroutine get_k
10268 integer,
intent(in) :: igrid,ixI^L
10269 double precision,
intent(inout) :: xloc(ndim)
10270 double precision,
intent(inout) :: Tloc
10271 double precision,
intent(in) :: dxb^D
10273 double precision :: xd^D
10274 double precision :: factor(0:1^D&),Tnear(0:1^D&)
10275 integer :: ixb^D,ix^D,ixbl^D,j,ixO^L
10277 ^d&ixbl^d=floor((xloc(^d)-ps(igrid)%x(iximin^dd,^d))/dxb^d)+iximin^d;
10278 ^d&xd^d=(xloc(^d)-ps(igrid)%x(ixbl^dd,^d))/dxb^d;
10279 ^d&ixomin^d=ixbl^d;
10280 ^d&ixomax^d=ixomin^d+1;
10283 factor(ix^d)={abs(1-ix^d-xd^d)*}
10284 tnear(ix^d)=ps(igrid)%wextra(ixbl^d+ix^d,iw_tcoff)
10290 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_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, public trace_debug_sample_bhat_gradbhat(seed, bhat, grad_bhat, status, b_min)
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)
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