2 use,
intrinsic :: ieee_arithmetic, only: ieee_value,ieee_quiet_nan, &
72 private :: trace_summary_seed,trace_summary_multi
73 private :: trace_summary_twist_seed,trace_summary_twist_multi
74 private :: trace_summary_mapping_seed,trace_summary_mapping_multi
75 private :: trace_summary_topology_multi
76 private :: trace_summary_validate,trace_summary_init_result
77 private :: trace_summary_init_twist_result
78 private :: trace_summary_init_mapping_result
79 private :: trace_summary_init_topology_result
80 private :: trace_summary_locate_seed,trace_summary_trace_seed
81 private :: trace_summary_trace_twist_seed
82 private :: trace_summary_init_state,trace_summary_advance_state
83 private :: trace_summary_trace_state_to_end,trace_summary_trace_states_grouped
84 private :: trace_summary_advance_state_in_grid
85 private :: trace_summary_rk2_step,trace_summary_rk45_cartesian_step
86 private :: trace_summary_rk45_spherical_step
87 private :: trace_intersect_domain
88 private :: trace_summary_accumulate_twist,trace_twist_density_at_point
89 private :: trace_tangent_accumulate_twist,trace_tangent_fill_twist_result
90 private :: sample_b_curlb_at_point
91 private :: sample_b_curlb_spherical_at_point
92 private :: sample_b_at_point,trace_summary_fill_mapping
93 private :: trace_total_b_at_cell,trace_bhat_at_cell
94 private :: sample_bhat_gradbhat_at_point
95 private :: sample_bhat_gradbhat_cellfd_at_point
96 private :: sample_bhat_gradbhat_xeps_at_point
97 private :: sample_bhat_gradbhat_interpderiv_at_point
98 private :: trace_debug_locate_point,trace_locate_point_with_hint
99 private :: trace_tangent_rhs
100 private :: trace_advance_tangent_state_rk2,trace_project_to_perp_bhat
101 private :: trace_tangent_rk2_trial,trace_endpoint_b_bhat
102 private :: trace_tangent_rk2_trial_from_rhs
103 private :: trace_tangent_state_advance_in_grid_rk45_cartesian
104 private :: trace_tangent_rk45_cartesian_step
105 private :: trace_tangent_rhs_cartesian_located
106 private :: trace_tangent_rk45_cartesian_finish_boundary
107 private :: trace_tangent_trace_states_grouped_rk45_spherical
108 private :: trace_tangent_state_advance_in_grid_rk45_spherical
109 private :: trace_tangent_rk45_spherical_step
110 private :: trace_tangent_rk45_spherical_finish_boundary
111 private :: trace_q0_finalize_from_states
112 private :: trace_sample_b_on_domain_face_limit
113 private :: trace_locate_face_limit_grid
114 private :: trace_face_normal,trace_project_to_boundary_face
115 private :: trace_make_perp_basis,trace_debug_nan
116 private :: trace_face_from_dim_side,trace_face_bn,trace_face_is_boundary
117 private :: trace_boundary_face_at_point
118 private :: trace_is_supported_summary_geometry
119 private :: trace_effective_step,trace_spherical_metric_ok
120 private :: trace_segment_length
121 private :: trace_summary_twist_status_from_states
122 private :: trace_init_qperp_result,trace_qperp_single_core
123 private :: trace_qperp_compute_q0_scalars
124 private :: trace_qperp_project_to_boundary_face
125 private :: trace_tangent_state_init
126 private :: trace_tangent_trace_states_grouped
127 private :: trace_tangent_state_advance_in_grid
128 private :: trace_tangent_state_finalize_boundary
129 private :: trace_qperp_prepare_seed_result
130 private :: trace_qperp_compute_scalars
131 private :: trace_qperp_finalize_from_states
132 private :: trace_spherical_rmin_q_prepare_seed_result
133 private :: trace_spherical_rmin_q_finalize_from_states
134 private :: trace_spherical_radial_q_finalize_from_states
135 private :: trace_spherical_radial_q_face_pair_admitted
136 private :: trace_spherical_radial_endpoint_matrix
137 private :: trace_spherical_radial_project_to_surface
138 private :: trace_spherical_qperp_prepare_seed_result
139 private :: trace_spherical_qperp_finalize_from_states
140 private :: trace_spherical_qperp_compute_from_states
141 private :: trace_spherical_q_from_endpoint_matrices
142 private :: trace_spherical_basis,trace_spherical_coord_to_cart
143 private :: trace_cart_to_spherical_coord
144 private :: trace_spherical_sample_b_bhat_cart
145 private :: trace_spherical_sample_bhat_gradbhat_covariant
146 private :: trace_spherical_sample_bhat_gradbhat_cartfd
147 private :: trace_spherical_bhat_cart_to_rhs
148 private :: trace_spherical_endpoint_b_bhat
149 private :: trace_spherical_face_probe_coord
150 private :: trace_spherical_physical_cell_scale
151 private :: trace_spherical_cell_scale_from_widths
152 private :: trace_spherical_interp_ctx_build
153 private :: trace_spherical_interp_ctx_build_cached
154 private :: trace_spherical_effective_step_ctx
155 private :: trace_spherical_sample_bsph_ctx
156 private :: trace_spherical_sample_b_bhat_cart_ctx
157 private :: trace_spherical_sample_cached_curlb_ctx
158 private :: trace_spherical_sample_bhat_gradbhat_covariant_ctx
159 private :: get_k_spherical_ctx
160 private :: trace_spherical_interp_ctx_fill
161 private :: trace_spherical_interp_ctx_load_bcorners
162 private :: trace_interp_weights_block,trace_interp_index_3d
163 private :: trace_interp_weights_block_near,trace_interp_index_3d_near
164 private :: trace_spherical_local_cell_widths
165 private :: trace_spherical_profile_add_count
166 private :: trace_spherical_profile_add_time
167 private :: trace_spherical_profile_note_trace_steps
168 private :: trace_spherical_profile_time
169 private :: trace_cartesian_like_geometry,trace_rk45_position_integrator
170 private :: trace_cartesian_rhs_bhat
171 private :: trace_cartesian_local_cell_size
172 private :: trace_rk45_try_boundary_finish
173 private :: trace_rk2_stats_note_direction
174 private :: trace_rk2_stats_note_step
175 private :: trace_rk2_stats_note_completion
176 private :: trace_rk2_stats_note_step_limit
177 private :: trace_rk2_stats_note_group_iteration
178 private :: trace_rk2_stats_note_grid_group
179 private :: trace_rk2_stats_note_rhs
180 private :: trace_rk2_stats_add_grouped_time
181 private :: trace_rk45_stats_note_direction
182 private :: trace_rk45_stats_note_attempt
183 private :: trace_rk45_stats_note_tangent_error
185 type,
private :: trace_sph_interp_ctx
186 logical :: valid=.false.
189 double precision :: x(3)=zero
190 double precision :: xd(3)=zero
191 double precision :: dxc(3)=zero
192 double precision :: w(0:1,3)=zero
193 double precision :: dxloc(3)=zero
194 double precision :: r=zero,theta=zero,phi=zero
195 double precision :: sin_theta=zero,cos_theta=zero
196 double precision :: sin_phi=zero,cos_phi=zero
197 double precision :: rsin_theta=zero
198 double precision :: h_local=zero
199 logical :: bcorner_valid=.false.
200 double precision :: bcorner(0:1,0:1,0:1,3)=zero
201 end type trace_sph_interp_ctx
203 type,
private :: trace_spherical_curl_cache_block
204 double precision,
dimension(:^D&,:),
allocatable :: current
205 logical :: ready=.false.
206 end type trace_spherical_curl_cache_block
208 type(trace_spherical_curl_cache_block),
allocatable,
private :: &
209 trace_spherical_curl_cache(:)
210 logical,
private :: trace_spherical_curl_cache_ready=.false.
212 integer,
parameter,
private :: trace_step_control_fixed=0
213 integer,
parameter,
private :: trace_step_control_cell_fraction=1
214 integer,
private :: trace_step_control_mode=trace_step_control_fixed
215 double precision,
private :: trace_step_fraction=0.1d0
216 double precision,
private :: trace_step_min=0.d0
218 integer,
parameter,
private :: trace_integrator_rk2=0
219 integer,
parameter,
private :: trace_integrator_rk45_cartesian=1
220 integer,
parameter,
private :: trace_integrator_rk45_spherical=2
221 integer,
parameter,
private :: trace_tangent_group_rk2_general=1
222 integer,
parameter,
private :: trace_tangent_group_rk2_short_boundary=2
223 integer,
parameter,
private :: trace_tangent_group_rk45_cartesian=3
224 integer,
parameter,
private :: trace_rk45_reject_error=1
225 integer,
parameter,
private :: trace_rk45_reject_stage_failure=2
226 integer,
parameter,
private :: trace_rk45_reject_stage_outside=3
227 integer,
parameter,
private :: trace_rk45_reject_boundary=4
228 integer,
parameter,
private :: trace_rk45_reject_tangent_error=5
229 integer,
private :: trace_integrator_mode=trace_integrator_rk2
230 double precision,
private :: trace_rk45_atol=1.
d-8
231 double precision,
private :: trace_rk45_rtol=1.
d-6
232 double precision,
private :: trace_rk45_safety=0.9d0
233 double precision,
private :: trace_rk45_min_shrink=0.2d0
234 double precision,
private :: trace_rk45_max_grow=5.d0
235 double precision,
private :: trace_rk45_tangent_floor=1.d0
236 double precision,
private :: trace_rk45_tangent_rtol=2.
d-5
237 logical,
private :: trace_rk2_stats_enabled=.false.
238 integer(kind=8),
private :: trace_rk2_directions=0_8
239 integer(kind=8),
private :: trace_rk2_completed_directions=0_8
240 integer(kind=8),
private :: trace_rk2_total_steps=0_8
241 integer(kind=8),
private :: trace_rk2_boundary_completions=0_8
242 integer(kind=8),
private :: trace_rk2_max_steps_failures=0_8
243 integer(kind=8),
private :: trace_rk2_domain_limited_steps=0_8
244 integer(kind=8),
private :: trace_rk2_grid_transition_steps=0_8
245 integer(kind=8),
private :: trace_rk2_cell_fraction_limited=0_8
246 integer(kind=8),
private :: trace_rk2_dl_limited=0_8
247 integer(kind=8),
private :: trace_rk2_dl_min_limited=0_8
248 integer(kind=8),
private :: trace_rk2_group_iterations=0_8
249 integer(kind=8),
private :: trace_rk2_grid_groups=0_8
250 integer(kind=8),
private :: trace_rk2_group_state_sum=0_8
251 integer(kind=8),
private :: trace_rk2_group_state_max=0_8
252 integer(kind=8),
private :: trace_rk2_rhs_calls=0_8
253 double precision,
private :: trace_rk2_sum_step_length=0.d0
254 double precision,
private :: trace_rk2_min_step_length=huge(one)
255 double precision,
private :: trace_rk2_max_step_length=0.d0
256 double precision,
private :: trace_rk2_grouped_time=0.d0
257 integer(kind=8),
private :: trace_rk2_max_steps_per_direction=0_8
258 logical,
private :: trace_rk45_stats_enabled=.false.
259 integer(kind=8),
private :: trace_rk45_directions=0_8
260 integer(kind=8),
private :: trace_rk45_attempts=0_8
261 integer(kind=8),
private :: trace_rk45_accepted=0_8
262 integer(kind=8),
private :: trace_rk45_rejected=0_8
263 integer(kind=8),
private :: trace_rk45_rejected_error=0_8
264 integer(kind=8),
private :: trace_rk45_rejected_position_error=0_8
265 integer(kind=8),
private :: trace_rk45_rejected_tangent_error=0_8
266 integer(kind=8),
private :: trace_rk45_rejected_stage_failure=0_8
267 integer(kind=8),
private :: trace_rk45_rejected_stage_outside=0_8
268 integer(kind=8),
private :: trace_rk45_rejected_boundary=0_8
269 integer(kind=8),
private :: trace_rk45_boundary_limited=0_8
270 double precision,
private :: trace_rk45_sum_accepted_h=0.d0
271 double precision,
private :: trace_rk45_min_accepted_h=huge(one)
272 double precision,
private :: trace_rk45_max_accepted_h=0.d0
273 integer(kind=8),
private :: trace_rk45_tangent_error_samples=0_8
274 integer(kind=8),
private :: trace_rk45_tangent_would_reject=0_8
275 double precision,
private :: trace_rk45_sum_tangent_error_ratio=0.d0
276 double precision,
private :: trace_rk45_max_tangent_error_ratio=0.d0
277 double precision,
private :: trace_rk45_max_tangent_u_error_ratio=0.d0
278 double precision,
private :: trace_rk45_max_tangent_v_error_ratio=0.d0
279 double precision,
private :: trace_rk45_max_position_error_ratio=0.d0
281 logical,
private :: trace_spherical_profile_enabled=.false.
282 logical,
parameter,
private :: trace_spherical_profile_timers=.false.
283 integer(kind=8),
private :: trace_profile_seeds=0_8
284 integer(kind=8),
private :: trace_profile_directions=0_8
285 integer(kind=8),
private :: trace_profile_steps=0_8
286 integer(kind=8),
private :: trace_profile_boundary_events=0_8
287 integer(kind=8),
private :: trace_profile_endpoint_finalizations=0_8
288 integer(kind=8),
private :: trace_profile_context_requests=0_8
289 integer(kind=8),
private :: trace_profile_same_cell_hits=0_8
290 integer(kind=8),
private :: trace_profile_same_grid_hits=0_8
291 integer(kind=8),
private :: trace_profile_full_context_builds=0_8
292 integer(kind=8),
private :: trace_profile_context_failures=0_8
293 integer(kind=8),
private :: trace_profile_cache_invalidations=0_8
294 integer(kind=8),
private :: trace_profile_b_samples=0_8
295 integer(kind=8),
private :: trace_profile_curl_samples=0_8
296 integer(kind=8),
private :: trace_profile_grad_samples=0_8
297 integer(kind=8),
private :: trace_profile_grad_success=0_8
298 integer(kind=8),
private :: trace_profile_grad_fallbacks=0_8
299 integer(kind=8),
private :: trace_profile_b_corner_loads=0_8
300 integer(kind=8),
private :: trace_profile_b_corner_hits=0_8
301 integer(kind=8),
private :: trace_profile_hlocal_evals=0_8
302 integer(kind=8),
private :: trace_profile_face_probes=0_8
303 integer(kind=8),
private :: trace_profile_tangent_systems=0_8
304 integer(kind=8),
private :: trace_profile_q_tangent_systems=0_8
305 integer(kind=8),
private :: trace_profile_qperp_tangent_systems=0_8
306 integer(kind=8),
private :: trace_profile_combined_tangent_systems=0_8
307 integer(kind=8),
private :: trace_profile_max_steps_per_trace=0_8
308 double precision,
private :: trace_profile_time_context=0.d0
309 double precision,
private :: trace_profile_time_b_interp=0.d0
310 double precision,
private :: trace_profile_time_curl_interp=0.d0
311 double precision,
private :: trace_profile_time_grad_bhat=0.d0
312 double precision,
private :: trace_profile_time_step=0.d0
313 double precision,
private :: trace_profile_time_tangent=0.d0
315 type,
private :: trace_summary_state
316 double precision :: x(
ndim)
317 double precision :: footpoint(
ndim)
318 double precision :: length
319 double precision :: twist
322 integer :: twist_status
328 logical :: accumulate_twist
329 double precision :: rk45_h
330 type(trace_sph_interp_ctx) :: sph_cache
331 end type trace_summary_state
333 type,
private :: trace_tangent_state
339 double precision :: x(
ndim)
340 double precision :: u(
ndim)
341 double precision :: v(
ndim)
342 double precision :: p(
ndim)
343 double precision :: q(
ndim)
344 double precision :: length
345 double precision :: twist
349 integer :: twist_status
351 double precision :: endpoint(
ndim)
352 double precision :: endpoint_b(
ndim)
353 double precision :: endpoint_bhat(
ndim)
354 double precision :: u_perp(
ndim)
355 double precision :: v_perp(
ndim)
356 double precision :: p_perp(
ndim)
357 double precision :: q_perp(
ndim)
358 double precision :: rk45_h
359 logical :: accumulate_twist
360 type(trace_sph_interp_ctx) :: sph_cache
361 end type trace_tangent_state
365 double precision :: forward_footpoint(
ndim)
366 double precision :: backward_footpoint(
ndim)
367 double precision :: forward_length
368 double precision :: backward_length
369 double precision :: total_length
370 integer :: forward_nstep
371 integer :: backward_nstep
372 integer :: forward_status
373 integer :: backward_status
378 double precision :: forward_twist
379 double precision :: backward_twist
380 double precision :: total_twist
381 logical :: valid_twist
382 integer :: status_twist
387 double precision :: source_b(3)
388 double precision :: forward_footpoint(
ndim)
389 double precision :: backward_footpoint(
ndim)
390 double precision :: forward_b(3)
391 double precision :: backward_b(3)
392 double precision :: forward_length
393 double precision :: backward_length
394 double precision :: source_bn
395 double precision :: forward_bn
396 double precision :: backward_bn
397 integer :: forward_face
398 integer :: backward_face
399 integer :: forward_status
400 integer :: backward_status
406 double precision :: qperp
407 double precision :: logqperp
408 double precision :: n2
409 double precision :: bfactor
410 double precision :: q0
411 double precision :: logq0
412 double precision :: qperp0
413 double precision :: logqperp0
414 double precision :: n2_qperp0
415 double precision :: bfactor_qperp0
416 double precision :: forward_bn_q0
417 double precision :: backward_bn_q0
418 double precision :: b_seed(
ndim)
419 double precision :: bhat_seed(
ndim)
420 double precision :: forward_endpoint(
ndim)
421 double precision :: backward_endpoint(
ndim)
422 double precision :: forward_b(
ndim)
423 double precision :: backward_b(
ndim)
424 double precision :: forward_bhat(
ndim)
425 double precision :: backward_bhat(
ndim)
426 double precision :: forward_length
427 double precision :: backward_length
428 integer :: forward_nstep
429 integer :: backward_nstep
432 double precision :: u_forward_perp(
ndim)
433 double precision :: v_forward_perp(
ndim)
434 double precision :: u_backward_perp(
ndim)
435 double precision :: v_backward_perp(
ndim)
436 integer :: forward_face
437 integer :: backward_face
438 integer :: forward_status
439 integer :: backward_status
441 integer :: status_qperp0
445 logical :: valid_qperp0
450 double precision :: length_forward
451 double precision :: length_backward
452 double precision :: length_total
453 double precision :: twist_forward
454 double precision :: twist_backward
455 double precision :: twist_total
456 double precision :: forward_endpoint(
ndim)
457 double precision :: backward_endpoint(
ndim)
458 integer :: forward_nstep
459 integer :: backward_nstep
460 integer :: forward_face
461 integer :: backward_face
462 integer :: forward_status
463 integer :: backward_status
464 double precision :: map_forward_endpoint(
ndim)
465 double precision :: map_backward_endpoint(
ndim)
466 double precision :: map_forward_length
467 double precision :: map_backward_length
468 integer :: map_forward_face
469 integer :: map_backward_face
470 integer :: map_forward_status
471 integer :: map_backward_status
472 double precision :: source_b(3)
473 double precision :: forward_b(3)
474 double precision :: backward_b(3)
475 double precision :: source_bn
476 double precision :: forward_bn
477 double precision :: backward_bn
479 logical :: has_mapping
480 logical :: valid_twist
482 integer :: status_twist
489 character(len=*),
intent(in) :: mode
490 double precision,
intent(in) :: step_fraction,step_min
492 character(len=len(mode)) :: mode_lc
497 code=iachar(mode_lc(i:i))
498 if (code>=iachar(
'A') .and. code<=iachar(
'Z'))
then
499 mode_lc(i:i)=achar(code+iachar(
'a')-iachar(
'A'))
503 select case (trim(mode_lc))
504 case (
'cell_fraction')
505 trace_step_control_mode=trace_step_control_cell_fraction
507 trace_step_control_mode=trace_step_control_fixed
509 trace_step_fraction=step_fraction
510 trace_step_min=max(zero,step_min)
514 max_grow,tangent_floor,tangent_rtol)
515 character(len=*),
intent(in) :: mode
516 double precision,
intent(in) :: atol,rtol,safety,min_shrink,max_grow
517 double precision,
intent(in) :: tangent_floor,tangent_rtol
519 character(len=len(mode)) :: mode_lc
524 code=iachar(mode_lc(i:i))
525 if (code>=iachar(
'A') .and. code<=iachar(
'Z'))
then
526 mode_lc(i:i)=achar(code+iachar(
'a')-iachar(
'A'))
530 select case (trim(mode_lc))
531 case (
'rk45_cartesian')
532 trace_integrator_mode=trace_integrator_rk45_cartesian
533 case (
'rk45_spherical')
534 trace_integrator_mode=trace_integrator_rk45_spherical
536 trace_integrator_mode=trace_integrator_rk2
538 trace_rk45_atol=max(atol,zero)
539 trace_rk45_rtol=max(rtol,zero)
540 trace_rk45_safety=max(0.1d0,min(safety,one))
541 trace_rk45_min_shrink=max(0.01d0,min(min_shrink,one))
542 trace_rk45_max_grow=max(one,max_grow)
543 trace_rk45_tangent_floor=max(tangent_floor,smalldouble)
544 trace_rk45_tangent_rtol=max(tangent_rtol,smalldouble)
548 logical,
intent(in) :: enabled
550 trace_rk2_stats_enabled=enabled
554 trace_rk2_directions=0_8
555 trace_rk2_completed_directions=0_8
556 trace_rk2_total_steps=0_8
557 trace_rk2_boundary_completions=0_8
558 trace_rk2_max_steps_failures=0_8
559 trace_rk2_domain_limited_steps=0_8
560 trace_rk2_grid_transition_steps=0_8
561 trace_rk2_cell_fraction_limited=0_8
562 trace_rk2_dl_limited=0_8
563 trace_rk2_dl_min_limited=0_8
564 trace_rk2_group_iterations=0_8
565 trace_rk2_grid_groups=0_8
566 trace_rk2_group_state_sum=0_8
567 trace_rk2_group_state_max=0_8
568 trace_rk2_rhs_calls=0_8
569 trace_rk2_sum_step_length=0.d0
570 trace_rk2_min_step_length=huge(one)
571 trace_rk2_max_step_length=0.d0
572 trace_rk2_grouped_time=0.d0
573 trace_rk2_max_steps_per_direction=0_8
577 character(len=*),
intent(in) :: label
579 double precision :: mean_group_size,mean_h,mean_steps_per_direction
581 if (.not.trace_rk2_stats_enabled)
return
584 if (trace_rk2_total_steps>0_8)
then
585 mean_h=trace_rk2_sum_step_length/dble(trace_rk2_total_steps)
587 mean_steps_per_direction=zero
588 if (trace_rk2_completed_directions>0_8)
then
589 mean_steps_per_direction=dble(trace_rk2_total_steps)/ &
590 dble(trace_rk2_completed_directions)
593 if (trace_rk2_grid_groups>0_8)
then
594 mean_group_size=dble(trace_rk2_group_state_sum)/ &
595 dble(trace_rk2_grid_groups)
598 write(*,
'(a)')
'[mt_rk2] Cartesian field-line RK2 summary: '// &
600 write(*,
'(a,i0)')
' traced_directions: ',trace_rk2_directions
601 write(*,
'(a,i0)')
' completed_directions: ', &
602 trace_rk2_completed_directions
603 write(*,
'(a,i0)')
' total_steps: ',trace_rk2_total_steps
604 write(*,
'(a,es12.4)')
' mean_step_length: ',mean_h
605 if (trace_rk2_total_steps>0_8)
then
606 write(*,
'(a,es12.4)')
' min_step_length: ', &
607 trace_rk2_min_step_length
608 write(*,
'(a,es12.4)')
' max_step_length: ', &
609 trace_rk2_max_step_length
611 write(*,
'(a,es12.4)')
' mean_steps_per_direction: ', &
612 mean_steps_per_direction
613 write(*,
'(a,i0)')
' max_steps_per_direction: ', &
614 trace_rk2_max_steps_per_direction
615 write(*,
'(a,i0)')
' boundary_completions: ', &
616 trace_rk2_boundary_completions
617 write(*,
'(a,i0)')
' max_steps_failures: ', &
618 trace_rk2_max_steps_failures
619 write(*,
'(a,i0)')
' domain_boundary_limited_steps: ', &
620 trace_rk2_domain_limited_steps
621 write(*,
'(a,i0)')
' block_grid_clipped_steps: 0'
622 write(*,
'(a,i0)')
' grid_transition_steps: ', &
623 trace_rk2_grid_transition_steps
624 write(*,
'(a,i0)')
' cell_fraction_limited_evals: ', &
625 trace_rk2_cell_fraction_limited
626 write(*,
'(a,i0)')
' dL_cap_limited_evals: ',trace_rk2_dl_limited
627 write(*,
'(a,i0)')
' dL_min_limited_evals: ',trace_rk2_dl_min_limited
628 write(*,
'(a,i0)')
' grouped_driver_outer_iterations: ', &
629 trace_rk2_group_iterations
630 write(*,
'(a,i0)')
' grouped_driver_parallel_batches: ', &
631 trace_rk2_grid_groups
632 write(*,
'(a,es12.4)')
' grouped_driver_mean_batch_size: ', &
634 write(*,
'(a,i0)')
' grouped_driver_max_batch_size: ', &
635 trace_rk2_group_state_max
636 write(*,
'(a,es12.4)')
' grouped_driver_cpu_time: ', &
637 trace_rk2_grouped_time
638 write(*,
'(a,i0)')
' trace_tangent_rhs_calls: ',trace_rk2_rhs_calls
639 write(*,
'(a)')
' note: Cartesian RK2 grouped tracing does not clip '// &
640 'steps to AMR block/grid boundaries; grid changes are counted after '// &
641 'accepted full steps.'
644 subroutine trace_rk2_stats_note_direction()
645 if (.not.trace_rk2_stats_enabled)
return
647 trace_rk2_directions=trace_rk2_directions+1_8
649 end subroutine trace_rk2_stats_note_direction
651 subroutine trace_rk2_stats_note_step(h,domain_limited,grid_transition)
652 double precision,
intent(in) :: h
653 logical,
intent(in) :: domain_limited,grid_transition
655 if (.not.trace_rk2_stats_enabled)
return
657 trace_rk2_total_steps=trace_rk2_total_steps+1_8
658 trace_rk2_sum_step_length=trace_rk2_sum_step_length+abs(h)
659 trace_rk2_min_step_length=min(trace_rk2_min_step_length,abs(h))
660 trace_rk2_max_step_length=max(trace_rk2_max_step_length,abs(h))
661 if (domain_limited) trace_rk2_domain_limited_steps= &
662 trace_rk2_domain_limited_steps+1_8
663 if (grid_transition) trace_rk2_grid_transition_steps= &
664 trace_rk2_grid_transition_steps+1_8
666 end subroutine trace_rk2_stats_note_step
668 subroutine trace_rk2_stats_note_completion(status,nstep)
669 integer,
intent(in) :: status,
nstep
671 if (.not.trace_rk2_stats_enabled)
return
673 trace_rk2_completed_directions=trace_rk2_completed_directions+1_8
674 trace_rk2_max_steps_per_direction=max( &
675 trace_rk2_max_steps_per_direction,int(
nstep,kind=8))
678 trace_rk2_boundary_completions=trace_rk2_boundary_completions+1_8
680 trace_rk2_max_steps_failures=trace_rk2_max_steps_failures+1_8
683 end subroutine trace_rk2_stats_note_completion
685 subroutine trace_rk2_stats_note_step_limit(step_cap,cell_step,actual_step)
686 double precision,
intent(in) :: step_cap,cell_step,actual_step
688 double precision :: tol
690 if (.not.trace_rk2_stats_enabled)
return
691 tol=100.d0*epsilon(one)*max(one,step_cap,cell_step,actual_step)
693 if (actual_step>=step_cap-tol)
then
694 trace_rk2_dl_limited=trace_rk2_dl_limited+1_8
695 else if (trace_step_min>zero .and. actual_step>=trace_step_min-tol .and. &
696 actual_step>cell_step+tol)
then
697 trace_rk2_dl_min_limited=trace_rk2_dl_min_limited+1_8
699 trace_rk2_cell_fraction_limited=trace_rk2_cell_fraction_limited+1_8
702 end subroutine trace_rk2_stats_note_step_limit
704 subroutine trace_rk2_stats_note_group_iteration()
705 if (.not.trace_rk2_stats_enabled)
return
707 trace_rk2_group_iterations=trace_rk2_group_iterations+1_8
709 end subroutine trace_rk2_stats_note_group_iteration
711 subroutine trace_rk2_stats_note_grid_group(group_size)
712 integer,
intent(in) :: group_size
714 if (.not.trace_rk2_stats_enabled)
return
716 trace_rk2_grid_groups=trace_rk2_grid_groups+1_8
717 trace_rk2_group_state_sum=trace_rk2_group_state_sum+ &
718 int(group_size,kind=8)
719 trace_rk2_group_state_max=max(trace_rk2_group_state_max, &
720 int(group_size,kind=8))
722 end subroutine trace_rk2_stats_note_grid_group
724 subroutine trace_rk2_stats_note_rhs()
725 if (.not.trace_rk2_stats_enabled)
return
727 trace_rk2_rhs_calls=trace_rk2_rhs_calls+1_8
728 end subroutine trace_rk2_stats_note_rhs
730 subroutine trace_rk2_stats_add_grouped_time(dt)
731 double precision,
intent(in) ::
dt
733 if (.not.trace_rk2_stats_enabled)
return
735 trace_rk2_grouped_time=trace_rk2_grouped_time+
dt
737 end subroutine trace_rk2_stats_add_grouped_time
740 logical,
intent(in) :: enabled
742 trace_rk45_stats_enabled=enabled
746 trace_rk45_directions=0_8
747 trace_rk45_attempts=0_8
748 trace_rk45_accepted=0_8
749 trace_rk45_rejected=0_8
750 trace_rk45_rejected_error=0_8
751 trace_rk45_rejected_position_error=0_8
752 trace_rk45_rejected_tangent_error=0_8
753 trace_rk45_rejected_stage_failure=0_8
754 trace_rk45_rejected_stage_outside=0_8
755 trace_rk45_rejected_boundary=0_8
756 trace_rk45_boundary_limited=0_8
757 trace_rk45_sum_accepted_h=0.d0
758 trace_rk45_min_accepted_h=huge(one)
759 trace_rk45_max_accepted_h=0.d0
760 trace_rk45_tangent_error_samples=0_8
761 trace_rk45_tangent_would_reject=0_8
762 trace_rk45_sum_tangent_error_ratio=0.d0
763 trace_rk45_max_tangent_error_ratio=0.d0
764 trace_rk45_max_tangent_u_error_ratio=0.d0
765 trace_rk45_max_tangent_v_error_ratio=0.d0
766 trace_rk45_max_position_error_ratio=0.d0
770 character(len=*),
intent(in) :: label
772 double precision :: mean_h,mean_reject_per_trace,mean_tangent_error
774 if (.not.trace_rk45_stats_enabled)
return
775 if (trace_integrator_mode/=trace_integrator_rk45_cartesian .and. &
776 trace_integrator_mode/=trace_integrator_rk45_spherical)
return
779 if (trace_rk45_accepted>0_8)
then
780 mean_h=trace_rk45_sum_accepted_h/dble(trace_rk45_accepted)
782 mean_reject_per_trace=zero
783 if (trace_rk45_directions>0_8)
then
784 mean_reject_per_trace=dble(trace_rk45_rejected)/dble(trace_rk45_directions)
787 select case (trace_integrator_mode)
788 case (trace_integrator_rk45_cartesian)
789 write(*,
'(a)')
'[mt_rk45] Cartesian field-line RK45 summary: '// &
791 case (trace_integrator_rk45_spherical)
792 write(*,
'(a)')
'[mt_rk45] Spherical field-line RK45 summary: '// &
795 write(*,
'(a,i0)')
' traced_directions: ',trace_rk45_directions
796 write(*,
'(a,i0)')
' attempts: ',trace_rk45_attempts
797 write(*,
'(a,i0)')
' accepted_steps: ',trace_rk45_accepted
798 write(*,
'(a,i0)')
' rejected_steps: ',trace_rk45_rejected
799 write(*,
'(a,i0)')
' rejected_error_steps: ', &
800 trace_rk45_rejected_error
801 write(*,
'(a,i0)')
' rejected_position_error_steps: ', &
802 trace_rk45_rejected_position_error
803 write(*,
'(a,i0)')
' rejected_tangent_error_steps: ', &
804 trace_rk45_rejected_tangent_error
805 write(*,
'(a,i0)')
' rejected_stage_failure_steps: ', &
806 trace_rk45_rejected_stage_failure
807 write(*,
'(a,i0)')
' rejected_stage_outside_steps: ', &
808 trace_rk45_rejected_stage_outside
809 write(*,
'(a,i0)')
' rejected_boundary_steps: ', &
810 trace_rk45_rejected_boundary
811 write(*,
'(a,es12.4)')
' rejected_steps_per_direction: ', &
812 mean_reject_per_trace
813 write(*,
'(a,i0)')
' boundary_limited_steps: ', &
814 trace_rk45_boundary_limited
815 write(*,
'(a,es12.4)')
' mean_accepted_step: ',mean_h
816 if (trace_rk45_accepted>0_8)
then
817 write(*,
'(a,es12.4)')
' min_accepted_step: ', &
818 trace_rk45_min_accepted_h
819 write(*,
'(a,es12.4)')
' max_accepted_step: ', &
820 trace_rk45_max_accepted_h
822 if (trace_rk45_tangent_error_samples>0_8)
then
823 write(*,
'(a)')
' error_control_mode: position_tangent'
824 mean_tangent_error=trace_rk45_sum_tangent_error_ratio/ &
825 dble(trace_rk45_tangent_error_samples)
826 write(*,
'(a,i0)')
' tangent_error_samples: ', &
827 trace_rk45_tangent_error_samples
828 write(*,
'(a,i0)')
' tangent_would_reject_steps: ', &
829 trace_rk45_tangent_would_reject
830 write(*,
'(a,es12.4)')
' max_position_error_ratio: ', &
831 trace_rk45_max_position_error_ratio
832 write(*,
'(a,es12.4)')
' mean_tangent_error_ratio: ', &
834 write(*,
'(a,es12.4)')
' max_tangent_error_ratio: ', &
835 trace_rk45_max_tangent_error_ratio
836 write(*,
'(a,es12.4)')
' max_tangent_u_error_ratio: ', &
837 trace_rk45_max_tangent_u_error_ratio
838 write(*,
'(a,es12.4)')
' max_tangent_v_error_ratio: ', &
839 trace_rk45_max_tangent_v_error_ratio
840 write(*,
'(a,es12.4)')
' tangent_error_rtol: ', &
841 trace_rk45_tangent_rtol
842 write(*,
'(a,es12.4)')
' tangent_error_floor: ', &
843 trace_rk45_tangent_floor
844 write(*,
'(a)')
' tangent_error_note: standard-logQ tangent '// &
845 'traces use position+tangent RK45 accept/reject.'
847 write(*,
'(a)')
' error_control_mode: position'
849 write(*,
'(a)')
' note: this experimental RK45 mode traces '// &
850 'position/length/twist and tangent-transport Q products where enabled.'
853 subroutine trace_rk45_stats_note_direction()
854 if (.not.trace_rk45_stats_enabled)
return
855 if (trace_integrator_mode/=trace_integrator_rk45_cartesian .and. &
856 trace_integrator_mode/=trace_integrator_rk45_spherical)
return
858 trace_rk45_directions=trace_rk45_directions+1_8
860 end subroutine trace_rk45_stats_note_direction
862 subroutine trace_rk45_stats_note_attempt(accepted,boundary_limited,h, &
864 logical,
intent(in) :: accepted,boundary_limited
865 double precision,
intent(in) :: h
866 integer,
intent(in),
optional :: reject_reason
868 if (.not.trace_rk45_stats_enabled)
return
869 if (trace_integrator_mode/=trace_integrator_rk45_cartesian .and. &
870 trace_integrator_mode/=trace_integrator_rk45_spherical)
return
872 trace_rk45_attempts=trace_rk45_attempts+1_8
874 trace_rk45_accepted=trace_rk45_accepted+1_8
875 trace_rk45_sum_accepted_h=trace_rk45_sum_accepted_h+abs(h)
876 trace_rk45_min_accepted_h=min(trace_rk45_min_accepted_h,abs(h))
877 trace_rk45_max_accepted_h=max(trace_rk45_max_accepted_h,abs(h))
878 if (boundary_limited) trace_rk45_boundary_limited= &
879 trace_rk45_boundary_limited+1_8
881 trace_rk45_rejected=trace_rk45_rejected+1_8
882 if (
present(reject_reason))
then
883 select case (reject_reason)
884 case (trace_rk45_reject_error)
885 trace_rk45_rejected_error=trace_rk45_rejected_error+1_8
886 trace_rk45_rejected_position_error= &
887 trace_rk45_rejected_position_error+1_8
888 case (trace_rk45_reject_tangent_error)
889 trace_rk45_rejected_error=trace_rk45_rejected_error+1_8
890 trace_rk45_rejected_tangent_error= &
891 trace_rk45_rejected_tangent_error+1_8
892 case (trace_rk45_reject_stage_failure)
893 trace_rk45_rejected_stage_failure= &
894 trace_rk45_rejected_stage_failure+1_8
895 case (trace_rk45_reject_stage_outside)
896 trace_rk45_rejected_stage_outside= &
897 trace_rk45_rejected_stage_outside+1_8
898 case (trace_rk45_reject_boundary)
899 trace_rk45_rejected_boundary=trace_rk45_rejected_boundary+1_8
904 end subroutine trace_rk45_stats_note_attempt
906 subroutine trace_rk45_stats_note_tangent_error(position_error_ratio, &
907 u_error_ratio,v_error_ratio)
908 double precision,
intent(in) :: position_error_ratio
909 double precision,
intent(in) :: u_error_ratio,v_error_ratio
911 double precision :: tangent_error_ratio
913 if (.not.trace_rk45_stats_enabled)
return
914 if (trace_integrator_mode/=trace_integrator_rk45_cartesian .and. &
915 trace_integrator_mode/=trace_integrator_rk45_spherical)
return
916 tangent_error_ratio=max(u_error_ratio,v_error_ratio)
918 trace_rk45_tangent_error_samples= &
919 trace_rk45_tangent_error_samples+1_8
920 trace_rk45_sum_tangent_error_ratio= &
921 trace_rk45_sum_tangent_error_ratio+tangent_error_ratio
922 trace_rk45_max_tangent_error_ratio= &
923 max(trace_rk45_max_tangent_error_ratio,tangent_error_ratio)
924 trace_rk45_max_tangent_u_error_ratio= &
925 max(trace_rk45_max_tangent_u_error_ratio,u_error_ratio)
926 trace_rk45_max_tangent_v_error_ratio= &
927 max(trace_rk45_max_tangent_v_error_ratio,v_error_ratio)
928 trace_rk45_max_position_error_ratio= &
929 max(trace_rk45_max_position_error_ratio,position_error_ratio)
930 if (tangent_error_ratio>trace_rk45_tangent_rtol) &
931 trace_rk45_tangent_would_reject= &
932 trace_rk45_tangent_would_reject+1_8
934 end subroutine trace_rk45_stats_note_tangent_error
937 logical,
intent(in) :: enabled
939 trace_spherical_profile_enabled=enabled
943 trace_profile_seeds=0_8
944 trace_profile_directions=0_8
945 trace_profile_steps=0_8
946 trace_profile_boundary_events=0_8
947 trace_profile_endpoint_finalizations=0_8
948 trace_profile_context_requests=0_8
949 trace_profile_same_cell_hits=0_8
950 trace_profile_same_grid_hits=0_8
951 trace_profile_full_context_builds=0_8
952 trace_profile_context_failures=0_8
953 trace_profile_cache_invalidations=0_8
954 trace_profile_b_samples=0_8
955 trace_profile_curl_samples=0_8
956 trace_profile_grad_samples=0_8
957 trace_profile_grad_success=0_8
958 trace_profile_grad_fallbacks=0_8
959 trace_profile_b_corner_loads=0_8
960 trace_profile_b_corner_hits=0_8
961 trace_profile_hlocal_evals=0_8
962 trace_profile_face_probes=0_8
963 trace_profile_tangent_systems=0_8
964 trace_profile_q_tangent_systems=0_8
965 trace_profile_qperp_tangent_systems=0_8
966 trace_profile_combined_tangent_systems=0_8
967 trace_profile_max_steps_per_trace=0_8
968 trace_profile_time_context=0.d0
969 trace_profile_time_b_interp=0.d0
970 trace_profile_time_curl_interp=0.d0
971 trace_profile_time_grad_bhat=0.d0
972 trace_profile_time_step=0.d0
973 trace_profile_time_tangent=0.d0
977 integer,
intent(in) :: nseed
979 if (.not.trace_spherical_profile_enabled)
return
980 call trace_spherical_profile_add_count(trace_profile_seeds, &
981 int(max(nseed,0),kind=8))
985 character(len=*),
intent(in) :: label
987 double precision :: avg_steps,denom,hit_denom
989 if (.not.trace_spherical_profile_enabled)
return
992 denom=max(one,dble(trace_profile_directions))
993 avg_steps=dble(trace_profile_steps)/denom
994 hit_denom=max(one,dble(trace_profile_context_requests))
996 write(*,
'(a)')
'[mt_profile] spherical topology profiling summary '// &
998 write(*,
'(a,i0)')
' seeds: ',trace_profile_seeds
999 write(*,
'(a,i0)')
' traced_directions: ',trace_profile_directions
1000 write(*,
'(a,i0)')
' accepted_steps_all_integrators: ', &
1002 write(*,
'(a,es12.4)')
' avg_steps_per_counted_trace: ',avg_steps
1003 write(*,
'(a,i0)')
' max_steps_per_trace: ', &
1004 trace_profile_max_steps_per_trace
1005 write(*,
'(a)')
' note: accepted steps include counted spherical '// &
1006 'summary and tangent integrations; shared Q/Qperp tangent '// &
1007 'transport is counted once.'
1008 write(*,
'(a)')
' note: profiling counters are diagnostic and may '// &
1009 'significantly slow hot loops; do not use profiling-on wall time '// &
1010 'as production timing.'
1011 write(*,
'(a,i0)')
' boundary_events: ',trace_profile_boundary_events
1012 write(*,
'(a,i0)')
' endpoint_finalizations: ', &
1013 trace_profile_endpoint_finalizations
1014 write(*,
'(a,i0)')
' context_requests: ',trace_profile_context_requests
1015 write(*,
'(a,i0,a,f6.2,a)')
' same_cell_hits: ', &
1016 trace_profile_same_cell_hits,
' (', &
1017 100.d0*dble(trace_profile_same_cell_hits)/hit_denom,
'%)'
1018 write(*,
'(a,i0,a,f6.2,a)')
' same_grid_hits: ', &
1019 trace_profile_same_grid_hits,
' (', &
1020 100.d0*dble(trace_profile_same_grid_hits)/hit_denom,
'%)'
1021 write(*,
'(a,i0,a,f6.2,a)')
' full_context_builds: ', &
1022 trace_profile_full_context_builds,
' (', &
1023 100.d0*dble(trace_profile_full_context_builds)/hit_denom,
'%)'
1024 write(*,
'(a,i0)')
' context_failures: ',trace_profile_context_failures
1025 write(*,
'(a,i0)')
' cache_invalidations: ', &
1026 trace_profile_cache_invalidations
1027 write(*,
'(a,i0)')
' B_samples: ',trace_profile_b_samples
1028 write(*,
'(a,i0)')
' curl_samples: ',trace_profile_curl_samples
1029 write(*,
'(a,i0)')
' grad_bhat_samples: ',trace_profile_grad_samples
1030 write(*,
'(a,i0)')
' grad_bhat_success: ',trace_profile_grad_success
1031 write(*,
'(a,i0)')
' grad_bhat_fallbacks: ', &
1032 trace_profile_grad_fallbacks
1033 write(*,
'(a,i0)')
' B_corner_loads: ',trace_profile_b_corner_loads
1034 write(*,
'(a,i0)')
' B_corner_cache_hits: ', &
1035 trace_profile_b_corner_hits
1036 write(*,
'(a,i0)')
' h_local_evals: ',trace_profile_hlocal_evals
1037 write(*,
'(a,i0)')
' boundary_face_probes: ', &
1038 trace_profile_face_probes
1039 write(*,
'(a,i0)')
' tangent_systems: ', &
1040 trace_profile_tangent_systems
1041 write(*,
'(a,i0)')
' q_tangent_systems: ', &
1042 trace_profile_q_tangent_systems
1043 write(*,
'(a,i0)')
' qperp_tangent_systems: ', &
1044 trace_profile_qperp_tangent_systems
1045 write(*,
'(a,i0)')
' combined_q_qperp_tangent_systems: ', &
1046 trace_profile_combined_tangent_systems
1047 write(*,
'(a)')
' timing_cpu_seconds:'
1048 if (.not.trace_spherical_profile_timers)
then
1049 write(*,
'(a)')
' disabled (hot-loop timers distort profiling runs)'
1052 write(*,
'(a,es12.4)')
' context: ',trace_profile_time_context
1053 write(*,
'(a,es12.4)')
' B_interp: ',trace_profile_time_b_interp
1054 write(*,
'(a,es12.4)')
' curl_interp: ', &
1055 trace_profile_time_curl_interp
1056 write(*,
'(a,es12.4)')
' grad_bhat: ',trace_profile_time_grad_bhat
1057 write(*,
'(a,es12.4)')
' step_size: ',trace_profile_time_step
1058 write(*,
'(a,es12.4)')
' tangent_transport: ', &
1059 trace_profile_time_tangent
1062 subroutine trace_spherical_profile_add_count(counter,delta)
1063 integer(kind=8),
intent(inout) :: counter
1064 integer(kind=8),
intent(in) :: delta
1066 if (.not.trace_spherical_profile_enabled)
return
1068 counter=counter+delta
1069 end subroutine trace_spherical_profile_add_count
1071 subroutine trace_spherical_profile_add_time(timer,dt)
1072 double precision,
intent(inout) :: timer
1073 double precision,
intent(in) ::
dt
1075 if (.not.trace_spherical_profile_enabled)
return
1076 if (.not.trace_spherical_profile_timers)
return
1079 end subroutine trace_spherical_profile_add_time
1081 subroutine trace_spherical_profile_note_trace_steps(nstep)
1082 integer,
intent(in) ::
nstep
1084 if (.not.trace_spherical_profile_enabled)
return
1086 trace_profile_max_steps_per_trace=max(trace_profile_max_steps_per_trace, &
1089 end subroutine trace_spherical_profile_note_trace_steps
1091 double precision function trace_spherical_profile_time()
result(tnow)
1092 if (.not.trace_spherical_profile_timers)
then
1097 end function trace_spherical_profile_time
1100 integer,
intent(out) :: status
1102 double precision :: bvec(ixg^t,1:3)
1103 integer :: iigrid,igrid,idirmin
1104 integer :: ixi^
l,ixo^
l,ixa^
l
1109 if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
then
1113 if (.not.
b0field .and. .not.
allocated(iw_mag))
then
1119 allocate(trace_spherical_curl_cache(
max_blocks))
1123 if (iximin1>ixamin1 .or. iximax1<ixamax1 .or. &
1124 iximin2>ixamin2 .or. iximax2<ixamax2 .or. &
1125 iximin3>ixamin3 .or. iximax3<ixamax3)
then
1133 allocate(trace_spherical_curl_cache(igrid)%current( &
1134 lbound(ps(igrid)%w,1):ubound(ps(igrid)%w,1), &
1135 lbound(ps(igrid)%w,2):ubound(ps(igrid)%w,2), &
1136 lbound(ps(igrid)%w,3):ubound(ps(igrid)%w,3),1:3))
1137 trace_spherical_curl_cache(igrid)%current=zero
1139 if (
allocated(iw_mag))
then
1140 bvec(:,:,:,1)=ps(igrid)%w(:,:,:,iw_mag(1))
1141 bvec(:,:,:,2)=ps(igrid)%w(:,:,:,iw_mag(2))
1142 bvec(:,:,:,3)=ps(igrid)%w(:,:,:,iw_mag(3))
1147 trace_spherical_curl_cache(igrid)%current,idirmin,1,3)
1149 trace_spherical_curl_cache(igrid)%current(ixo^s,1:3)= &
1150 trace_spherical_curl_cache(igrid)%current(ixo^s,1:3) &
1151 +ps(igrid)%J0(ixo^s,1:3)
1153 trace_spherical_curl_cache(igrid)%ready=.true.
1155 trace_spherical_curl_cache_ready=.true.
1162 if (
allocated(trace_spherical_curl_cache))
then
1163 do igrid=1,
size(trace_spherical_curl_cache)
1164 if (
allocated(trace_spherical_curl_cache(igrid)%current))
then
1165 deallocate(trace_spherical_curl_cache(igrid)%current)
1167 trace_spherical_curl_cache(igrid)%ready=.false.
1169 deallocate(trace_spherical_curl_cache)
1171 trace_spherical_curl_cache_ready=.false.
1177 double precision,
intent(in) :: seed(
ndim),dl
1178 integer,
intent(in) :: max_steps
1180 double precision,
intent(in),
optional :: b_min
1182 if (
present(b_min))
then
1183 call trace_summary_seed(seed,dl,max_steps,result,b_min)
1185 call trace_summary_seed(seed,dl,max_steps,result)
1191 double precision,
intent(in) :: seed(
ndim),dl
1192 integer,
intent(in) :: max_steps
1194 double precision,
intent(in),
optional :: b_min
1196 if (
present(b_min))
then
1197 call trace_summary_twist_seed(seed,dl,max_steps,result,b_min)
1199 call trace_summary_twist_seed(seed,dl,max_steps,result)
1206 double precision,
intent(in) :: seed(
ndim),dl
1207 integer,
intent(in) :: max_steps
1209 double precision,
intent(in),
optional :: b_min
1210 double precision,
intent(in),
optional :: source_normal(3)
1212 if (
present(b_min))
then
1213 if (
present(source_normal))
then
1214 call trace_summary_mapping_seed(seed,dl,max_steps,result,b_min, &
1217 call trace_summary_mapping_seed(seed,dl,max_steps,result,b_min)
1220 if (
present(source_normal))
then
1221 call trace_summary_mapping_seed(seed,dl,max_steps,result, &
1222 source_normal=source_normal)
1224 call trace_summary_mapping_seed(seed,dl,max_steps,result)
1231 double precision,
intent(in) :: seed(
ndim),dl
1232 integer,
intent(in) :: max_steps
1234 double precision,
intent(in),
optional :: b_min
1236 if (
present(b_min))
then
1237 call trace_qperp_single_core(seed,dl,max_steps,result,b_min)
1239 call trace_qperp_single_core(seed,dl,max_steps,result)
1245 double precision,
intent(in) :: seed(
ndim)
1246 double precision,
intent(out) :: bhat(3),grad_bhat(3,3)
1247 integer,
intent(out) :: status
1248 double precision,
intent(in),
optional :: b_min
1251 double precision :: field_min
1265 field_min=smalldouble
1266 if (
present(b_min)) field_min=max(b_min,zero)
1268 call trace_summary_locate_seed(seed,located,igrid)
1269 status=located%forward_status
1272 call sample_bhat_gradbhat_at_point(seed,igrid,field_min,bhat, &
1279 double precision,
intent(in) :: xhit(
ndim)
1280 integer,
intent(in) :: face_id
1281 double precision,
intent(out) :: b(
ndim),bhat(
ndim)
1282 integer,
intent(out) :: status
1283 double precision,
intent(in),
optional :: b_min
1285 double precision :: field_min,xprobe(
ndim),b3(3),bhat3(3)
1286 double precision :: xface,span
1287 integer :: normal_dim,side,igrid
1299 if (.not.trace_face_is_boundary(face_id))
then
1304 field_min=smalldouble
1305 if (
present(b_min)) field_min=max(b_min,zero)
1308 select case(face_id)
1338 span=max(abs(xprobmax1-xprobmin1), &
1339 max(abs(xprobmax2-xprobmin2),abs(xprobmax3-xprobmin3)))
1341 xprobe(normal_dim)=xface-side*1.
d-6*max(one,span)
1342 call trace_debug_locate_point(xprobe,igrid,status)
1345 call trace_sample_b_on_domain_face_limit(xhit,face_id,igrid,field_min, &
1355 grad_current,status_current,bhat_xeps,grad_xeps,status_xeps,b_min)
1357 double precision,
intent(in) :: seed(
ndim),eps
1358 double precision,
intent(out) :: bhat_current(3),grad_current(3,3)
1359 double precision,
intent(out) :: bhat_xeps(3),grad_xeps(3,3)
1360 integer,
intent(out) :: status_current,status_xeps
1361 double precision,
intent(in),
optional :: b_min
1364 double precision :: field_min
1383 field_min=smalldouble
1384 if (
present(b_min)) field_min=max(b_min,zero)
1386 call trace_summary_locate_seed(seed,located,igrid)
1387 status_current=located%forward_status
1389 call sample_bhat_gradbhat_at_point(seed,igrid,field_min, &
1390 bhat_current,grad_current,status_current)
1393 call sample_bhat_gradbhat_xeps_at_point(seed,eps,field_min,bhat_xeps, &
1394 grad_xeps,status_xeps)
1398 grad_current,status_current,bhat_xeps,grad_xeps,status_xeps, &
1399 bhat_interp,grad_interp,status_interp,b_min)
1401 double precision,
intent(in) :: seed(
ndim),eps
1402 double precision,
intent(out) :: bhat_current(3),grad_current(3,3)
1403 double precision,
intent(out) :: bhat_xeps(3),grad_xeps(3,3)
1404 double precision,
intent(out) :: bhat_interp(3),grad_interp(3,3)
1405 integer,
intent(out) :: status_current,status_xeps,status_interp
1406 double precision,
intent(in),
optional :: b_min
1409 double precision :: field_min
1433 field_min=smalldouble
1434 if (
present(b_min)) field_min=max(b_min,zero)
1436 call trace_summary_locate_seed(seed,located,igrid)
1437 status_current=located%forward_status
1438 status_interp=located%forward_status
1440 call sample_bhat_gradbhat_cellfd_at_point(seed,igrid,field_min, &
1441 bhat_current,grad_current,status_current)
1444 call sample_bhat_gradbhat_interpderiv_at_point(seed,igrid,field_min, &
1445 bhat_interp,grad_interp,status_interp)
1448 call sample_bhat_gradbhat_xeps_at_point(seed,eps,field_min,bhat_xeps, &
1449 grad_xeps,status_xeps)
1453 x_end,u_end,v_end,bhat_end,u_perp_end,v_perp_end,status,b_min)
1455 double precision,
intent(in) :: seed(
ndim),u0(
ndim),v0(
ndim),dl
1456 integer,
intent(in) ::
nstep
1457 logical,
intent(in) :: forward
1458 double precision,
intent(out) :: x_end(
ndim),u_end(
ndim),v_end(
ndim)
1459 double precision,
intent(out) :: bhat_end(
ndim)
1460 double precision,
intent(out) :: u_perp_end(
ndim),v_perp_end(
ndim)
1461 integer,
intent(out) :: status
1462 double precision,
intent(in),
optional :: b_min
1464 double precision :: field_min,h,bhat3(3),grad_end(3,3)
1465 integer :: igrid,
istep
1481 else if (dl<=zero .or.
nstep<0)
then
1486 field_min=smalldouble
1487 if (
present(b_min)) field_min=max(b_min,zero)
1489 if (.not.forward) h=-dl
1491 call trace_debug_locate_point(x_end,igrid,status)
1495 call trace_advance_tangent_state_rk2(x_end,u_end,v_end,igrid,h, &
1502 call sample_bhat_gradbhat_at_point(x_end,igrid,field_min,bhat3, &
1509 call trace_project_to_perp_bhat(u_end,bhat_end,u_perp_end)
1510 call trace_project_to_perp_bhat(v_end,bhat_end,v_perp_end)
1514 max_steps,forward,x_end,u_end,v_end,bhat_end,b_end,u_perp_end, &
1515 v_perp_end,u_face_end,v_face_end,length,face_id,status,b_min)
1517 double precision,
intent(in) :: seed(
ndim),u0(
ndim),v0(
ndim),dl
1518 integer,
intent(in) :: max_steps
1519 logical,
intent(in) :: forward
1520 double precision,
intent(out) :: x_end(
ndim),u_end(
ndim),v_end(
ndim)
1521 double precision,
intent(out) :: bhat_end(
ndim),b_end(
ndim)
1522 double precision,
intent(out) :: u_perp_end(
ndim),v_perp_end(
ndim)
1523 double precision,
intent(out) :: u_face_end(
ndim),v_face_end(
ndim)
1524 double precision,
intent(out) :: length
1525 integer,
intent(out) :: face_id,status
1526 double precision,
intent(in),
optional :: b_min
1528 double precision :: field_min,h,h_partial,partial_length
1532 integer :: igrid,igrid_trial,
istep,point_domain
1554 else if (dl<=zero .or. max_steps<0)
then
1559 field_min=smalldouble
1560 if (
present(b_min)) field_min=max(b_min,zero)
1562 if (.not.forward) h=-dl
1564 call trace_debug_locate_point(x_end,igrid,status)
1567 do istep=1,max_steps
1572 call trace_tangent_rhs(xold,uold,vold,igrid,field_min,kx1,ku1,kv1, &
1578 {
if (xprobe(^db)>=xprobmin^db .and. xprobe(^db)<xprobmax^db) point_domain=point_domain+1\}
1579 if (point_domain/=
ndim)
then
1580 call trace_intersect_domain(xold,xprobe,xhit,hit_ok,face_id)
1581 if (.not.hit_ok)
then
1582 call trace_boundary_face_at_point(xold,face_id,hit_ok)
1583 if (.not.hit_ok)
then
1594 partial_length=dsqrt(sum((xhit-xold)**2))
1595 if (partial_length<=100.d0*epsilon(one)*max(one,abs(h)))
then
1602 h_partial=sign(partial_length,h)
1603 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold,igrid, &
1604 h_partial,field_min,kx1,ku1,kv1,xtrial,utrial,vtrial,status)
1609 length=length+partial_length
1614 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold,igrid,h, &
1615 field_min,kx1,ku1,kv1,xtrial,utrial,vtrial,status)
1619 {
if (xtrial(^db)>=xprobmin^db .and. xtrial(^db)<xprobmax^db) point_domain=point_domain+1\}
1620 if (point_domain==
ndim)
then
1621 call trace_locate_point_with_hint(xtrial,igrid,igrid_trial,status)
1627 length=length+abs(h)
1629 call trace_intersect_domain(xold,xtrial,xhit,hit_ok,face_id)
1630 if (.not.hit_ok)
then
1631 call trace_boundary_face_at_point(xold,face_id,hit_ok)
1632 if (.not.hit_ok)
then
1643 partial_length=dsqrt(sum((xhit-xold)**2))
1644 if (partial_length<=100.d0*epsilon(one)*max(one,abs(h)))
then
1651 h_partial=sign(partial_length,h)
1652 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold,igrid, &
1653 h_partial,field_min,kx1,ku1,kv1,xtrial,utrial,vtrial,status)
1658 length=length+partial_length
1670 call trace_endpoint_b_bhat(x_end,face_id,igrid,field_min,b_end, &
1674 call trace_project_to_perp_bhat(u_end,bhat_end,u_perp_end)
1675 call trace_project_to_perp_bhat(v_end,bhat_end,v_perp_end)
1676 call trace_project_to_boundary_face(u_end,bhat_end,face_id,u_face_end)
1677 call trace_project_to_boundary_face(v_end,bhat_end,face_id,v_face_end)
1681 x_f,x_b,u_f_perp,v_f_perp,u_b_perp,v_b_perp,b_seed,b_f,b_b, &
1682 length_f,length_b,face_f,face_b,status,N2,bfactor,b_min)
1684 double precision,
intent(in) :: seed(
ndim),dl
1685 integer,
intent(in) :: max_steps
1686 double precision,
intent(out) :: qperp,logqperp,n2,bfactor
1687 double precision,
intent(out) :: x_f(
ndim),x_b(
ndim)
1688 double precision,
intent(out) :: u_f_perp(
ndim),v_f_perp(
ndim)
1689 double precision,
intent(out) :: u_b_perp(
ndim),v_b_perp(
ndim)
1690 double precision,
intent(out) :: b_seed(
ndim),b_f(
ndim),b_b(
ndim)
1691 double precision,
intent(out) :: length_f,length_b
1692 integer,
intent(out) :: face_f,face_b,status
1693 double precision,
intent(in),
optional :: b_min
1697 if (
present(b_min))
then
1704 logqperp=result%logqperp
1706 bfactor=result%bfactor
1707 x_f=result%forward_endpoint
1708 x_b=result%backward_endpoint
1709 u_f_perp=result%u_forward_perp
1710 v_f_perp=result%v_forward_perp
1711 u_b_perp=result%u_backward_perp
1712 v_b_perp=result%v_backward_perp
1713 b_seed=result%B_seed
1714 b_f=result%forward_B
1715 b_b=result%backward_B
1716 length_f=result%forward_length
1717 length_b=result%backward_length
1718 face_f=result%forward_face
1719 face_b=result%backward_face
1720 status=result%status
1723 subroutine trace_init_qperp_result(seed,result)
1724 double precision,
intent(in) :: seed(
ndim)
1728 result%qperp=trace_debug_nan()
1729 result%logqperp=trace_debug_nan()
1730 result%N2=trace_debug_nan()
1731 result%bfactor=trace_debug_nan()
1732 result%q0=trace_debug_nan()
1733 result%logq0=trace_debug_nan()
1734 result%qperp0=trace_debug_nan()
1735 result%logqperp0=trace_debug_nan()
1736 result%N2_qperp0=trace_debug_nan()
1737 result%bfactor_qperp0=trace_debug_nan()
1738 result%forward_Bn_q0=trace_debug_nan()
1739 result%backward_Bn_q0=trace_debug_nan()
1741 result%bhat_seed=zero
1742 result%forward_endpoint=seed
1743 result%backward_endpoint=seed
1744 result%forward_B=zero
1745 result%backward_B=zero
1746 result%forward_bhat=zero
1747 result%backward_bhat=zero
1748 result%forward_length=zero
1749 result%backward_length=zero
1750 result%forward_nstep=0
1751 result%backward_nstep=0
1754 result%u_forward_perp=zero
1755 result%v_forward_perp=zero
1756 result%u_backward_perp=zero
1757 result%v_backward_perp=zero
1765 result%valid=.false.
1766 result%valid_q0=.false.
1767 result%valid_qperp0=.false.
1768 end subroutine trace_init_qperp_result
1770 subroutine trace_qperp_single_core(seed,dL,max_steps,result,b_min)
1771 double precision,
intent(in) :: seed(
ndim),dl
1772 integer,
intent(in) :: max_steps
1774 double precision,
intent(in),
optional :: b_min
1776 double precision :: field_min,b3(3),bseed_norm
1778 integer :: igrid,status,indomain
1780 call trace_init_qperp_result(seed,result)
1785 else if (
ndim/=3 .or. .not.trace_cartesian_like_geometry())
then
1788 else if (dl<=zero .or. max_steps<=0)
then
1794 {
if (seed(^db)>=xprobmin^db .and. seed(^db)<xprobmax^db) indomain=indomain+1\}
1795 if (indomain/=
ndim)
then
1800 field_min=smalldouble
1801 if (
present(b_min)) field_min=max(b_min,zero)
1803 call trace_debug_locate_point(seed,igrid,status)
1805 result%status=status
1808 call sample_b_at_point(seed,igrid,field_min,b3,status)
1810 result%status=status
1813 result%B_seed=b3(1:
ndim)
1814 bseed_norm=dsqrt(sum(result%B_seed**2))
1815 if (bseed_norm<=zero .or. bseed_norm<field_min)
then
1819 result%bhat_seed=result%B_seed/bseed_norm
1820 call trace_make_perp_basis(b3/bseed_norm,result%u0,result%v0,status)
1822 result%status=status
1827 result%v0,dl,max_steps,.true.,result%forward_endpoint,u_end, &
1828 v_end,result%forward_bhat,result%forward_B,result%u_forward_perp, &
1829 result%v_forward_perp,u_face,v_face,result%forward_length, &
1830 result%forward_face,status,b_min=field_min)
1831 result%forward_status=status
1833 result%status=status
1838 result%v0,dl,max_steps,.false.,result%backward_endpoint,u_end, &
1839 v_end,result%backward_bhat,result%backward_B,result%u_backward_perp, &
1840 result%v_backward_perp,u_face,v_face,result%backward_length, &
1841 result%backward_face,status,b_min=field_min)
1842 result%backward_status=status
1844 result%status=status
1848 call trace_qperp_compute_scalars(result,field_min)
1849 end subroutine trace_qperp_single_core
1851 subroutine trace_tangent_state_init(seed,u0,v0,igrid,seed_id,direction, &
1852 state,accumulate_twist)
1853 double precision,
intent(in) :: seed(
ndim),u0(
ndim),v0(
ndim)
1854 integer,
intent(in) :: igrid,seed_id,direction
1855 type(trace_tangent_state),
intent(out) :: state
1856 logical,
intent(in),
optional :: accumulate_twist
1858 state%seed_id=seed_id
1859 state%direction=direction
1861 state%complete=.false.
1862 state%has_extra=.false.
1876 state%endpoint_B=zero
1877 state%endpoint_bhat=zero
1883 state%accumulate_twist=.false.
1884 if (
present(accumulate_twist)) state%accumulate_twist=accumulate_twist
1885 state%sph_cache%valid=.false.
1886 if (trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical)
then
1887 call trace_spherical_profile_add_count(trace_profile_directions,1_8)
1888 call trace_spherical_profile_add_count(trace_profile_tangent_systems,1_8)
1890 end subroutine trace_tangent_state_init
1892 subroutine trace_tangent_trace_states_grouped(states,nstate,dL,max_steps, &
1893 threshold,trace_mode)
1897 integer,
intent(in) :: nstate,max_steps
1898 integer,
intent(in),
optional :: trace_mode
1899 type(trace_tangent_state),
intent(inout) :: states(nstate)
1900 double precision,
intent(in) :: dl,threshold
1902 logical,
allocatable :: processed(:)
1903 double precision :: t0,tgroup0,tgroup1
1904 integer :: active_count,group_size,istate,jstate,target_grid,group_mode
1905 logical :: any_active
1906 logical :: profile_tangent
1908 group_mode=trace_tangent_group_rk2_general
1909 if (
present(trace_mode)) group_mode=trace_mode
1910 profile_tangent=(group_mode/=trace_tangent_group_rk45_cartesian .and. &
1911 trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical)
1912 if (profile_tangent) t0=trace_spherical_profile_time()
1914 if (trace_cartesian_like_geometry())
then
1919 if (trace_rk2_stats_enabled)
call cpu_time(tgroup0)
1924 if (states(istate)%active)
then
1926 active_count=active_count+1
1929 if (.not.any_active)
exit
1930 call trace_rk2_stats_note_group_iteration()
1931 call trace_rk2_stats_note_grid_group(active_count)
1934 if (.not.states(jstate)%active) cycle
1935 select case (group_mode)
1936 case (trace_tangent_group_rk2_general)
1937 call trace_tangent_state_advance_in_grid(states(jstate), &
1938 states(jstate)%igrid,dl,max_steps,threshold)
1939 case (trace_tangent_group_rk2_short_boundary)
1940 call trace_tangent_state_advance_in_grid(states(jstate), &
1941 states(jstate)%igrid,dl,max_steps,threshold, &
1942 short_boundary=.true.)
1943 case (trace_tangent_group_rk45_cartesian)
1944 call trace_tangent_state_advance_in_grid_rk45_cartesian( &
1945 states(jstate),states(jstate)%igrid,dl,max_steps,threshold)
1948 states(jstate)%active=.false.
1949 states(jstate)%complete=.true.
1954 if (trace_rk2_stats_enabled)
then
1955 call cpu_time(tgroup1)
1956 call trace_rk2_stats_add_grouped_time(tgroup1-tgroup0)
1961 if (trace_rk2_stats_enabled)
call cpu_time(tgroup0)
1962 allocate(processed(nstate))
1966 if (states(istate)%active)
then
1971 if (.not.any_active)
exit
1972 call trace_rk2_stats_note_group_iteration()
1976 if (.not.states(istate)%active .or. processed(istate)) cycle
1977 target_grid=states(istate)%igrid
1978 if (trace_rk2_stats_enabled)
then
1981 if (states(jstate)%active .and. .not.processed(jstate) .and. &
1982 states(jstate)%igrid==target_grid) group_size=group_size+1
1984 call trace_rk2_stats_note_grid_group(group_size)
1988 if (.not.states(jstate)%active .or. processed(jstate)) cycle
1989 if (states(jstate)%igrid/=target_grid) cycle
1990 select case (group_mode)
1991 case (trace_tangent_group_rk2_general)
1992 call trace_tangent_state_advance_in_grid(states(jstate), &
1993 target_grid,dl,max_steps,threshold)
1994 case (trace_tangent_group_rk2_short_boundary)
1995 call trace_tangent_state_advance_in_grid(states(jstate), &
1996 target_grid,dl,max_steps,threshold,short_boundary=.true.)
1997 case (trace_tangent_group_rk45_cartesian)
1998 call trace_tangent_state_advance_in_grid_rk45_cartesian( &
1999 states(jstate),target_grid,dl,max_steps,threshold)
2002 states(jstate)%active=.false.
2003 states(jstate)%complete=.true.
2005 processed(jstate)=.true.
2010 deallocate(processed)
2011 if (trace_rk2_stats_enabled)
then
2012 call cpu_time(tgroup1)
2013 call trace_rk2_stats_add_grouped_time(tgroup1-tgroup0)
2015 if (profile_tangent)
call trace_spherical_profile_add_time( &
2016 trace_profile_time_tangent,trace_spherical_profile_time()-t0)
2017 end subroutine trace_tangent_trace_states_grouped
2019 subroutine trace_tangent_state_advance_in_grid_rk45_cartesian(state, &
2020 igrid,dL,max_steps,threshold)
2021 type(trace_tangent_state),
intent(inout) :: state
2022 integer,
intent(in) :: igrid,max_steps
2023 double precision,
intent(in) :: dl,threshold
2027 if (.not.state%active)
return
2029 do while(state%active .and. state%igrid==igrid .and. &
2030 state%nstep<max_steps)
2031 call trace_tangent_rk45_cartesian_step(state,dl,threshold,status)
2034 state%active=.false.
2035 state%complete=.true.
2040 if (state%active .and. state%nstep>=max_steps)
then
2042 state%active=.false.
2043 state%complete=.true.
2045 end subroutine trace_tangent_state_advance_in_grid_rk45_cartesian
2047 subroutine trace_tangent_rk45_cartesian_step(state,dL,threshold,status)
2048 type(trace_tangent_state),
intent(inout) :: state
2049 double precision,
intent(in) :: dl,threshold
2050 integer,
intent(out) :: status
2052 double precision,
parameter :: b21=1.d0/5.d0
2053 double precision,
parameter :: b31=3.d0/40.d0,b32=9.d0/40.d0
2054 double precision,
parameter :: b41=3.d0/10.d0,b42=-9.d0/10.d0, &
2056 double precision,
parameter :: b51=-11.d0/54.d0,b52=5.d0/2.d0, &
2057 b53=-70.d0/27.d0,b54=35.d0/27.d0
2058 double precision,
parameter :: b61=1631.d0/55296.d0, &
2059 b62=175.d0/512.d0,b63=575.d0/13824.d0, &
2060 b64=44275.d0/110592.d0,b65=253.d0/4096.d0
2061 double precision,
parameter :: c1=37.d0/378.d0,c3=250.d0/621.d0, &
2062 c4=125.d0/594.d0,c6=512.d0/1771.d0
2063 double precision,
parameter :: cs1=2825.d0/27648.d0, &
2064 cs3=18575.d0/48384.d0,cs4=13525.d0/55296.d0, &
2065 cs5=277.d0/14336.d0,cs6=one/4.d0
2069 double precision :: kx5(
ndim),kx6(
ndim)
2071 double precision :: ku5(
ndim),ku6(
ndim)
2073 double precision :: kv5(
ndim),kv6(
ndim)
2077 double precision :: x5sol(
ndim),x4err(
ndim)
2078 double precision :: u5sol(
ndim),v5sol(
ndim)
2079 double precision :: u4err(
ndim),v4err(
ndim)
2080 double precision :: h,hmax,hfloor,hcell,tol,err,grow,hsigned
2081 double precision :: pos_err_ratio,u_err_ratio,v_err_ratio
2082 double precision :: tan_err_ratio,control_ratio
2083 double precision :: tw1,tw3,tw4,tw6,twist_increment
2084 double precision :: dxb^
d
2085 integer :: igrid1,igrid2,igrid3,igrid4,igrid5,igrid6
2086 integer :: iter,point_domain,reject_reason,twist_status
2087 logical :: boundary_finished,pos_ok,tan_ok
2090 if (.not.trace_cartesian_like_geometry())
then
2103 hmax=abs(trace_effective_step(xold,dl,state%igrid,dxb^
d))
2104 if (hmax<=zero)
then
2111 hfloor=max(trace_step_min,100.d0*epsilon(one)*max(one,hmax))
2115 h=max(hfloor,min(h,hmax))
2117 if (state%direction<0) hsigned=-h
2119 call trace_tangent_rhs_cartesian_located(xold,uold,vold, &
2120 state%igrid,threshold,kx1,ku1,kv1,igrid1,status)
2123 x2=xold+hsigned*b21*kx1
2124 u2=uold+hsigned*b21*ku1
2125 v2=vold+hsigned*b21*kv1
2126 call trace_tangent_rhs_cartesian_located(x2,u2,v2,igrid1, &
2127 threshold,kx2,ku2,kv2,igrid2,status)
2130 call trace_tangent_rk45_cartesian_finish_boundary(state,xold,uold, &
2131 vold,x2,hsigned,threshold,kx1,ku1,kv1,status, &
2133 if (boundary_finished)
return
2134 reject_reason=trace_rk45_reject_stage_failure
2137 reject_reason=trace_rk45_reject_stage_outside
2138 if (trace_rk45_stats_enabled) &
2139 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
2141 if (h<=hfloor*(one+epsilon(one)))
exit
2142 h=max(hfloor,half*h)
2146 x3=xold+hsigned*(b31*kx1+b32*kx2)
2147 u3=uold+hsigned*(b31*ku1+b32*ku2)
2148 v3=vold+hsigned*(b31*kv1+b32*kv2)
2149 call trace_tangent_rhs_cartesian_located(x3,u3,v3,igrid2, &
2150 threshold,kx3,ku3,kv3,igrid3,status)
2153 call trace_tangent_rk45_cartesian_finish_boundary(state,xold,uold, &
2154 vold,x3,hsigned,threshold,kx1,ku1,kv1,status, &
2156 if (boundary_finished)
return
2157 reject_reason=trace_rk45_reject_stage_failure
2160 reject_reason=trace_rk45_reject_stage_outside
2161 if (trace_rk45_stats_enabled) &
2162 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
2164 if (h<=hfloor*(one+epsilon(one)))
exit
2165 h=max(hfloor,half*h)
2169 x4=xold+hsigned*(b41*kx1+b42*kx2+b43*kx3)
2170 u4=uold+hsigned*(b41*ku1+b42*ku2+b43*ku3)
2171 v4=vold+hsigned*(b41*kv1+b42*kv2+b43*kv3)
2172 call trace_tangent_rhs_cartesian_located(x4,u4,v4,igrid3, &
2173 threshold,kx4,ku4,kv4,igrid4,status)
2176 call trace_tangent_rk45_cartesian_finish_boundary(state,xold,uold, &
2177 vold,x4,hsigned,threshold,kx1,ku1,kv1,status, &
2179 if (boundary_finished)
return
2180 reject_reason=trace_rk45_reject_stage_failure
2183 reject_reason=trace_rk45_reject_stage_outside
2184 if (trace_rk45_stats_enabled) &
2185 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
2187 if (h<=hfloor*(one+epsilon(one)))
exit
2188 h=max(hfloor,half*h)
2192 x5s=xold+hsigned*(b51*kx1+b52*kx2+b53*kx3+b54*kx4)
2193 u5s=uold+hsigned*(b51*ku1+b52*ku2+b53*ku3+b54*ku4)
2194 v5s=vold+hsigned*(b51*kv1+b52*kv2+b53*kv3+b54*kv4)
2195 call trace_tangent_rhs_cartesian_located(x5s,u5s,v5s,igrid4, &
2196 threshold,kx5,ku5,kv5,igrid5,status)
2199 call trace_tangent_rk45_cartesian_finish_boundary(state,xold,uold, &
2200 vold,x5s,hsigned,threshold,kx1,ku1,kv1,status, &
2202 if (boundary_finished)
return
2203 reject_reason=trace_rk45_reject_stage_failure
2206 reject_reason=trace_rk45_reject_stage_outside
2207 if (trace_rk45_stats_enabled) &
2208 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
2210 if (h<=hfloor*(one+epsilon(one)))
exit
2211 h=max(hfloor,half*h)
2215 x6=xold+hsigned*(b61*kx1+b62*kx2+b63*kx3+b64*kx4+b65*kx5)
2216 u6=uold+hsigned*(b61*ku1+b62*ku2+b63*ku3+b64*ku4+b65*ku5)
2217 v6=vold+hsigned*(b61*kv1+b62*kv2+b63*kv3+b64*kv4+b65*kv5)
2218 call trace_tangent_rhs_cartesian_located(x6,u6,v6,igrid5, &
2219 threshold,kx6,ku6,kv6,igrid6,status)
2222 call trace_tangent_rk45_cartesian_finish_boundary(state,xold,uold, &
2223 vold,x6,hsigned,threshold,kx1,ku1,kv1,status, &
2225 if (boundary_finished)
return
2226 reject_reason=trace_rk45_reject_stage_failure
2229 reject_reason=trace_rk45_reject_stage_outside
2230 if (trace_rk45_stats_enabled) &
2231 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
2233 if (h<=hfloor*(one+epsilon(one)))
exit
2234 h=max(hfloor,half*h)
2238 x5sol=xold+hsigned*(c1*kx1+c3*kx3+c4*kx4+c6*kx6)
2239 u5sol=uold+hsigned*(c1*ku1+c3*ku3+c4*ku4+c6*ku6)
2240 v5sol=vold+hsigned*(c1*kv1+c3*kv3+c4*kv4+c6*kv6)
2241 x4err=xold+hsigned*(cs1*kx1+cs3*kx3+cs4*kx4+ &
2243 u4err=uold+hsigned*(cs1*ku1+cs3*ku3+cs4*ku4+ &
2245 v4err=vold+hsigned*(cs1*kv1+cs3*kv3+cs4*kv4+ &
2249 {
if (x5sol(^db)>=xprobmin^db .and. x5sol(^db)<xprobmax^db) point_domain=point_domain+1\}
2250 if (point_domain/=
ndim)
then
2251 call trace_tangent_rk45_cartesian_finish_boundary(state,xold,uold, &
2252 vold,x5sol,hsigned,threshold,kx1,ku1,kv1,status, &
2254 if (boundary_finished)
return
2255 if (trace_rk45_stats_enabled) &
2256 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
2257 trace_rk45_reject_boundary)
2262 call trace_cartesian_local_cell_size(xold,igrid1,hcell,status)
2264 err=dsqrt(sum((x5sol-x4err)**2))
2265 tol=trace_rk45_atol+trace_rk45_rtol*max(h,hcell)
2267 pos_err_ratio=err/tol
2271 u_err_ratio=dsqrt(sum((u5sol-u4err)**2))/ &
2272 max(dsqrt(sum(u5sol**2)),trace_rk45_tangent_floor)
2273 v_err_ratio=dsqrt(sum((v5sol-v4err)**2))/ &
2274 max(dsqrt(sum(v5sol**2)),trace_rk45_tangent_floor)
2275 tan_err_ratio=max(u_err_ratio,v_err_ratio)
2276 if (trace_rk45_stats_enabled) &
2277 call trace_rk45_stats_note_tangent_error(pos_err_ratio, &
2278 u_err_ratio,v_err_ratio)
2280 tan_ok=(tan_err_ratio<=trace_rk45_tangent_rtol)
2281 if ((pos_ok .and. tan_ok) .or. h<=hfloor*(one+epsilon(one)))
then
2282 if (state%accumulate_twist .and. &
2285 call trace_twist_density_at_point(xold,igrid1,threshold,tw1, &
2288 call trace_twist_density_at_point(x3,igrid3,threshold,tw3, &
2291 call trace_twist_density_at_point(x4,igrid4,threshold,tw4, &
2294 call trace_twist_density_at_point(x6,igrid6,threshold,tw6, &
2297 twist_increment=h*(c1*tw1+c3*tw3+c4*tw4+c6*tw6)
2298 state%twist=state%twist+twist_increment
2300 state%twist_status=twist_status
2306 state%length=state%length+h
2307 state%nstep=state%nstep+1
2308 call trace_locate_point_with_hint(state%x,igrid6,state%igrid,status)
2310 control_ratio=max(pos_err_ratio, &
2311 tan_err_ratio/trace_rk45_tangent_rtol)
2312 if (control_ratio>zero)
then
2313 grow=trace_rk45_safety*(one/control_ratio)**0.2d0
2314 grow=max(trace_rk45_min_shrink,min(trace_rk45_max_grow,grow))
2316 grow=trace_rk45_max_grow
2318 state%rk45_h=min(hmax,max(hfloor,h*grow))
2319 if (trace_rk45_stats_enabled) &
2320 call trace_rk45_stats_note_attempt(.true.,.false.,h)
2325 if (.not.pos_ok)
then
2326 grow=trace_rk45_safety*(tol/max(err,smalldouble))**0.25d0
2327 if (trace_rk45_stats_enabled) &
2328 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
2329 trace_rk45_reject_error)
2331 grow=trace_rk45_safety*(trace_rk45_tangent_rtol/ &
2332 max(tan_err_ratio,smalldouble))**0.25d0
2333 if (trace_rk45_stats_enabled) &
2334 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
2335 trace_rk45_reject_tangent_error)
2337 grow=max(trace_rk45_min_shrink,min(one,grow))
2338 h=max(hfloor,h*grow)
2341 call trace_tangent_rk45_cartesian_finish_boundary(state,xold,uold, &
2342 vold,xold+hsigned*kx1,hsigned,threshold,kx1,ku1,kv1,status, &
2345 end subroutine trace_tangent_rk45_cartesian_step
2347 subroutine trace_tangent_rhs_cartesian_located(x,u,v,igrid_hint, &
2348 threshold,kx,ku,kv,igrid,status)
2349 double precision,
intent(in) :: x(
ndim),u(
ndim),v(
ndim),threshold
2350 integer,
intent(in) :: igrid_hint
2351 double precision,
intent(out) :: kx(
ndim),ku(
ndim),kv(
ndim)
2352 integer,
intent(out) :: igrid,status
2359 if (.not.trace_cartesian_like_geometry())
return
2361 call trace_locate_point_with_hint(x,igrid_hint,igrid,status)
2363 call trace_tangent_rhs(x,u,v,igrid,threshold,kx,ku,kv,status)
2364 end subroutine trace_tangent_rhs_cartesian_located
2366 subroutine trace_tangent_rk45_cartesian_finish_boundary(state,xold,uold, &
2367 vold,xstage,hsigned,threshold,kx1,ku1,kv1,status,finished)
2368 type(trace_tangent_state),
intent(inout) :: state
2369 double precision,
intent(in) :: xold(
ndim),uold(
ndim),vold(
ndim)
2370 double precision,
intent(in) :: xstage(
ndim),hsigned,threshold
2371 double precision,
intent(in) :: kx1(
ndim),ku1(
ndim),kv1(
ndim)
2372 integer,
intent(out) :: status
2373 logical,
intent(out) :: finished
2375 double precision :: xhit(
ndim),utrial(
ndim),vtrial(
ndim)
2376 double precision :: xtrial(
ndim),partial_length,h_partial
2380 call trace_intersect_domain(xold,xstage,xhit,hit_ok,state%face_id)
2381 if (.not.hit_ok)
return
2383 partial_length=dsqrt(sum((xhit-xold)**2))
2384 if (partial_length>100.d0*epsilon(one)*max(one,abs(hsigned)))
then
2385 h_partial=sign(partial_length,hsigned)
2386 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold,state%igrid, &
2387 h_partial,threshold,kx1,ku1,kv1,xtrial,utrial,vtrial,status)
2389 call trace_tangent_accumulate_twist(state,xhit,partial_length, &
2393 state%length=state%length+partial_length
2394 state%nstep=state%nstep+1
2402 state%active=.false.
2403 state%complete=.true.
2405 call trace_tangent_state_finalize_boundary(state,threshold)
2406 call trace_rk45_stats_note_attempt(.true.,.true.,partial_length)
2409 end subroutine trace_tangent_rk45_cartesian_finish_boundary
2411 subroutine trace_tangent_trace_states_grouped_rk45_spherical(states, &
2412 nstate,dL,max_steps,threshold)
2413 integer,
intent(in) :: nstate,max_steps
2414 type(trace_tangent_state),
intent(inout) :: states(nstate)
2415 double precision,
intent(in) :: dl,threshold
2417 logical,
allocatable :: processed(:)
2418 integer :: istate,jstate,target_grid
2419 logical :: any_active
2421 allocate(processed(nstate))
2425 if (states(istate)%active)
then
2430 if (.not.any_active)
exit
2434 if (.not.states(istate)%active .or. processed(istate)) cycle
2435 target_grid=states(istate)%igrid
2438 if (.not.states(jstate)%active .or. processed(jstate)) cycle
2439 if (states(jstate)%igrid/=target_grid) cycle
2440 call trace_tangent_state_advance_in_grid_rk45_spherical( &
2441 states(jstate),target_grid,dl,max_steps,threshold)
2442 processed(jstate)=.true.
2447 deallocate(processed)
2448 end subroutine trace_tangent_trace_states_grouped_rk45_spherical
2450 subroutine trace_tangent_state_advance_in_grid_rk45_spherical(state, &
2451 igrid,dL,max_steps,threshold)
2452 type(trace_tangent_state),
intent(inout) :: state
2453 integer,
intent(in) :: igrid,max_steps
2454 double precision,
intent(in) :: dl,threshold
2458 if (.not.state%active)
return
2460 do while(state%active .and. state%igrid==igrid .and. &
2461 state%nstep<max_steps)
2462 call trace_tangent_rk45_spherical_step(state,dl,threshold,status)
2465 state%active=.false.
2466 state%complete=.true.
2471 if (state%active .and. state%nstep>=max_steps)
then
2473 state%active=.false.
2474 state%complete=.true.
2476 if ((.not.state%active) .and. trace_spherical_profile_enabled .and. &
2477 geo_coordinate==geo_spherical)
then
2478 call trace_spherical_profile_note_trace_steps(state%nstep)
2480 end subroutine trace_tangent_state_advance_in_grid_rk45_spherical
2482 subroutine trace_tangent_rk45_spherical_step(state,dL,threshold,status)
2483 type(trace_tangent_state),
intent(inout) :: state
2484 double precision,
intent(in) :: dl,threshold
2485 integer,
intent(out) :: status
2487 double precision,
parameter :: b21=1.d0/5.d0
2488 double precision,
parameter :: b31=3.d0/40.d0,b32=9.d0/40.d0
2489 double precision,
parameter :: b41=3.d0/10.d0,b42=-9.d0/10.d0, &
2491 double precision,
parameter :: b51=-11.d0/54.d0,b52=5.d0/2.d0, &
2492 b53=-70.d0/27.d0,b54=35.d0/27.d0
2493 double precision,
parameter :: b61=1631.d0/55296.d0, &
2494 b62=175.d0/512.d0,b63=575.d0/13824.d0, &
2495 b64=44275.d0/110592.d0,b65=253.d0/4096.d0
2496 double precision,
parameter :: c1=37.d0/378.d0,c3=250.d0/621.d0, &
2497 c4=125.d0/594.d0,c6=512.d0/1771.d0
2498 double precision,
parameter :: cs1=2825.d0/27648.d0, &
2499 cs3=18575.d0/48384.d0,cs4=13525.d0/55296.d0, &
2500 cs5=277.d0/14336.d0,cs6=one/4.d0
2503 double precision :: pold(
ndim),qold(
ndim)
2505 double precision :: kx5(
ndim),kx6(
ndim)
2507 double precision :: ku5(
ndim),ku6(
ndim)
2509 double precision :: kv5(
ndim),kv6(
ndim)
2511 double precision :: kp5(
ndim),kp6(
ndim)
2513 double precision :: kq5(
ndim),kq6(
ndim)
2519 double precision :: x5sol(
ndim),x4err(
ndim)
2520 double precision :: u5sol(
ndim),v5sol(
ndim)
2521 double precision :: u4err(
ndim),v4err(
ndim)
2522 double precision :: p5sol(
ndim),q5sol(
ndim)
2523 double precision :: p4err(
ndim),q4err(
ndim)
2524 double precision :: h,hmax,hfloor,hcell,tol,err,grow,hsigned
2525 double precision :: pos_err_ratio,u_err_ratio,v_err_ratio
2526 double precision :: p_err_ratio,q_err_ratio
2527 double precision :: tan_err_ratio,control_ratio
2528 double precision :: tw1,tw3,tw4,tw6,twist_increment
2529 double precision :: r_metric,sin_theta_metric
2530 double precision :: domain_min(
ndim),domain_max(
ndim)
2531 type(trace_sph_interp_ctx) :: ctx1,ctx2,ctx3,ctx4,ctx5,ctx6
2532 integer :: igrid1,igrid2,igrid3,igrid4,igrid5,igrid6
2533 integer :: iter,point_domain,ctx_status,reject_reason,twist_status
2534 logical :: boundary_finished,pos_ok,tan_ok
2537 if (geo_coordinate/=geo_spherical)
then
2551 call trace_spherical_interp_ctx_build_cached(xold,state%igrid, &
2552 state%sph_cache,ctx1,ctx_status)
2557 hmax=abs(trace_spherical_effective_step_ctx(dl,ctx1))
2559 if (hmax<=zero)
then
2566 hfloor=max(trace_step_min,100.d0*epsilon(one)*max(one,hmax))
2568 ^
d&domain_min(^
d)=xprobmin^
d;
2569 ^
d&domain_max(^
d)=xprobmax^
d;
2572 h=max(hfloor,min(h,hmax))
2574 if (state%direction<0) hsigned=-h
2576 if (state%has_extra)
then
2577 call trace_tangent_rhs(xold,uold,vold,ctx1%igrid,threshold,kx1, &
2578 ku1,kv1,status,pold,qold,kp1,kq1,sph_ctx=ctx1)
2580 call trace_tangent_rhs(xold,uold,vold,ctx1%igrid,threshold,kx1, &
2581 ku1,kv1,status,sph_ctx=ctx1)
2586 x2=xold+hsigned*b21*kx1
2587 u2=uold+hsigned*b21*ku1
2588 v2=vold+hsigned*b21*kv1
2589 if (state%has_extra)
then
2590 p2=pold+hsigned*b21*kp1
2591 q2=qold+hsigned*b21*kq1
2593 call trace_spherical_interp_ctx_build_cached(x2,igrid1, &
2594 state%sph_cache,ctx2,ctx_status)
2596 call trace_tangent_rk45_spherical_finish_boundary(state,xold,uold, &
2597 vold,x2,hsigned,threshold,kx1,ku1,kv1,status, &
2598 boundary_finished,pold,qold,kp1,kq1)
2599 if (boundary_finished)
return
2600 reject_reason=trace_rk45_reject_stage_failure
2603 reject_reason=trace_rk45_reject_stage_outside
2604 call trace_rk45_stats_note_attempt(.false.,.false.,h,reject_reason)
2605 if (h<=hfloor*(one+epsilon(one)))
exit
2606 h=max(hfloor,half*h)
2609 if (state%has_extra)
then
2610 call trace_tangent_rhs(x2,u2,v2,ctx2%igrid,threshold,kx2,ku2, &
2611 kv2,status,p2,q2,kp2,kq2,sph_ctx=ctx2)
2613 call trace_tangent_rhs(x2,u2,v2,ctx2%igrid,threshold,kx2,ku2, &
2614 kv2,status,sph_ctx=ctx2)
2619 x3=xold+hsigned*(b31*kx1+b32*kx2)
2620 u3=uold+hsigned*(b31*ku1+b32*ku2)
2621 v3=vold+hsigned*(b31*kv1+b32*kv2)
2622 if (state%has_extra)
then
2623 p3=pold+hsigned*(b31*kp1+b32*kp2)
2624 q3=qold+hsigned*(b31*kq1+b32*kq2)
2626 call trace_spherical_interp_ctx_build_cached(x3,igrid2, &
2627 state%sph_cache,ctx3,ctx_status)
2629 call trace_tangent_rk45_spherical_finish_boundary(state,xold,uold, &
2630 vold,x3,hsigned,threshold,kx1,ku1,kv1,status, &
2631 boundary_finished,pold,qold,kp1,kq1)
2632 if (boundary_finished)
return
2633 reject_reason=trace_rk45_reject_stage_failure
2636 reject_reason=trace_rk45_reject_stage_outside
2637 call trace_rk45_stats_note_attempt(.false.,.false.,h,reject_reason)
2638 if (h<=hfloor*(one+epsilon(one)))
exit
2639 h=max(hfloor,half*h)
2642 if (state%has_extra)
then
2643 call trace_tangent_rhs(x3,u3,v3,ctx3%igrid,threshold,kx3,ku3, &
2644 kv3,status,p3,q3,kp3,kq3,sph_ctx=ctx3)
2646 call trace_tangent_rhs(x3,u3,v3,ctx3%igrid,threshold,kx3,ku3, &
2647 kv3,status,sph_ctx=ctx3)
2652 x4=xold+hsigned*(b41*kx1+b42*kx2+b43*kx3)
2653 u4=uold+hsigned*(b41*ku1+b42*ku2+b43*ku3)
2654 v4=vold+hsigned*(b41*kv1+b42*kv2+b43*kv3)
2655 if (state%has_extra)
then
2656 p4=pold+hsigned*(b41*kp1+b42*kp2+b43*kp3)
2657 q4=qold+hsigned*(b41*kq1+b42*kq2+b43*kq3)
2659 call trace_spherical_interp_ctx_build_cached(x4,igrid3, &
2660 state%sph_cache,ctx4,ctx_status)
2662 call trace_tangent_rk45_spherical_finish_boundary(state,xold,uold, &
2663 vold,x4,hsigned,threshold,kx1,ku1,kv1,status, &
2664 boundary_finished,pold,qold,kp1,kq1)
2665 if (boundary_finished)
return
2666 reject_reason=trace_rk45_reject_stage_failure
2669 reject_reason=trace_rk45_reject_stage_outside
2670 call trace_rk45_stats_note_attempt(.false.,.false.,h,reject_reason)
2671 if (h<=hfloor*(one+epsilon(one)))
exit
2672 h=max(hfloor,half*h)
2675 if (state%has_extra)
then
2676 call trace_tangent_rhs(x4,u4,v4,ctx4%igrid,threshold,kx4,ku4, &
2677 kv4,status,p4,q4,kp4,kq4,sph_ctx=ctx4)
2679 call trace_tangent_rhs(x4,u4,v4,ctx4%igrid,threshold,kx4,ku4, &
2680 kv4,status,sph_ctx=ctx4)
2685 x5s=xold+hsigned*(b51*kx1+b52*kx2+b53*kx3+b54*kx4)
2686 u5s=uold+hsigned*(b51*ku1+b52*ku2+b53*ku3+b54*ku4)
2687 v5s=vold+hsigned*(b51*kv1+b52*kv2+b53*kv3+b54*kv4)
2688 if (state%has_extra)
then
2689 p5s=pold+hsigned*(b51*kp1+b52*kp2+b53*kp3+b54*kp4)
2690 q5s=qold+hsigned*(b51*kq1+b52*kq2+b53*kq3+b54*kq4)
2692 call trace_spherical_interp_ctx_build_cached(x5s,igrid4, &
2693 state%sph_cache,ctx5,ctx_status)
2695 call trace_tangent_rk45_spherical_finish_boundary(state,xold,uold, &
2696 vold,x5s,hsigned,threshold,kx1,ku1,kv1,status, &
2697 boundary_finished,pold,qold,kp1,kq1)
2698 if (boundary_finished)
return
2699 reject_reason=trace_rk45_reject_stage_failure
2702 reject_reason=trace_rk45_reject_stage_outside
2703 call trace_rk45_stats_note_attempt(.false.,.false.,h,reject_reason)
2704 if (h<=hfloor*(one+epsilon(one)))
exit
2705 h=max(hfloor,half*h)
2708 if (state%has_extra)
then
2709 call trace_tangent_rhs(x5s,u5s,v5s,ctx5%igrid,threshold,kx5,ku5, &
2710 kv5,status,p5s,q5s,kp5,kq5,sph_ctx=ctx5)
2712 call trace_tangent_rhs(x5s,u5s,v5s,ctx5%igrid,threshold,kx5,ku5, &
2713 kv5,status,sph_ctx=ctx5)
2718 x6=xold+hsigned*(b61*kx1+b62*kx2+b63*kx3+b64*kx4+b65*kx5)
2719 u6=uold+hsigned*(b61*ku1+b62*ku2+b63*ku3+b64*ku4+b65*ku5)
2720 v6=vold+hsigned*(b61*kv1+b62*kv2+b63*kv3+b64*kv4+b65*kv5)
2721 if (state%has_extra)
then
2722 p6=pold+hsigned*(b61*kp1+b62*kp2+b63*kp3+b64*kp4+b65*kp5)
2723 q6=qold+hsigned*(b61*kq1+b62*kq2+b63*kq3+b64*kq4+b65*kq5)
2725 call trace_spherical_interp_ctx_build_cached(x6,igrid5, &
2726 state%sph_cache,ctx6,ctx_status)
2728 call trace_tangent_rk45_spherical_finish_boundary(state,xold,uold, &
2729 vold,x6,hsigned,threshold,kx1,ku1,kv1,status, &
2730 boundary_finished,pold,qold,kp1,kq1)
2731 if (boundary_finished)
return
2732 reject_reason=trace_rk45_reject_stage_failure
2735 reject_reason=trace_rk45_reject_stage_outside
2736 call trace_rk45_stats_note_attempt(.false.,.false.,h,reject_reason)
2737 if (h<=hfloor*(one+epsilon(one)))
exit
2738 h=max(hfloor,half*h)
2741 if (state%has_extra)
then
2742 call trace_tangent_rhs(x6,u6,v6,ctx6%igrid,threshold,kx6,ku6, &
2743 kv6,status,p6,q6,kp6,kq6,sph_ctx=ctx6)
2745 call trace_tangent_rhs(x6,u6,v6,ctx6%igrid,threshold,kx6,ku6, &
2746 kv6,status,sph_ctx=ctx6)
2751 x5sol=xold+hsigned*(c1*kx1+c3*kx3+c4*kx4+c6*kx6)
2752 u5sol=uold+hsigned*(c1*ku1+c3*ku3+c4*ku4+c6*ku6)
2753 v5sol=vold+hsigned*(c1*kv1+c3*kv3+c4*kv4+c6*kv6)
2754 x4err=xold+hsigned*(cs1*kx1+cs3*kx3+cs4*kx4+ &
2756 u4err=uold+hsigned*(cs1*ku1+cs3*ku3+cs4*ku4+ &
2758 v4err=vold+hsigned*(cs1*kv1+cs3*kv3+cs4*kv4+ &
2760 if (state%has_extra)
then
2761 p5sol=pold+hsigned*(c1*kp1+c3*kp3+c4*kp4+c6*kp6)
2762 q5sol=qold+hsigned*(c1*kq1+c3*kq3+c4*kq4+c6*kq6)
2763 p4err=pold+hsigned*(cs1*kp1+cs3*kp3+cs4*kp4+ &
2765 q4err=qold+hsigned*(cs1*kq1+cs3*kq3+cs4*kq4+ &
2770 {
if (x5sol(^db)>=domain_min(^db) .and. x5sol(^db)<domain_max(^db)) point_domain=point_domain+1\}
2771 if (point_domain/=
ndim)
then
2772 call trace_tangent_rk45_spherical_finish_boundary(state,xold,uold, &
2773 vold,x5sol,hsigned,threshold,kx1,ku1,kv1,status, &
2774 boundary_finished,pold,qold,kp1,kq1)
2775 if (boundary_finished)
return
2776 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
2777 trace_rk45_reject_boundary)
2784 r_metric=max(abs(xold(1)),smalldouble)
2785 sin_theta_metric=max(abs(dsin(xold(2))),smalldouble)
2786 err=dsqrt((x5sol(1)-x4err(1))**2+ &
2787 (r_metric*(x5sol(2)-x4err(2)))**2+ &
2788 (r_metric*sin_theta_metric*(x5sol(3)-x4err(3)))**2)
2790 if (hcell<=zero) hcell=hmax
2791 tol=trace_rk45_atol+trace_rk45_rtol*max(h,hcell)
2793 pos_err_ratio=err/tol
2797 u_err_ratio=dsqrt(sum((u5sol-u4err)**2))/ &
2798 max(dsqrt(sum(u5sol**2)),trace_rk45_tangent_floor)
2799 v_err_ratio=dsqrt(sum((v5sol-v4err)**2))/ &
2800 max(dsqrt(sum(v5sol**2)),trace_rk45_tangent_floor)
2801 if (state%has_extra)
then
2802 p_err_ratio=dsqrt(sum((p5sol-p4err)**2))/ &
2803 max(dsqrt(sum(p5sol**2)),trace_rk45_tangent_floor)
2804 q_err_ratio=dsqrt(sum((q5sol-q4err)**2))/ &
2805 max(dsqrt(sum(q5sol**2)),trace_rk45_tangent_floor)
2806 u_err_ratio=max(u_err_ratio,p_err_ratio)
2807 v_err_ratio=max(v_err_ratio,q_err_ratio)
2809 tan_err_ratio=max(u_err_ratio,v_err_ratio)
2810 call trace_rk45_stats_note_tangent_error(pos_err_ratio, &
2811 u_err_ratio,v_err_ratio)
2813 tan_ok=(tan_err_ratio<=trace_rk45_tangent_rtol)
2814 if ((pos_ok .and. tan_ok) .or. h<=hfloor*(one+epsilon(one)))
then
2815 if (state%accumulate_twist .and. &
2818 call trace_twist_density_at_point(xold,ctx1%igrid,threshold,tw1, &
2819 twist_status,sph_cache=ctx1)
2821 call trace_twist_density_at_point(x3,ctx3%igrid,threshold, &
2822 tw3,twist_status,sph_cache=ctx3)
2824 call trace_twist_density_at_point(x4,ctx4%igrid,threshold, &
2825 tw4,twist_status,sph_cache=ctx4)
2827 call trace_twist_density_at_point(x6,ctx6%igrid,threshold, &
2828 tw6,twist_status,sph_cache=ctx6)
2830 twist_increment=h*(c1*tw1+c3*tw3+c4*tw4+c6*tw6)
2831 state%twist=state%twist+twist_increment
2833 state%twist_status=twist_status
2839 if (state%has_extra)
then
2843 state%length=state%length+h
2844 state%nstep=state%nstep+1
2845 call trace_locate_point_with_hint(state%x,igrid6,state%igrid,status)
2847 state%sph_cache%valid=.false.
2848 if (trace_spherical_profile_enabled) &
2849 call trace_spherical_profile_add_count(trace_profile_steps,1_8)
2850 control_ratio=max(pos_err_ratio, &
2851 tan_err_ratio/trace_rk45_tangent_rtol)
2852 if (control_ratio>zero)
then
2853 grow=trace_rk45_safety*(one/control_ratio)**0.2d0
2854 grow=max(trace_rk45_min_shrink,min(trace_rk45_max_grow,grow))
2856 grow=trace_rk45_max_grow
2858 state%rk45_h=min(hmax,max(hfloor,h*grow))
2859 call trace_rk45_stats_note_attempt(.true.,.false.,h)
2864 if (.not.pos_ok)
then
2865 grow=trace_rk45_safety*(tol/max(err,smalldouble))**0.25d0
2866 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
2867 trace_rk45_reject_error)
2869 grow=trace_rk45_safety*(trace_rk45_tangent_rtol/ &
2870 max(tan_err_ratio,smalldouble))**0.25d0
2871 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
2872 trace_rk45_reject_tangent_error)
2874 grow=max(trace_rk45_min_shrink,min(one,grow))
2875 h=max(hfloor,h*grow)
2878 call trace_tangent_rk45_spherical_finish_boundary(state,xold,uold, &
2879 vold,xold+hsigned*kx1,hsigned,threshold,kx1,ku1,kv1,status, &
2880 boundary_finished,pold,qold,kp1,kq1)
2882 end subroutine trace_tangent_rk45_spherical_step
2884 subroutine trace_tangent_rk45_spherical_finish_boundary(state,xold,uold, &
2885 vold,xstage,hsigned,threshold,kx1,ku1,kv1,status,finished, &
2887 type(trace_tangent_state),
intent(inout) :: state
2888 double precision,
intent(in) :: xold(
ndim),uold(
ndim),vold(
ndim)
2889 double precision,
intent(in) :: xstage(
ndim),hsigned,threshold
2890 double precision,
intent(in) :: kx1(
ndim),ku1(
ndim),kv1(
ndim)
2891 integer,
intent(out) :: status
2892 logical,
intent(out) :: finished
2893 double precision,
intent(in),
optional :: pold(
ndim),qold(
ndim)
2894 double precision,
intent(in),
optional :: kp1(
ndim),kq1(
ndim)
2896 double precision :: xhit(
ndim),utrial(
ndim),vtrial(
ndim)
2897 double precision :: ptrial(
ndim),qtrial(
ndim)
2898 double precision :: xtrial(
ndim),partial_length,h_partial,alpha_hit
2902 call trace_intersect_domain(xold,xstage,xhit,hit_ok,state%face_id, &
2904 if (.not.hit_ok)
return
2906 partial_length=trace_segment_length(xold,xhit,hsigned,alpha_hit)
2907 if (partial_length>100.d0*epsilon(one)*max(one,abs(hsigned)))
then
2908 h_partial=sign(partial_length,hsigned)
2909 if (state%has_extra)
then
2910 if (.not.(
present(pold) .and.
present(qold) .and.
present(kp1) &
2911 .and.
present(kq1)))
then
2915 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold,state%igrid, &
2916 h_partial,threshold,kx1,ku1,kv1,xtrial,utrial,vtrial,status, &
2917 pold,qold,kp1,kq1,ptrial,qtrial,sph_cache=state%sph_cache)
2919 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold,state%igrid, &
2920 h_partial,threshold,kx1,ku1,kv1,xtrial,utrial,vtrial,status, &
2921 sph_cache=state%sph_cache)
2924 call trace_tangent_accumulate_twist(state,xhit,partial_length, &
2928 if (state%has_extra)
then
2932 state%length=state%length+partial_length
2933 state%nstep=state%nstep+1
2934 if (trace_spherical_profile_enabled) &
2935 call trace_spherical_profile_add_count(trace_profile_steps,1_8)
2939 if (state%has_extra)
then
2940 if (.not.(
present(pold) .and.
present(qold)))
then
2951 state%active=.false.
2952 state%complete=.true.
2954 state%sph_cache%valid=.false.
2955 if (trace_spherical_profile_enabled)
then
2956 call trace_spherical_profile_add_count(trace_profile_boundary_events,1_8)
2958 call trace_tangent_state_finalize_boundary(state,threshold)
2959 call trace_rk45_stats_note_attempt(.true.,.true.,partial_length)
2962 end subroutine trace_tangent_rk45_spherical_finish_boundary
2964 subroutine trace_tangent_state_advance_in_grid(state,igrid,dL,max_steps, &
2965 threshold,short_boundary)
2966 type(trace_tangent_state),
intent(inout) :: state
2967 integer,
intent(in) :: igrid,max_steps
2968 double precision,
intent(in) :: dl,threshold
2969 logical,
intent(in),
optional :: short_boundary
2971 integer,
parameter :: max_bisect=50
2972 double precision :: h,h_partial,partial_length,alpha_hit
2973 double precision :: h_abs_low,h_abs_high,h_abs_mid,h_abs_final,hsign
2975 double precision :: ptrial(
ndim),qtrial(
ndim)
2977 double precision :: pold(
ndim),qold(
ndim)
2981 double precision :: dxb^
d
2982 type(trace_sph_interp_ctx) :: ctx_old
2983 integer :: igrid_old,igrid_trial,point_domain,iter
2984 integer :: ctx_status,trial_status
2985 logical :: hit_ok,use_short_boundary
2987 if (.not.state%active)
return
2988 use_short_boundary=.false.
2989 if (
present(short_boundary)) use_short_boundary=short_boundary
2991 do while(state%active .and. state%igrid==igrid .and. &
2992 state%nstep<max_steps)
3000 if (geo_coordinate==geo_spherical)
then
3001 call trace_spherical_interp_ctx_build_cached(xold,state%igrid, &
3002 state%sph_cache,ctx_old,ctx_status)
3005 h=trace_spherical_effective_step_ctx(dl,ctx_old)
3007 h=trace_effective_step(xold,dl,state%igrid,dxb^
d)
3009 if (state%direction<0) h=-h
3011 if (state%has_extra)
then
3013 call trace_tangent_rhs(xold,uold,vold,state%igrid,threshold,kx1, &
3014 ku1,kv1,state%status,pold,qold,kp1,kq1,sph_ctx=ctx_old)
3016 call trace_tangent_rhs(xold,uold,vold,state%igrid,threshold,kx1, &
3017 ku1,kv1,state%status,pold,qold,kp1,kq1)
3021 call trace_tangent_rhs(xold,uold,vold,state%igrid,threshold,kx1, &
3022 ku1,kv1,state%status,sph_ctx=ctx_old)
3024 call trace_tangent_rhs(xold,uold,vold,state%igrid,threshold,kx1, &
3025 ku1,kv1,state%status)
3029 state%active=.false.
3030 state%complete=.true.
3031 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3034 if (use_short_boundary)
then
3038 if (state%has_extra)
then
3039 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold,state%igrid, &
3040 h,threshold,kx1,ku1,kv1,xtrial,utrial,vtrial,state%status, &
3041 pold,qold,kp1,kq1,ptrial,qtrial,sph_cache=state%sph_cache, &
3044 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold,state%igrid, &
3045 h,threshold,kx1,ku1,kv1,xtrial,utrial,vtrial,state%status, &
3046 sph_cache=state%sph_cache,clamp_stage=.true.)
3049 state%active=.false.
3050 state%complete=.true.
3051 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3056 {
if (xtrial(^db)>=xprobmin^db .and. xtrial(^db)<xprobmax^db) point_domain=point_domain+1\}
3057 if (point_domain==
ndim)
then
3058 igrid_old=state%igrid
3059 call trace_locate_point_with_hint(xtrial,state%igrid,igrid_trial, &
3062 state%active=.false.
3063 state%complete=.true.
3064 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3067 call trace_tangent_accumulate_twist(state,xtrial,abs(h),threshold)
3071 if (state%has_extra)
then
3075 state%igrid=igrid_trial
3076 state%length=state%length+abs(h)
3077 state%nstep=state%nstep+1
3078 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_step(abs(h),.false., &
3079 igrid_trial/=igrid_old)
3080 if (trace_spherical_profile_enabled .and. &
3081 geo_coordinate==geo_spherical)
then
3082 call trace_spherical_profile_add_count(trace_profile_steps,1_8)
3093 do iter=1,max_bisect
3094 h_abs_mid=half*(h_abs_low+h_abs_high)
3095 if (h_abs_high-h_abs_low<=100.d0*epsilon(one)*max(one,abs(h))) &
3098 if (state%has_extra)
then
3099 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold, &
3100 state%igrid,hsign*h_abs_mid,threshold,kx1,ku1,kv1, &
3101 xtrial,utrial,vtrial,trial_status,pold,qold,kp1,kq1, &
3102 ptrial,qtrial,sph_cache=state%sph_cache, &
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, &
3108 sph_cache=state%sph_cache,clamp_stage=.true.)
3111 h_abs_high=h_abs_mid
3115 {
if (xtrial(^db)>=xprobmin^db .and. xtrial(^db)<xprobmax^db) point_domain=point_domain+1\}
3116 if (point_domain==
ndim)
then
3121 if (state%has_extra)
then
3126 h_abs_high=h_abs_mid
3131 call trace_intersect_domain(xlow,xhigh,xhit,hit_ok,state%face_id, &
3134 h_abs_final=h_abs_low+max(zero,min(one,alpha_hit))* &
3135 (h_abs_high-h_abs_low)
3138 h_abs_final=h_abs_low
3139 call trace_boundary_face_at_point(xhit,state%face_id,hit_ok)
3141 if (.not.hit_ok)
then
3143 state%active=.false.
3144 state%complete=.true.
3145 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3149 partial_length=h_abs_final
3150 if (partial_length>100.d0*epsilon(one)*max(one,abs(h)))
then
3152 if (state%has_extra)
then
3153 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold, &
3154 state%igrid,hsign*h_abs_final,threshold,kx1,ku1,kv1, &
3155 xtrial,utrial,vtrial,trial_status,pold,qold,kp1,kq1, &
3156 ptrial,qtrial,sph_cache=state%sph_cache, &
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, &
3162 sph_cache=state%sph_cache,clamp_stage=.true.)
3165 state%status=trial_status
3166 state%active=.false.
3167 state%complete=.true.
3168 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3171 call trace_tangent_accumulate_twist(state,xhit,partial_length, &
3175 if (state%has_extra)
then
3179 state%length=state%length+partial_length
3180 state%nstep=state%nstep+1
3181 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_step(partial_length,.true.,.false.)
3182 if (trace_spherical_profile_enabled .and. &
3183 geo_coordinate==geo_spherical)
then
3184 call trace_spherical_profile_add_count(trace_profile_steps,1_8)
3189 if (state%has_extra)
then
3197 state%active=.false.
3198 if (trace_spherical_profile_enabled .and. &
3199 geo_coordinate==geo_spherical)
then
3200 call trace_spherical_profile_add_count( &
3201 trace_profile_boundary_events,1_8)
3203 call trace_tangent_state_finalize_boundary(state,threshold)
3204 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3212 {
if (xprobe(^db)>=xprobmin^db .and. xprobe(^db)<xprobmax^db) point_domain=point_domain+1\}
3213 if (point_domain/=
ndim)
then
3214 call trace_intersect_domain(xold,xprobe,xhit,hit_ok,state%face_id, &
3216 if (.not.hit_ok)
then
3217 call trace_boundary_face_at_point(xold,state%face_id,hit_ok)
3219 state%active=.false.
3223 if (state%has_extra)
then
3228 if (hit_ok)
call trace_tangent_state_finalize_boundary(state, &
3230 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3233 partial_length=trace_segment_length(xold,xhit,h,alpha_hit)
3234 if (partial_length<=100.d0*epsilon(one)*max(one,abs(h)))
then
3238 if (state%has_extra)
then
3244 state%active=.false.
3245 call trace_tangent_state_finalize_boundary(state,threshold)
3246 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3249 h_partial=sign(partial_length,h)
3250 if (state%has_extra)
then
3251 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold,state%igrid, &
3252 h_partial,threshold,kx1,ku1,kv1,xtrial,utrial,vtrial, &
3253 state%status,pold,qold,kp1,kq1,ptrial,qtrial, &
3254 sph_cache=state%sph_cache)
3256 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold,state%igrid, &
3257 h_partial,threshold,kx1,ku1,kv1,xtrial,utrial,vtrial, &
3258 state%status,sph_cache=state%sph_cache)
3261 state%active=.false.
3262 state%complete=.true.
3263 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3266 call trace_tangent_accumulate_twist(state,xhit,partial_length, &
3271 if (state%has_extra)
then
3275 state%length=state%length+partial_length
3278 state%active=.false.
3279 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_step(partial_length,.true.,.false.)
3280 call trace_tangent_state_finalize_boundary(state,threshold)
3281 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3285 if (state%has_extra)
then
3286 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold,state%igrid,h, &
3287 threshold,kx1,ku1,kv1,xtrial,utrial,vtrial,state%status, &
3288 pold,qold,kp1,kq1,ptrial,qtrial,sph_cache=state%sph_cache)
3290 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold,state%igrid,h, &
3291 threshold,kx1,ku1,kv1,xtrial,utrial,vtrial,state%status, &
3292 sph_cache=state%sph_cache)
3295 state%active=.false.
3296 state%complete=.true.
3297 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3302 {
if (xtrial(^db)>=xprobmin^db .and. xtrial(^db)<xprobmax^db) point_domain=point_domain+1\}
3303 if (point_domain==
ndim)
then
3304 igrid_old=state%igrid
3305 call trace_locate_point_with_hint(xtrial,state%igrid,igrid_trial, &
3308 state%active=.false.
3309 state%complete=.true.
3310 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3313 call trace_tangent_accumulate_twist(state,xtrial,abs(h),threshold)
3317 if (state%has_extra)
then
3321 state%igrid=igrid_trial
3322 state%length=state%length+abs(h)
3323 state%nstep=state%nstep+1
3324 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_step(abs(h),.false., &
3325 igrid_trial/=igrid_old)
3326 if (trace_spherical_profile_enabled .and. &
3327 geo_coordinate==geo_spherical)
then
3328 call trace_spherical_profile_add_count(trace_profile_steps,1_8)
3331 call trace_intersect_domain(xold,xtrial,xhit,hit_ok,state%face_id, &
3333 if (.not.hit_ok)
then
3334 call trace_boundary_face_at_point(xold,state%face_id,hit_ok)
3336 state%active=.false.
3340 if (state%has_extra)
then
3345 if (hit_ok)
call trace_tangent_state_finalize_boundary(state, &
3347 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3350 partial_length=trace_segment_length(xold,xhit,h,alpha_hit)
3351 if (partial_length<=100.d0*epsilon(one)*max(one,abs(h)))
then
3355 if (state%has_extra)
then
3361 state%active=.false.
3362 call trace_tangent_state_finalize_boundary(state,threshold)
3363 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3366 h_partial=sign(partial_length,h)
3367 if (state%has_extra)
then
3368 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold,state%igrid, &
3369 h_partial,threshold,kx1,ku1,kv1,xtrial,utrial,vtrial, &
3370 state%status,pold,qold,kp1,kq1,ptrial,qtrial, &
3371 sph_cache=state%sph_cache)
3373 call trace_tangent_rk2_trial_from_rhs(xold,uold,vold,state%igrid, &
3374 h_partial,threshold,kx1,ku1,kv1,xtrial,utrial,vtrial, &
3375 state%status,sph_cache=state%sph_cache)
3378 state%active=.false.
3379 state%complete=.true.
3380 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3383 call trace_tangent_accumulate_twist(state,xhit,partial_length, &
3388 if (state%has_extra)
then
3392 state%length=state%length+partial_length
3395 state%active=.false.
3396 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_step(partial_length,.true.,.false.)
3397 if (trace_spherical_profile_enabled .and. &
3398 geo_coordinate==geo_spherical)
then
3399 call trace_spherical_profile_add_count(trace_profile_boundary_events, &
3402 call trace_tangent_state_finalize_boundary(state,threshold)
3403 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3408 if (state%active .and. state%nstep>=max_steps)
then
3410 state%active=.false.
3411 state%complete=.true.
3412 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_completion(state%status,state%nstep)
3414 if ((.not.state%active) .and. trace_spherical_profile_enabled .and. &
3415 geo_coordinate==geo_spherical)
then
3416 call trace_spherical_profile_note_trace_steps(state%nstep)
3418 end subroutine trace_tangent_state_advance_in_grid
3420 subroutine trace_tangent_state_finalize_boundary(state,threshold)
3421 type(trace_tangent_state),
intent(inout) :: state
3422 double precision,
intent(in) :: threshold
3425 if (trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical) &
3426 call trace_spherical_profile_add_count( &
3427 trace_profile_endpoint_finalizations,1_8)
3429 call trace_endpoint_b_bhat(state%endpoint,state%face_id,state%igrid, &
3430 threshold,state%endpoint_B,state%endpoint_bhat,state%status)
3433 call trace_project_to_perp_bhat(state%u,state%endpoint_bhat, &
3435 call trace_project_to_perp_bhat(state%v,state%endpoint_bhat, &
3437 if (state%has_extra)
then
3438 call trace_project_to_perp_bhat(state%p,state%endpoint_bhat, &
3440 call trace_project_to_perp_bhat(state%q,state%endpoint_bhat, &
3443 state%complete=.true.
3444 end subroutine trace_tangent_state_finalize_boundary
3446 subroutine trace_qperp_prepare_seed_result(seed,field_min,result,igrid, &
3448 double precision,
intent(in) :: seed(
ndim),field_min
3450 integer,
intent(out) :: igrid,status
3452 double precision :: b3(3),bseed_norm
3455 call trace_init_qperp_result(seed,result)
3460 {
if (seed(^db)>=xprobmin^db .and. seed(^db)<xprobmax^db) indomain=indomain+1\}
3461 if (indomain/=
ndim)
then
3463 result%status=status
3467 call trace_debug_locate_point(seed,igrid,status)
3469 result%status=status
3473 call sample_b_at_point(seed,igrid,field_min,b3,status)
3475 result%status=status
3478 result%B_seed=b3(1:
ndim)
3479 bseed_norm=dsqrt(sum(result%B_seed**2))
3480 if (bseed_norm<=zero .or. bseed_norm<field_min)
then
3482 result%status=status
3486 result%bhat_seed=result%B_seed/bseed_norm
3487 call trace_make_perp_basis(b3/bseed_norm,result%u0,result%v0,status)
3489 end subroutine trace_qperp_prepare_seed_result
3491 subroutine trace_qperp_compute_scalars(result,field_min)
3493 double precision,
intent(in) :: field_min
3495 double precision :: bseed_norm,bf_norm,bb_norm,dot_f,dot_b,qtmp
3497 bseed_norm=dsqrt(sum(result%B_seed**2))
3498 bf_norm=dsqrt(sum(result%forward_B**2))
3499 bb_norm=dsqrt(sum(result%backward_B**2))
3500 if (bseed_norm<=zero .or. bf_norm<=zero .or. bb_norm<=zero .or. &
3501 bseed_norm<field_min .or. bf_norm<field_min .or. &
3502 bb_norm<field_min)
then
3507 dot_f=sum(result%u_forward_perp*result%v_forward_perp)
3508 dot_b=sum(result%u_backward_perp*result%v_backward_perp)
3509 result%N2=sum(result%u_forward_perp**2)* &
3510 sum(result%v_backward_perp**2)+ &
3511 sum(result%u_backward_perp**2)* &
3512 sum(result%v_forward_perp**2)-2.d0*dot_f*dot_b
3513 result%bfactor=abs(bf_norm*bb_norm)/(bseed_norm**2)
3514 qtmp=result%N2*result%bfactor
3515 if (qtmp>zero .and. ieee_is_finite(qtmp))
then
3517 result%logqperp=dlog10(qtmp)
3521 result%logqperp0=result%logqperp
3522 result%valid_qperp0=.true.
3525 result%N2=trace_debug_nan()
3526 result%bfactor=trace_debug_nan()
3527 result%qperp=trace_debug_nan()
3528 result%logqperp=trace_debug_nan()
3530 result%valid=.false.
3531 result%qperp0=trace_debug_nan()
3532 result%logqperp0=trace_debug_nan()
3533 result%valid_qperp0=.false.
3536 call trace_qperp_compute_q0_scalars(result,field_min)
3537 end subroutine trace_qperp_compute_scalars
3539 subroutine trace_qperp_compute_q0_scalars(result,field_min)
3541 double precision,
intent(in) :: field_min
3543 double precision :: bseed_norm,bnf,bnb,n2bnd,qtmp
3544 double precision :: uf_face(
ndim),vf_face(
ndim)
3545 double precision :: ub_face(
ndim),vb_face(
ndim)
3546 integer :: status_f,status_b
3548 result%q0=trace_debug_nan()
3549 result%logq0=trace_debug_nan()
3550 result%N2_qperp0=trace_debug_nan()
3551 result%bfactor_qperp0=trace_debug_nan()
3552 result%forward_Bn_q0=trace_debug_nan()
3553 result%backward_Bn_q0=trace_debug_nan()
3554 result%valid_q0=.false.
3557 result%status_q0=result%forward_status
3561 result%status_q0=result%backward_status
3565 bseed_norm=dsqrt(sum(result%B_seed**2))
3566 if (bseed_norm<=zero .or. bseed_norm<field_min)
then
3571 call trace_qperp_project_to_boundary_face(result%u_forward_perp, &
3572 result%forward_B,result%forward_face,uf_face,bnf,status_f)
3573 call trace_qperp_project_to_boundary_face(result%v_forward_perp, &
3574 result%forward_B,result%forward_face,vf_face,bnf,status_f)
3575 call trace_qperp_project_to_boundary_face(result%u_backward_perp, &
3576 result%backward_B,result%backward_face,ub_face,bnb,status_b)
3577 call trace_qperp_project_to_boundary_face(result%v_backward_perp, &
3578 result%backward_B,result%backward_face,vb_face,bnb,status_b)
3580 result%status_q0=status_f
3584 result%status_q0=status_b
3587 if (abs(bnf)<field_min .or. abs(bnb)<field_min)
then
3592 n2bnd=sum(uf_face**2)*sum(vb_face**2)+ &
3593 sum(ub_face**2)*sum(vf_face**2)- &
3594 2.d0*sum(uf_face*vf_face)*sum(ub_face*vb_face)
3595 result%N2_qperp0=abs(n2bnd)
3596 result%bfactor_qperp0=abs(bnf*bnb)/(bseed_norm**2)
3597 result%forward_Bn_q0=bnf
3598 result%backward_Bn_q0=bnb
3599 qtmp=result%N2_qperp0*result%bfactor_qperp0
3600 if (qtmp>zero .and. ieee_is_finite(qtmp))
then
3602 result%logq0=dlog10(qtmp)
3603 result%valid_q0=.true.
3606 result%q0=trace_debug_nan()
3607 result%logq0=trace_debug_nan()
3608 result%valid_q0=.false.
3611 end subroutine trace_qperp_compute_q0_scalars
3613 subroutine trace_qperp_project_to_boundary_face(vec,B,face_id,vec_face, &
3615 double precision,
intent(in) :: vec(
ndim),b(
ndim)
3616 integer,
intent(in) :: face_id
3617 double precision,
intent(out) :: vec_face(
ndim),bn
3618 integer,
intent(out) :: status
3620 double precision :: normal(
ndim),vecn
3626 call trace_face_normal(face_id,normal,ok)
3633 vecn=sum(vec*normal)
3634 vec_face=vec-vecn/bn*b
3636 end subroutine trace_qperp_project_to_boundary_face
3638 subroutine trace_qperp_finalize_from_states(forward_state,backward_state, &
3640 type(trace_tangent_state),
intent(in) :: forward_state,backward_state
3642 double precision,
intent(in) :: field_min
3644 result%forward_endpoint=forward_state%endpoint
3645 result%forward_B=forward_state%endpoint_B
3646 result%forward_bhat=forward_state%endpoint_bhat
3647 result%forward_length=forward_state%length
3648 result%forward_nstep=forward_state%nstep
3649 result%forward_face=forward_state%face_id
3650 result%forward_status=forward_state%status
3651 result%u_forward_perp=forward_state%u_perp
3652 result%v_forward_perp=forward_state%v_perp
3654 result%backward_endpoint=backward_state%endpoint
3655 result%backward_B=backward_state%endpoint_B
3656 result%backward_bhat=backward_state%endpoint_bhat
3657 result%backward_length=backward_state%length
3658 result%backward_nstep=backward_state%nstep
3659 result%backward_face=backward_state%face_id
3660 result%backward_status=backward_state%status
3661 result%u_backward_perp=backward_state%u_perp
3662 result%v_backward_perp=backward_state%v_perp
3665 result%status=forward_state%status
3669 result%status=backward_state%status
3673 call trace_qperp_compute_scalars(result,field_min)
3674 end subroutine trace_qperp_finalize_from_states
3676 subroutine trace_q0_finalize_from_states(forward_state,backward_state, &
3678 type(trace_tangent_state),
intent(in) :: forward_state,backward_state
3680 double precision,
intent(in) :: field_min
3682 result%forward_endpoint=forward_state%endpoint
3683 result%forward_B=forward_state%endpoint_B
3684 result%forward_bhat=forward_state%endpoint_bhat
3685 result%forward_length=forward_state%length
3686 result%forward_nstep=forward_state%nstep
3687 result%forward_face=forward_state%face_id
3688 result%forward_status=forward_state%status
3689 result%u_forward_perp=forward_state%u_perp
3690 result%v_forward_perp=forward_state%v_perp
3692 result%backward_endpoint=backward_state%endpoint
3693 result%backward_B=backward_state%endpoint_B
3694 result%backward_bhat=backward_state%endpoint_bhat
3695 result%backward_length=backward_state%length
3696 result%backward_nstep=backward_state%nstep
3697 result%backward_face=backward_state%face_id
3698 result%backward_status=backward_state%status
3699 result%u_backward_perp=backward_state%u_perp
3700 result%v_backward_perp=backward_state%v_perp
3703 result%status=forward_state%status
3704 result%status_q0=forward_state%status
3708 result%status=backward_state%status
3709 result%status_q0=backward_state%status
3714 call trace_qperp_compute_q0_scalars(result,field_min)
3715 end subroutine trace_q0_finalize_from_states
3717 subroutine trace_spherical_rmin_q_prepare_seed_result(seed,field_min, &
3718 result,igrid,status)
3719 double precision,
intent(in) :: seed(
ndim),field_min
3721 integer,
intent(out) :: igrid,status
3723 double precision :: bcart(3),bhat_cart(3),er(3),etheta(3),ephi(3)
3724 double precision :: radial_tol
3727 call trace_init_qperp_result(seed,result)
3731 if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
then
3733 result%status=status
3734 result%status_q0=status
3739 {
if (seed(^db)>=xprobmin^db .and. seed(^db)<xprobmax^db) indomain=indomain+1\}
3740 if (indomain/=
ndim)
then
3742 result%status=status
3743 result%status_q0=status
3747 call trace_debug_locate_point(seed,igrid,status)
3749 result%status=status
3750 result%status_q0=status
3755 call trace_spherical_sample_b_bhat_cart(seed,igrid,field_min,bcart, &
3758 result%status=status
3759 result%status_q0=status
3762 call trace_spherical_basis(seed,er,etheta,ephi,status)
3764 result%status=status
3765 result%status_q0=status
3768 result%B_seed=bcart(1:
ndim)
3769 result%bhat_seed=bhat_cart(1:
ndim)
3770 radial_tol=100.d0*epsilon(one)*max(one,abs(xprobmin1),abs(xprobmax1))
3773 if (abs(seed(1)-xprobmin1)<=radial_tol .or. &
3774 abs(seed(1)-xprobmax1)<=radial_tol)
then
3775 result%u0=etheta(1:
ndim)
3776 result%v0=ephi(1:
ndim)
3778 call trace_make_perp_basis(bhat_cart,result%u0,result%v0,status)
3780 result%status=status
3781 result%status_q0=status
3786 end subroutine trace_spherical_rmin_q_prepare_seed_result
3788 subroutine trace_spherical_rmin_q_finalize_from_states(forward_state, &
3789 backward_state,result,field_min)
3790 type(trace_tangent_state),
intent(in) :: forward_state,backward_state
3792 double precision,
intent(in) :: field_min
3794 call trace_spherical_radial_q_finalize_from_states(forward_state, &
3795 backward_state,result,field_min)
3797 end subroutine trace_spherical_rmin_q_finalize_from_states
3799 subroutine trace_spherical_radial_q_finalize_from_states(forward_state, &
3800 backward_state,result,field_min)
3801 type(trace_tangent_state),
intent(in) :: forward_state,backward_state
3803 double precision,
intent(in) :: field_min
3805 double precision :: bnf,bnb,frob2,qtmp,logqtmp,bfactor
3806 double precision :: af(2,2),ab(2,2)
3807 integer :: status_f,status_b,status_q
3810 result%forward_endpoint=forward_state%endpoint
3811 result%forward_B=forward_state%endpoint_B
3812 result%forward_bhat=forward_state%endpoint_bhat
3813 result%forward_length=forward_state%length
3814 result%forward_nstep=forward_state%nstep
3815 result%forward_face=forward_state%face_id
3816 result%forward_status=forward_state%status
3817 result%u_forward_perp=forward_state%u
3818 result%v_forward_perp=forward_state%v
3820 result%backward_endpoint=backward_state%endpoint
3821 result%backward_B=backward_state%endpoint_B
3822 result%backward_bhat=backward_state%endpoint_bhat
3823 result%backward_length=backward_state%length
3824 result%backward_nstep=backward_state%nstep
3825 result%backward_face=backward_state%face_id
3826 result%backward_status=backward_state%status
3827 result%u_backward_perp=backward_state%u
3828 result%v_backward_perp=backward_state%v
3830 result%q0=trace_debug_nan()
3831 result%logq0=trace_debug_nan()
3832 result%N2_qperp0=trace_debug_nan()
3833 result%bfactor_qperp0=trace_debug_nan()
3834 result%forward_Bn_q0=trace_debug_nan()
3835 result%backward_Bn_q0=trace_debug_nan()
3836 result%valid_q0=.false.
3839 result%status_q0=forward_state%status
3840 result%status=forward_state%status
3844 result%status_q0=backward_state%status
3845 result%status=backward_state%status
3850 if (.not.trace_spherical_radial_q_face_pair_admitted( &
3851 forward_state%face_id,backward_state%face_id))
then
3856 if (dsqrt(sum(result%B_seed**2))<=zero .or. &
3857 dsqrt(sum(result%B_seed**2))<field_min)
then
3862 call trace_spherical_radial_endpoint_matrix(forward_state,af,bnf,status_f)
3863 result%forward_Bn_q0=bnf
3865 result%status_q0=status_f
3869 call trace_spherical_radial_endpoint_matrix(backward_state,ab,bnb,status_b)
3870 result%backward_Bn_q0=bnb
3872 result%status_q0=status_b
3876 if (abs(bnf)<1.
d-10 .or. abs(bnb)<1.
d-10)
then
3881 call trace_spherical_q_from_endpoint_matrices(af,ab,qtmp,logqtmp, &
3882 frob2,bfactor,valid_q,status_q)
3883 result%N2_qperp0=frob2
3884 result%bfactor_qperp0=bfactor
3885 if (.not.valid_q)
then
3886 result%status_q0=status_q
3891 result%logq0=logqtmp
3892 result%valid_q0=.true.
3894 end subroutine trace_spherical_radial_q_finalize_from_states
3896 logical function trace_spherical_radial_q_face_pair_admitted(face_forward, &
3897 face_backward)
result(is_admitted)
3898 integer,
intent(in) :: face_forward,face_backward
3901 select case (face_forward)
3909 end function trace_spherical_radial_q_face_pair_admitted
3911 subroutine trace_spherical_radial_endpoint_matrix(state,Amat,Bn,status)
3912 type(trace_tangent_state),
intent(in) :: state
3913 double precision,
intent(out) :: amat(2,2),bn
3914 integer,
intent(out) :: status
3916 double precision :: u_face(
ndim),v_face(
ndim)
3917 double precision :: er(3),etheta(3),ephi(3)
3918 double precision :: bn_u,bn_v
3919 integer :: status_u,status_v,basis_status
3925 call trace_spherical_radial_project_to_surface(state%u,state%endpoint_B, &
3926 state%endpoint,state%face_id,u_face,bn_u,status_u)
3932 call trace_spherical_radial_project_to_surface(state%v,state%endpoint_B, &
3933 state%endpoint,state%face_id,v_face,bn_v,status_v)
3942 call trace_spherical_basis(state%endpoint,er,etheta,ephi,basis_status)
3947 amat(1,1)=sum(u_face*etheta(1:
ndim))
3948 amat(2,1)=sum(u_face*ephi(1:
ndim))
3949 amat(1,2)=sum(v_face*etheta(1:
ndim))
3950 amat(2,2)=sum(v_face*ephi(1:
ndim))
3953 end subroutine trace_spherical_radial_endpoint_matrix
3955 subroutine trace_spherical_radial_project_to_surface(vec,B,x,face_id, &
3957 double precision,
intent(in) :: vec(
ndim),b(
ndim),x(
ndim)
3958 integer,
intent(in) :: face_id
3959 double precision,
intent(out) :: vec_face(
ndim),bn
3960 integer,
intent(out) :: status
3962 double precision :: er(3),etheta(3),ephi(3),normal(
ndim),vecn
3963 double precision :: bhat(
ndim),bnorm
3968 if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
return
3971 call trace_spherical_basis(x,er,etheta,ephi,status)
3973 select case (face_id)
3982 bnorm=dsqrt(sum(b**2))
3983 if (bnorm<=smalldouble)
then
3989 if (abs(bn)<=smalldouble)
then
3993 vecn=sum(vec*normal)
3994 vec_face=vec-vecn/bn*bhat
3997 end subroutine trace_spherical_radial_project_to_surface
3999 subroutine trace_spherical_qperp_prepare_seed_result(seed,field_min, &
4000 result,igrid,status)
4001 double precision,
intent(in) :: seed(
ndim),field_min
4003 integer,
intent(out) :: igrid,status
4005 double precision :: bcart(3),bhat_cart(3)
4008 call trace_init_qperp_result(seed,result)
4012 if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
then
4014 result%status=status
4019 {
if (seed(^db)>=xprobmin^db .and. seed(^db)<xprobmax^db) indomain=indomain+1\}
4020 if (indomain/=
ndim)
then
4022 result%status=status
4026 call trace_debug_locate_point(seed,igrid,status)
4028 result%status=status
4033 call trace_spherical_sample_b_bhat_cart(seed,igrid,field_min,bcart, &
4036 result%status=status
4039 result%B_seed=bcart(1:
ndim)
4040 result%bhat_seed=bhat_cart(1:
ndim)
4041 call trace_make_perp_basis(bhat_cart,result%u0,result%v0,status)
4044 end subroutine trace_spherical_qperp_prepare_seed_result
4046 subroutine trace_spherical_qperp_finalize_from_states(forward_state, &
4047 backward_state,result,field_min)
4048 type(trace_tangent_state),
intent(in) :: forward_state,backward_state
4050 double precision,
intent(in) :: field_min
4052 result%forward_endpoint=forward_state%endpoint
4053 result%forward_B=forward_state%endpoint_B
4054 result%forward_bhat=forward_state%endpoint_bhat
4055 result%forward_length=forward_state%length
4056 result%forward_nstep=forward_state%nstep
4057 result%forward_face=forward_state%face_id
4058 result%forward_status=forward_state%status
4059 result%u_forward_perp=forward_state%u_perp
4060 result%v_forward_perp=forward_state%v_perp
4062 result%backward_endpoint=backward_state%endpoint
4063 result%backward_B=backward_state%endpoint_B
4064 result%backward_bhat=backward_state%endpoint_bhat
4065 result%backward_length=backward_state%length
4066 result%backward_nstep=backward_state%nstep
4067 result%backward_face=backward_state%face_id
4068 result%backward_status=backward_state%status
4069 result%u_backward_perp=backward_state%u_perp
4070 result%v_backward_perp=backward_state%v_perp
4073 result%status=forward_state%status
4074 result%status_qperp0=forward_state%status
4078 result%status=backward_state%status
4079 result%status_qperp0=backward_state%status
4083 call trace_spherical_qperp_compute_from_states(result,field_min)
4084 end subroutine trace_spherical_qperp_finalize_from_states
4086 subroutine trace_spherical_qperp_compute_from_states(result,field_min)
4088 double precision,
intent(in) :: field_min
4091 double precision :: forward_bhat3(3),backward_bhat3(3)
4092 double precision :: af(2,2),ab(2,2)
4093 double precision :: bseed_norm,bf_norm,bb_norm,frob2,qtmp,logqtmp,bfactor
4094 integer :: status_f,status_b,status_q
4097 result%qperp=trace_debug_nan()
4098 result%logqperp=trace_debug_nan()
4099 result%N2=trace_debug_nan()
4100 result%bfactor=trace_debug_nan()
4101 result%qperp0=trace_debug_nan()
4102 result%logqperp0=trace_debug_nan()
4103 result%N2_qperp0=trace_debug_nan()
4104 result%bfactor_qperp0=trace_debug_nan()
4105 result%valid=.false.
4106 result%valid_qperp0=.false.
4114 bseed_norm=dsqrt(sum(result%B_seed**2))
4115 bf_norm=dsqrt(sum(result%forward_B**2))
4116 bb_norm=dsqrt(sum(result%backward_B**2))
4117 if (bseed_norm<=zero .or. bf_norm<=zero .or. bb_norm<=zero .or. &
4118 bseed_norm<field_min .or. bf_norm<field_min .or. &
4119 bb_norm<field_min)
then
4127 forward_bhat3(1:
ndim)=result%forward_bhat
4128 backward_bhat3(1:
ndim)=result%backward_bhat
4129 call trace_make_perp_basis(forward_bhat3,f1,f2,status_f)
4130 call trace_make_perp_basis(backward_bhat3,b1,b2,status_b)
4132 result%status=status_f
4133 result%status_qperp0=status_f
4137 result%status=status_b
4138 result%status_qperp0=status_b
4142 af(1,1)=sum(result%u_forward_perp*f1)
4143 af(2,1)=sum(result%u_forward_perp*f2)
4144 af(1,2)=sum(result%v_forward_perp*f1)
4145 af(2,2)=sum(result%v_forward_perp*f2)
4146 ab(1,1)=sum(result%u_backward_perp*b1)
4147 ab(2,1)=sum(result%u_backward_perp*b2)
4148 ab(1,2)=sum(result%v_backward_perp*b1)
4149 ab(2,2)=sum(result%v_backward_perp*b2)
4151 call trace_spherical_q_from_endpoint_matrices(af,ab,qtmp,logqtmp, &
4152 frob2,bfactor,valid_q,status_q)
4154 result%bfactor=bfactor
4155 result%N2_qperp0=frob2
4156 result%bfactor_qperp0=bfactor
4157 if (.not.valid_q)
then
4158 result%status=status_q
4159 result%status_qperp0=status_q
4164 result%logqperp=logqtmp
4168 result%logqperp0=result%logqperp
4169 result%valid_qperp0=.true.
4171 end subroutine trace_spherical_qperp_compute_from_states
4173 subroutine trace_spherical_q_from_endpoint_matrices(Af,Ab,qval,logq, &
4174 frob2,bfactor,valid,status)
4175 double precision,
intent(in) :: af(2,2),ab(2,2)
4176 double precision,
intent(out) :: qval,logq,frob2,bfactor
4177 logical,
intent(out) :: valid
4178 integer,
intent(out) :: status
4180 double precision :: dmat(2,2),detab,detd,q_tol,det_tol
4182 qval=trace_debug_nan()
4183 logq=trace_debug_nan()
4184 frob2=trace_debug_nan()
4185 bfactor=trace_debug_nan()
4189 detab=ab(1,1)*ab(2,2)-ab(1,2)*ab(2,1)
4191 if (.not.ieee_is_finite(detab) .or. abs(detab)<=det_tol)
then
4196 dmat(1,1)=(af(1,1)*ab(2,2)-af(1,2)*ab(2,1))/detab
4197 dmat(1,2)=(-af(1,1)*ab(1,2)+af(1,2)*ab(1,1))/detab
4198 dmat(2,1)=(af(2,1)*ab(2,2)-af(2,2)*ab(2,1))/detab
4199 dmat(2,2)=(-af(2,1)*ab(1,2)+af(2,2)*ab(1,1))/detab
4200 detd=dmat(1,1)*dmat(2,2)-dmat(1,2)*dmat(2,1)
4203 if (.not.ieee_is_finite(detd) .or. abs(detd)<=det_tol)
then
4208 qval=frob2/abs(detd)
4210 if (qval>zero .and. ieee_is_finite(qval))
then
4211 if (qval<2.d0-q_tol)
then
4220 qval=trace_debug_nan()
4221 logq=trace_debug_nan()
4226 end subroutine trace_spherical_q_from_endpoint_matrices
4228 subroutine trace_spherical_basis(x,er,etheta,ephi,status)
4229 double precision,
intent(in) :: x(
ndim)
4230 double precision,
intent(out) :: er(3),etheta(3),ephi(3)
4231 integer,
intent(out) :: status
4233 double precision :: theta,phi,sint,cost,sinp,cosp
4239 if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
return
4242 if (.not.trace_spherical_metric_ok(x))
then
4252 er=(/ sint*cosp,sint*sinp,cost /)
4253 etheta=(/ cost*cosp,cost*sinp,-sint /)
4254 ephi=(/ -sinp,cosp,zero /)
4257 end subroutine trace_spherical_basis
4259 subroutine trace_spherical_coord_to_cart(x,xcart,status)
4260 double precision,
intent(in) :: x(
ndim)
4261 double precision,
intent(out) :: xcart(3)
4262 integer,
intent(out) :: status
4264 double precision :: r,theta,phi,sint
4268 if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
return
4271 if (.not.trace_spherical_metric_ok(x))
then
4279 xcart(1)=r*sint*dcos(phi)
4280 xcart(2)=r*sint*dsin(phi)
4281 xcart(3)=r*dcos(theta)
4284 end subroutine trace_spherical_coord_to_cart
4286 subroutine trace_cart_to_spherical_coord(xcart,x,status)
4287 double precision,
intent(in) :: xcart(3)
4288 double precision,
intent(out) :: x(
ndim)
4289 integer,
intent(out) :: status
4291 double precision :: r,rho,phi,twopi
4295 if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
return
4298 r=dsqrt(sum(xcart**2))
4299 if (r<=100.d0*epsilon(one))
then
4303 rho=dsqrt(xcart(1)**2+xcart(2)**2)
4304 phi=datan2(xcart(2),xcart(1))
4305 twopi=2.d0*dacos(-one)
4306 if (phi<xprobmin3 .and. phi+twopi<xprobmax3) phi=phi+twopi
4307 if (phi>=xprobmax3 .and. phi-twopi>=xprobmin3) phi=phi-twopi
4309 x(2)=datan2(rho,xcart(3))
4313 end subroutine trace_cart_to_spherical_coord
4315 subroutine trace_spherical_interp_ctx_build(x,igrid,ctx,status)
4316 double precision,
intent(in) :: x(
ndim)
4317 integer,
intent(in) :: igrid
4318 type(trace_sph_interp_ctx),
intent(out) :: ctx
4319 integer,
intent(out) :: status
4321 double precision :: xd^
d,dxc^
d
4322 double precision :: t0
4323 integer :: ixi^
l,ixbl^
d
4325 if (trace_spherical_profile_enabled)
then
4326 call trace_spherical_profile_add_count(trace_profile_context_requests, &
4328 call trace_spherical_profile_add_count( &
4329 trace_profile_full_context_builds,1_8)
4330 t0=trace_spherical_profile_time()
4350 ctx%bcorner_valid=.false.
4353 if (
ndim/=3 .or. geo_coordinate/=geo_spherical .or. igrid<0)
then
4354 if (trace_spherical_profile_enabled)
then
4355 call trace_spherical_profile_add_count(trace_profile_context_failures, &
4357 call trace_spherical_profile_add_time(trace_profile_time_context, &
4358 trace_spherical_profile_time()-t0)
4365 if (.not.trace_spherical_metric_ok(x))
then
4367 if (trace_spherical_profile_enabled)
then
4368 call trace_spherical_profile_add_count(trace_profile_context_failures, &
4370 call trace_spherical_profile_add_time(trace_profile_time_context, &
4371 trace_spherical_profile_time()-t0)
4377 call trace_interp_weights_block(x,igrid,ixi^
l,ixbl^
d,xd^
d,dxc^
d,status)
4379 if (trace_spherical_profile_enabled)
then
4380 call trace_spherical_profile_add_count(trace_profile_context_failures, &
4382 call trace_spherical_profile_add_time(trace_profile_time_context, &
4383 trace_spherical_profile_time()-t0)
4388 call trace_spherical_interp_ctx_fill(x,igrid,ixbl^
d,xd^
d,dxc^
d,ctx, &
4391 call trace_spherical_interp_ctx_load_bcorners(ctx,status)
4393 if (trace_spherical_profile_enabled)
then
4395 call trace_spherical_profile_add_count(trace_profile_context_failures, &
4398 call trace_spherical_profile_add_time(trace_profile_time_context, &
4399 trace_spherical_profile_time()-t0)
4402 end subroutine trace_spherical_interp_ctx_build
4404 subroutine trace_spherical_interp_ctx_build_cached(x,igrid,cache,ctx,status)
4405 double precision,
intent(in) :: x(
ndim)
4406 integer,
intent(in) :: igrid
4407 type(trace_sph_interp_ctx),
intent(inout) :: cache
4408 type(trace_sph_interp_ctx),
intent(out) :: ctx
4409 integer,
intent(out) :: status
4411 double precision :: xd^
d,dxc^
d
4412 double precision :: t0
4413 integer :: ixi^
l,ixbl^
d
4414 logical :: same_cell
4416 if (trace_spherical_profile_enabled)
then
4417 call trace_spherical_profile_add_count(trace_profile_context_requests, &
4419 t0=trace_spherical_profile_time()
4423 if (
ndim/=3 .or. geo_coordinate/=geo_spherical .or. igrid<0)
then
4424 if (trace_spherical_profile_enabled)
then
4425 call trace_spherical_profile_add_count(trace_profile_context_failures, &
4427 call trace_spherical_profile_add_time(trace_profile_time_context, &
4428 trace_spherical_profile_time()-t0)
4430 call trace_spherical_interp_ctx_build(x,igrid,ctx,status)
4435 if (cache%valid .and. cache%igrid==igrid)
then
4437 call trace_interp_weights_block_near(x,igrid,ixi^
l,cache%ixbl, &
4438 ixbl^
d,xd^
d,dxc^
d,status)
4440 call trace_spherical_interp_ctx_fill(x,igrid,ixbl^
d,xd^
d,dxc^
d, &
4443 same_cell=(ixbl1==cache%ixbl(1) .and. ixbl2==cache%ixbl(2) .and. &
4444 ixbl3==cache%ixbl(3))
4445 if (same_cell .and. cache%bcorner_valid)
then
4446 ctx%bcorner_valid=.true.
4447 ctx%bcorner=cache%bcorner
4448 if (trace_spherical_profile_enabled)
then
4449 call trace_spherical_profile_add_count( &
4450 trace_profile_b_corner_hits,1_8)
4453 call trace_spherical_interp_ctx_load_bcorners(ctx,status)
4458 if (trace_spherical_profile_enabled)
then
4460 call trace_spherical_profile_add_count( &
4461 trace_profile_same_cell_hits,1_8)
4463 call trace_spherical_profile_add_count( &
4464 trace_profile_same_grid_hits,1_8)
4466 call trace_spherical_profile_add_time(trace_profile_time_context, &
4467 trace_spherical_profile_time()-t0)
4469 else if (trace_spherical_profile_enabled)
then
4470 call trace_spherical_profile_add_count(trace_profile_context_failures, &
4472 call trace_spherical_profile_add_time(trace_profile_time_context, &
4473 trace_spherical_profile_time()-t0)
4477 else if (cache%valid .and. trace_spherical_profile_enabled)
then
4478 call trace_spherical_profile_add_count(trace_profile_cache_invalidations, &
4482 if (trace_spherical_profile_enabled)
then
4483 call trace_spherical_profile_add_time(trace_profile_time_context, &
4484 trace_spherical_profile_time()-t0)
4486 call trace_spherical_interp_ctx_build(x,igrid,ctx,status)
4489 end subroutine trace_spherical_interp_ctx_build_cached
4491 subroutine trace_spherical_interp_ctx_fill(x,igrid,ixbl^D,xd^D,dxc^D,ctx, &
4493 double precision,
intent(in) :: x(
ndim)
4494 integer,
intent(in) :: igrid,ixbl^
d
4495 double precision,
intent(in) :: xd^
d,dxc^
d
4496 type(trace_sph_interp_ctx),
intent(out) :: ctx
4497 integer,
intent(out) :: status
4499 if (trace_spherical_profile_enabled)
then
4500 call trace_spherical_profile_add_count(trace_profile_hlocal_evals,1_8)
4520 ctx%bcorner_valid=.false.
4523 if (
ndim/=3 .or. geo_coordinate/=geo_spherical .or. igrid<0)
return
4528 ctx%ixbl=(/ixbl1,ixbl2,ixbl3/)
4529 ctx%xd=(/xd1,xd2,xd3/)
4530 ctx%dxc=(/dxc1,dxc2,dxc3/)
4538 ctx%dxloc(1)=min(abs(ps(igrid)%dx(ixbl1,ixbl2,ixbl3,1)), &
4539 abs(ps(igrid)%dx(ixbl1+1,ixbl2,ixbl3,1)))
4540 ctx%dxloc(2)=min(abs(ps(igrid)%dx(ixbl1,ixbl2,ixbl3,2)), &
4541 abs(ps(igrid)%dx(ixbl1,ixbl2+1,ixbl3,2)))
4542 ctx%dxloc(3)=min(abs(ps(igrid)%dx(ixbl1,ixbl2,ixbl3,3)), &
4543 abs(ps(igrid)%dx(ixbl1,ixbl2,ixbl3+1,3)))
4544 ctx%dxloc=max(ctx%dxloc,smalldouble)
4549 ctx%sin_theta=dsin(ctx%theta)
4550 ctx%cos_theta=dcos(ctx%theta)
4551 ctx%sin_phi=dsin(ctx%phi)
4552 ctx%cos_phi=dcos(ctx%phi)
4553 ctx%rsin_theta=ctx%r*ctx%sin_theta
4554 if (ctx%r<=smalldouble .or. abs(ctx%sin_theta)<=smalldouble)
then
4559 ctx%h_local=trace_spherical_cell_scale_from_widths(ctx%r, &
4560 ctx%sin_theta,ctx%dxloc)
4561 ctx%h_local=max(ctx%h_local,smalldouble)
4565 end subroutine trace_spherical_interp_ctx_fill
4567 subroutine trace_spherical_interp_ctx_load_bcorners(ctx,status)
4568 type(trace_sph_interp_ctx),
intent(inout) :: ctx
4569 integer,
intent(out) :: status
4571 integer :: i1,i2,i3,igrid,ix1,ix2,ix3
4574 if (.not.ctx%valid)
return
4575 if (ctx%bcorner_valid)
then
4576 if (trace_spherical_profile_enabled)
then
4577 call trace_spherical_profile_add_count(trace_profile_b_corner_hits, &
4583 if (.not.
b0field .and. .not.
allocated(iw_mag))
return
4594 if (
allocated(iw_mag))
then
4595 ctx%bcorner(i1,i2,i3,1:3)= &
4596 ps(igrid)%w(ix1,ix2,ix3,iw_mag(1:3))
4599 ctx%bcorner(i1,i2,i3,1:3)= &
4600 ctx%bcorner(i1,i2,i3,1:3) &
4601 +ps(igrid)%B0(ix1,ix2,ix3,1:3,0)
4606 ctx%bcorner_valid=.true.
4607 if (trace_spherical_profile_enabled)
then
4608 call trace_spherical_profile_add_count(trace_profile_b_corner_loads, &
4613 end subroutine trace_spherical_interp_ctx_load_bcorners
4615 double precision function trace_spherical_effective_step_ctx(ds,ctx) &
4617 double precision,
intent(in) :: ds
4618 type(trace_sph_interp_ctx),
intent(in) :: ctx
4620 double precision :: step_cap,t0
4622 if (trace_spherical_profile_enabled) t0=trace_spherical_profile_time()
4625 if (.not.ctx%valid)
then
4626 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4627 trace_profile_time_step,trace_spherical_profile_time()-t0)
4631 if (ctx%h_local<=zero)
then
4632 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4633 trace_profile_time_step,trace_spherical_profile_time()-t0)
4636 select case (trace_step_control_mode)
4637 case (trace_step_control_cell_fraction)
4638 ds_eff=min(step_cap,trace_step_fraction*ctx%h_local)
4639 if (trace_step_min>zero) ds_eff=max(ds_eff,min(trace_step_min,step_cap))
4641 ds_eff=min(step_cap,ctx%h_local)
4643 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4644 trace_profile_time_step,trace_spherical_profile_time()-t0)
4645 end function trace_spherical_effective_step_ctx
4647 subroutine trace_spherical_sample_bsph_ctx(ctx,threshold,Bsph,status)
4648 type(trace_sph_interp_ctx),
intent(in) :: ctx
4649 double precision,
intent(in) :: threshold
4650 double precision,
intent(out) :: bsph(3)
4651 integer,
intent(out) :: status
4653 double precision :: b2,weight
4654 double precision :: t0
4655 integer :: i1,i2,i3,j
4657 if (trace_spherical_profile_enabled)
then
4658 call trace_spherical_profile_add_count(trace_profile_b_samples,1_8)
4659 t0=trace_spherical_profile_time()
4664 if (.not.ctx%valid)
then
4665 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4666 trace_profile_time_b_interp,trace_spherical_profile_time()-t0)
4669 if (.not.ctx%bcorner_valid)
then
4670 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4671 trace_profile_time_b_interp,trace_spherical_profile_time()-t0)
4679 weight=ctx%w(i1,1)*ctx%w(i2,2)*ctx%w(i3,3)
4681 bsph(j)=bsph(j)+ctx%bcorner(i1,i2,i3,j)*weight
4687 if (b2<=zero .or. dsqrt(b2)<threshold)
then
4689 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4690 trace_profile_time_b_interp,trace_spherical_profile_time()-t0)
4694 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4695 trace_profile_time_b_interp,trace_spherical_profile_time()-t0)
4697 end subroutine trace_spherical_sample_bsph_ctx
4699 subroutine trace_spherical_sample_b_bhat_cart_ctx(ctx,threshold,Bcart, &
4701 type(trace_sph_interp_ctx),
intent(in) :: ctx
4702 double precision,
intent(in) :: threshold
4703 double precision,
intent(out) :: bcart(3),bhat_cart(3)
4704 integer,
intent(out) :: status
4706 double precision :: bsph(3),bnorm
4710 call trace_spherical_sample_bsph_ctx(ctx,threshold,bsph,status)
4713 bcart(1)=bsph(1)*ctx%sin_theta*ctx%cos_phi &
4714 +bsph(2)*ctx%cos_theta*ctx%cos_phi &
4715 -bsph(3)*ctx%sin_phi
4716 bcart(2)=bsph(1)*ctx%sin_theta*ctx%sin_phi &
4717 +bsph(2)*ctx%cos_theta*ctx%sin_phi &
4718 +bsph(3)*ctx%cos_phi
4719 bcart(3)=bsph(1)*ctx%cos_theta-bsph(2)*ctx%sin_theta
4720 bnorm=dsqrt(sum(bcart**2))
4721 if (bnorm<=zero .or. bnorm<threshold)
then
4725 bhat_cart=bcart/bnorm
4727 end subroutine trace_spherical_sample_b_bhat_cart_ctx
4729 subroutine trace_spherical_sample_cached_curlb_ctx(ctx,curlB,status)
4730 type(trace_sph_interp_ctx),
intent(in) :: ctx
4731 double precision,
intent(out) :: curlb(3)
4732 integer,
intent(out) :: status
4734 double precision :: weight
4735 double precision :: t0
4736 integer :: i1,i2,i3,j,igrid,ix1,ix2,ix3
4738 if (trace_spherical_profile_enabled)
then
4739 call trace_spherical_profile_add_count(trace_profile_curl_samples,1_8)
4740 t0=trace_spherical_profile_time()
4745 if (.not.ctx%valid)
then
4746 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4747 trace_profile_time_curl_interp,trace_spherical_profile_time()-t0)
4750 if (.not.trace_spherical_curl_cache_ready)
then
4751 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4752 trace_profile_time_curl_interp,trace_spherical_profile_time()-t0)
4755 if (.not.
allocated(trace_spherical_curl_cache))
then
4756 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4757 trace_profile_time_curl_interp,trace_spherical_profile_time()-t0)
4761 if (igrid>
size(trace_spherical_curl_cache))
then
4762 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4763 trace_profile_time_curl_interp,trace_spherical_profile_time()-t0)
4766 if (.not.trace_spherical_curl_cache(igrid)%ready)
then
4767 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4768 trace_profile_time_curl_interp,trace_spherical_profile_time()-t0)
4771 if (.not.
allocated(trace_spherical_curl_cache(igrid)%current))
then
4772 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4773 trace_profile_time_curl_interp,trace_spherical_profile_time()-t0)
4784 weight=ctx%w(i1,1)*ctx%w(i2,2)*ctx%w(i3,3)
4786 curlb(j)=curlb(j)+ &
4787 trace_spherical_curl_cache(igrid)%current(ix1,ix2,ix3,j) &
4794 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4795 trace_profile_time_curl_interp,trace_spherical_profile_time()-t0)
4797 end subroutine trace_spherical_sample_cached_curlb_ctx
4799 subroutine trace_spherical_sample_bhat_gradbhat_covariant_ctx(ctx, &
4800 threshold,bhat_cart,grad_bhat_cart,status)
4801 type(trace_sph_interp_ctx),
intent(in) :: ctx
4802 double precision,
intent(in) :: threshold
4803 double precision,
intent(out) :: bhat_cart(3),grad_bhat_cart(3,3)
4804 integer,
intent(out) :: status
4806 double precision :: dw(0:1,3),weight,bnorm,projected
4807 double precision :: bsph(3),bhat_sph(3),dbdq(3,3),dbhatdq(3,3)
4808 double precision :: a_local(3,3),e(3,3)
4809 double precision :: t0
4810 integer :: i1,i2,i3,j
4812 if (trace_spherical_profile_enabled)
then
4813 call trace_spherical_profile_add_count(trace_profile_grad_samples,1_8)
4814 t0=trace_spherical_profile_time()
4820 if (.not.ctx%valid)
then
4821 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4822 trace_profile_time_grad_bhat,trace_spherical_profile_time()-t0)
4825 if (.not.ctx%bcorner_valid)
then
4827 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4828 trace_profile_time_grad_bhat,trace_spherical_profile_time()-t0)
4833 dw(0,1)=-one/ctx%dxc(1)
4834 dw(1,1)= one/ctx%dxc(1)
4835 dw(0,2)=-one/ctx%dxc(2)
4836 dw(1,2)= one/ctx%dxc(2)
4837 dw(0,3)=-one/ctx%dxc(3)
4838 dw(1,3)= one/ctx%dxc(3)
4845 weight=ctx%w(i1,1)*ctx%w(i2,2)*ctx%w(i3,3)
4846 bsph(1:3)=bsph(1:3)+ctx%bcorner(i1,i2,i3,1:3)*weight
4847 dbdq(1:3,1)=dbdq(1:3,1)+ctx%bcorner(i1,i2,i3,1:3)* &
4848 dw(i1,1)*ctx%w(i2,2)*ctx%w(i3,3)
4849 dbdq(1:3,2)=dbdq(1:3,2)+ctx%bcorner(i1,i2,i3,1:3)* &
4850 ctx%w(i1,1)*dw(i2,2)*ctx%w(i3,3)
4851 dbdq(1:3,3)=dbdq(1:3,3)+ctx%bcorner(i1,i2,i3,1:3)* &
4852 ctx%w(i1,1)*ctx%w(i2,2)*dw(i3,3)
4857 bnorm=dsqrt(sum(bsph**2))
4858 if (bnorm<=zero .or. bnorm<threshold)
then
4860 if (trace_spherical_profile_enabled)
call trace_spherical_profile_add_time( &
4861 trace_profile_time_grad_bhat,trace_spherical_profile_time()-t0)
4867 projected=sum(bhat_sph*dbdq(1:3,j))
4868 dbhatdq(1:3,j)=(dbdq(1:3,j)-bhat_sph(1:3)*projected)/bnorm
4871 e(1:3,1)=(/ctx%sin_theta*ctx%cos_phi, &
4872 ctx%sin_theta*ctx%sin_phi,ctx%cos_theta/)
4873 e(1:3,2)=(/ctx%cos_theta*ctx%cos_phi, &
4874 ctx%cos_theta*ctx%sin_phi,-ctx%sin_theta/)
4875 e(1:3,3)=(/-ctx%sin_phi,ctx%cos_phi,zero/)
4876 bhat_cart=bhat_sph(1)*e(1:3,1)+bhat_sph(2)*e(1:3,2) &
4877 +bhat_sph(3)*e(1:3,3)
4879 a_local(1:3,1)=dbhatdq(1:3,1)
4880 a_local(1,2)=(dbhatdq(1,2)-bhat_sph(2))/ctx%r
4881 a_local(2,2)=(dbhatdq(2,2)+bhat_sph(1))/ctx%r
4882 a_local(3,2)= dbhatdq(3,2)/ctx%r
4883 a_local(1,3)=(dbhatdq(1,3)-ctx%sin_theta*bhat_sph(3))/ctx%rsin_theta
4884 a_local(2,3)=(dbhatdq(2,3)-ctx%cos_theta*bhat_sph(3))/ctx%rsin_theta
4885 a_local(3,3)=(dbhatdq(3,3)+ctx%sin_theta*bhat_sph(1) &
4886 +ctx%cos_theta*bhat_sph(2))/ctx%rsin_theta
4888 grad_bhat_cart=matmul(e,matmul(a_local,transpose(e)))
4890 if (trace_spherical_profile_enabled)
then
4891 call trace_spherical_profile_add_count(trace_profile_grad_success,1_8)
4892 call trace_spherical_profile_add_time(trace_profile_time_grad_bhat, &
4893 trace_spherical_profile_time()-t0)
4896 end subroutine trace_spherical_sample_bhat_gradbhat_covariant_ctx
4898 subroutine get_k_spherical_ctx(ctx,K,ftype,b_min,field_ok)
4899 type(trace_sph_interp_ctx),
intent(in) :: ctx
4900 double precision,
intent(out) :: k(
ndim)
4901 character(len=std_len),
intent(in) :: ftype
4902 double precision,
intent(in),
optional :: b_min
4903 logical,
intent(out),
optional :: field_ok
4905 double precision :: b(3),ftotal,field_min
4906 logical :: valid_field
4911 if (ftype/=
'Bfield')
then
4912 if (
present(field_ok)) field_ok=.false.
4915 call trace_spherical_sample_bsph_ctx(ctx,zero,b,status)
4917 if (
present(field_ok)) field_ok=.false.
4920 ftotal=dsqrt(sum(b**2))
4921 field_min=smalldouble
4922 if (
present(b_min)) field_min=max(b_min,zero)
4923 valid_field=ftotal>zero .and. ftotal>=field_min
4924 if (
present(field_ok)) field_ok=valid_field
4925 if (.not.valid_field)
return
4929 k(2)=b(2)/(ctx%r*ftotal)
4930 k(3)=b(3)/(ctx%rsin_theta*ftotal)
4932 end subroutine get_k_spherical_ctx
4934 subroutine trace_spherical_sample_b_bhat_cart(x,igrid,threshold,Bcart, &
4936 double precision,
intent(in) :: x(
ndim),threshold
4937 integer,
intent(in) :: igrid
4938 double precision,
intent(out) :: bcart(3),bhat_cart(3)
4939 integer,
intent(out) :: status
4941 type(trace_sph_interp_ctx) :: ctx
4946 if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
return
4949 call trace_spherical_interp_ctx_build(x,igrid,ctx,status)
4951 call trace_spherical_sample_b_bhat_cart_ctx(ctx,threshold,bcart, &
4954 end subroutine trace_spherical_sample_b_bhat_cart
4956 subroutine trace_spherical_sample_bhat_gradbhat_covariant(x,igrid, &
4957 threshold,bhat_cart,grad_bhat_cart,status)
4958 double precision,
intent(in) :: x(
ndim),threshold
4959 integer,
intent(in) :: igrid
4960 double precision,
intent(out) :: bhat_cart(3),grad_bhat_cart(3,3)
4961 integer,
intent(out) :: status
4963 type(trace_sph_interp_ctx) :: ctx
4968 if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
return
4971 call trace_spherical_interp_ctx_build(x,igrid,ctx,status)
4973 call trace_spherical_sample_bhat_gradbhat_covariant_ctx(ctx,threshold, &
4974 bhat_cart,grad_bhat_cart,status)
4976 end subroutine trace_spherical_sample_bhat_gradbhat_covariant
4978 subroutine trace_spherical_sample_bhat_gradbhat_cartfd(x,igrid,threshold, &
4979 bhat,grad_bhat,status)
4980 double precision,
intent(in) :: x(
ndim),threshold
4981 integer,
intent(in) :: igrid
4982 double precision,
intent(out) :: bhat(3),grad_bhat(3,3)
4983 integer,
intent(out) :: status
4985 double precision :: xcart(3),xplus_cart(3),xminus_cart(3)
4986 double precision :: xplus(
ndim),xminus(
ndim),bplus(3),bminus(3)
4987 double precision :: btmp(3),eps
4988 integer :: j,igrid_plus,igrid_minus,status_plus,status_minus
4993 if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
return
4996 call trace_spherical_sample_b_bhat_cart(x,igrid,threshold,btmp,bhat, &
4999 call trace_spherical_coord_to_cart(x,xcart,status)
5002 eps=max(1.
d-8*max(one,abs(x(1))), &
5003 0.01d0*trace_spherical_physical_cell_scale(x,igrid))
5007 xplus_cart(j)=xplus_cart(j)+eps
5008 xminus_cart(j)=xminus_cart(j)-eps
5011 call trace_cart_to_spherical_coord(xplus_cart,xplus,status_plus)
5013 call trace_locate_point_with_hint(xplus,igrid,igrid_plus,status_plus)
5016 call trace_spherical_sample_b_bhat_cart(xplus,igrid_plus,threshold, &
5017 btmp,bplus,status_plus)
5021 call trace_cart_to_spherical_coord(xminus_cart,xminus,status_minus)
5023 call trace_locate_point_with_hint(xminus,igrid,igrid_minus, &
5027 call trace_spherical_sample_b_bhat_cart(xminus,igrid_minus,threshold, &
5028 btmp,bminus,status_minus)
5033 grad_bhat(:,j)=(bplus-bminus)/(2.d0*eps)
5035 grad_bhat(:,j)=(bplus-bhat)/eps
5037 grad_bhat(:,j)=(bhat-bminus)/eps
5045 end subroutine trace_spherical_sample_bhat_gradbhat_cartfd
5047 subroutine trace_spherical_bhat_cart_to_rhs(x,bhat_cart,kx,status)
5048 double precision,
intent(in) :: x(
ndim),bhat_cart(3)
5049 double precision,
intent(out) :: kx(
ndim)
5050 integer,
intent(out) :: status
5052 double precision :: er(3),etheta(3),ephi(3),r,sint
5056 if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
return
5059 call trace_spherical_basis(x,er,etheta,ephi,status)
5063 if (r<=smalldouble .or. abs(sint)<=smalldouble)
then
5067 kx(1)=sum(bhat_cart*er)
5068 kx(2)=sum(bhat_cart*etheta)/r
5069 kx(3)=sum(bhat_cart*ephi)/(r*sint)
5072 end subroutine trace_spherical_bhat_cart_to_rhs
5074 subroutine trace_spherical_endpoint_b_bhat(x,face_id,igrid,threshold,B, &
5076 double precision,
intent(in) :: x(
ndim),threshold
5077 integer,
intent(in) :: face_id,igrid
5078 double precision,
intent(out) :: b(
ndim),bhat(
ndim)
5079 integer,
intent(out) :: status
5081 double precision :: xprobe(
ndim),bcart(3),bhat_cart(3)
5082 integer :: normal_dim,sample_igrid
5087 if (
ndim/=3 .or. geo_coordinate/=geo_spherical .or. igrid<0)
then
5091 if (.not.trace_face_is_boundary(face_id))
return
5094 select case(face_id)
5112 call trace_spherical_face_probe_coord(face_id,igrid, &
5113 xprobe(normal_dim),status)
5115 xprobe(1)=max(xprobmin1,min(xprobe(1), &
5116 xprobmax1-100.d0*epsilon(one)*max(one,abs(xprobmax1))))
5117 xprobe(2)=max(xprobmin2,min(xprobe(2), &
5118 xprobmax2-100.d0*epsilon(one)*max(one,abs(xprobmax2))))
5119 xprobe(3)=max(xprobmin3,min(xprobe(3), &
5120 xprobmax3-100.d0*epsilon(one)*max(one,abs(xprobmax3))))
5121 call trace_debug_locate_point(xprobe,sample_igrid,status)
5123 call trace_spherical_sample_b_bhat_cart(xprobe,sample_igrid,threshold, &
5124 bcart,bhat_cart,status)
5127 bhat=bhat_cart(1:
ndim)
5130 end subroutine trace_spherical_endpoint_b_bhat
5132 subroutine trace_spherical_face_probe_coord(face_id,igrid,xprobe,status)
5133 integer,
intent(in) :: face_id,igrid
5134 double precision,
intent(out) :: xprobe
5135 integer,
intent(out) :: status
5137 integer :: i1,i2,i3,normal_dim,side
5139 if (trace_spherical_profile_enabled)
then
5140 call trace_spherical_profile_add_count(trace_profile_face_probes,1_8)
5145 if (
ndim/=3 .or. geo_coordinate/=geo_spherical .or. igrid<0)
then
5154 select case(face_id)
5183 xprobe=ps(igrid)%x(i1,i2,i3,normal_dim)
5185 if (xprobe<xprobmin1 .and. normal_dim==1)
return
5186 if (xprobe<xprobmin2 .and. normal_dim==2)
return
5187 if (xprobe<xprobmin3 .and. normal_dim==3)
return
5189 if (xprobe>xprobmax1 .and. normal_dim==1)
return
5190 if (xprobe>xprobmax2 .and. normal_dim==2)
return
5191 if (xprobe>xprobmax3 .and. normal_dim==3)
return
5195 end subroutine trace_spherical_face_probe_coord
5197 double precision function trace_spherical_physical_cell_scale(x,igrid) &
5199 double precision,
intent(in) :: x(
ndim)
5200 integer,
intent(in) :: igrid
5202 double precision :: r,sint,dxloc(
ndim)
5206 if (
ndim/=3 .or. geo_coordinate/=geo_spherical .or. igrid<0)
return
5209 call trace_spherical_local_cell_widths(x,igrid,dxloc,status)
5211 r=max(abs(x(1)),smalldouble)
5212 sint=max(abs(dsin(x(2))),smalldouble)
5213 cell_scale=trace_spherical_cell_scale_from_widths(r,sint,dxloc)
5215 end function trace_spherical_physical_cell_scale
5217 double precision function trace_spherical_cell_scale_from_widths(r,sint, &
5218 dxloc)
result(cell_scale)
5219 double precision,
intent(in) :: r,sint,dxloc(
ndim)
5223 cell_scale=min(abs(dxloc(1)),abs(r)*abs(dxloc(2)))
5224 cell_scale=min(cell_scale,abs(r)*max(abs(sint),smalldouble)* &
5226 cell_scale=max(cell_scale,smalldouble)
5228 end function trace_spherical_cell_scale_from_widths
5231 double precision,
intent(out) :: hmin
5232 integer,
intent(out) :: status
5234 double precision :: dxloc(
ndim),hcell,r,sint
5235 integer :: iigrid,igrid,ix1,ix2,ix3
5239 if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
return
5245 do ix3=ixmlo3,ixmhi3
5246 do ix2=ixmlo2,ixmhi2
5247 do ix1=ixmlo1,ixmhi1
5248 r=ps(igrid)%x(ix1,ix2,ix3,1)
5249 sint=dsin(ps(igrid)%x(ix1,ix2,ix3,2))
5250 if (r<=smalldouble .or. abs(sint)<=smalldouble) cycle
5251 dxloc(1)=abs(ps(igrid)%dx(ix1,ix2,ix3,1))
5252 dxloc(2)=abs(ps(igrid)%dx(ix1,ix2,ix3,2))
5253 dxloc(3)=abs(ps(igrid)%dx(ix1,ix2,ix3,3))
5254 hcell=trace_spherical_cell_scale_from_widths(r,sint,dxloc)
5255 hmin=min(hmin,hcell)
5265 double precision,
intent(out) :: hmin
5266 integer,
intent(out) :: status
5268 double precision :: hlocal,hcell
5269 integer :: iigrid,igrid,ix1,ix2,ix3
5274 if (
ndim/=3 .or. .not.trace_cartesian_like_geometry())
return
5280 do ix3=ixmlo3,ixmhi3
5281 do ix2=ixmlo2,ixmhi2
5282 do ix1=ixmlo1,ixmhi1
5283 hcell=min(abs(ps(igrid)%dx(ix1,ix2,ix3,1)), &
5284 abs(ps(igrid)%dx(ix1,ix2,ix3,2)))
5285 hcell=min(hcell,abs(ps(igrid)%dx(ix1,ix2,ix3,3)))
5286 if (hcell>zero) hlocal=min(hlocal,hcell)
5292 call mpi_allreduce(hlocal,hmin,1,mpi_double_precision,mpi_min, &
5301 logical function trace_cartesian_like_geometry()
result(is_cart_like)
5302 is_cart_like=.false.
5305 select case (geo_coordinate)
5306 case (geo_cartesian,geo_cartesian_stretched)
5310 end function trace_cartesian_like_geometry
5312 logical function trace_rk45_position_integrator()
result(is_rk45)
5316 select case (trace_integrator_mode)
5317 case (trace_integrator_rk45_cartesian)
5318 is_rk45=trace_cartesian_like_geometry()
5319 case (trace_integrator_rk45_spherical)
5320 is_rk45=geo_coordinate==geo_spherical
5323 end function trace_rk45_position_integrator
5325 subroutine trace_interp_weights_block(x,igrid,ixI^L,ixbl^D,xd^D,dxc^D, &
5327 double precision,
intent(in) :: x(
ndim)
5328 integer,
intent(in) :: igrid,ixi^
l
5329 integer,
intent(out) :: ixbl^
d,status
5330 double precision,
intent(out) :: xd^
d,dxc^
d
5339 call trace_interp_index_3d(x(1),igrid,1,ixi^
l,ixbl1,xd1,dxc1,status)
5341 call trace_interp_index_3d(x(2),igrid,2,ixi^
l,ixbl2,xd2,dxc2,status)
5343 call trace_interp_index_3d(x(3),igrid,3,ixi^
l,ixbl3,xd3,dxc3,status)
5345 end subroutine trace_interp_weights_block
5347 subroutine trace_interp_weights_block_near(x,igrid,ixI^L,ixstart,ixbl^D, &
5349 double precision,
intent(in) :: x(
ndim)
5350 integer,
intent(in) :: igrid,ixi^
l
5351 integer,
intent(in) :: ixstart(3)
5352 integer,
intent(out) :: ixbl^
d,status
5353 double precision,
intent(out) :: xd^
d,dxc^
d
5362 call trace_interp_index_3d_near(x(1),igrid,1,ixi^
l,ixstart(1), &
5363 ixbl1,xd1,dxc1,status)
5365 call trace_interp_index_3d_near(x(2),igrid,2,ixi^
l,ixstart(2), &
5366 ixbl2,xd2,dxc2,status)
5368 call trace_interp_index_3d_near(x(3),igrid,3,ixi^
l,ixstart(3), &
5369 ixbl3,xd3,dxc3,status)
5371 end subroutine trace_interp_weights_block_near
5373 subroutine trace_interp_index_3d(xval,igrid,idim,ixI^L,ixlo,frac,dxc, &
5375 double precision,
intent(in) :: xval
5376 integer,
intent(in) :: igrid,idim,ixi^
l
5377 integer,
intent(out) :: ixlo,status
5378 double precision,
intent(out) :: frac,dxc
5380 double precision :: xlo,xhi,tol
5392 do i=iximin1,iximax1-1
5393 xlo=ps(igrid)%x(i,iximin2,iximin3,1)
5394 xhi=ps(igrid)%x(i+1,iximin2,iximin3,1)
5396 tol=100.d0*epsilon(one)*max(one,max(abs(xlo),abs(xhi)))
5397 if (abs(dxc)<=smalldouble) cycle
5398 if (xval>=min(xlo,xhi)-tol .and. &
5399 xval<=max(xlo,xhi)+tol)
then
5401 frac=max(zero,min(one,(xval-xlo)/dxc))
5407 do i=iximin2,iximax2-1
5408 xlo=ps(igrid)%x(iximin1,i,iximin3,2)
5409 xhi=ps(igrid)%x(iximin1,i+1,iximin3,2)
5411 tol=100.d0*epsilon(one)*max(one,max(abs(xlo),abs(xhi)))
5412 if (abs(dxc)<=smalldouble) cycle
5413 if (xval>=min(xlo,xhi)-tol .and. &
5414 xval<=max(xlo,xhi)+tol)
then
5416 frac=max(zero,min(one,(xval-xlo)/dxc))
5422 do i=iximin3,iximax3-1
5423 xlo=ps(igrid)%x(iximin1,iximin2,i,3)
5424 xhi=ps(igrid)%x(iximin1,iximin2,i+1,3)
5426 tol=100.d0*epsilon(one)*max(one,max(abs(xlo),abs(xhi)))
5427 if (abs(dxc)<=smalldouble) cycle
5428 if (xval>=min(xlo,xhi)-tol .and. &
5429 xval<=max(xlo,xhi)+tol)
then
5431 frac=max(zero,min(one,(xval-xlo)/dxc))
5438 end subroutine trace_interp_index_3d
5440 subroutine trace_interp_index_3d_near(xval,igrid,idim,ixI^L,ixstart, &
5441 ixlo,frac,dxc,status)
5442 double precision,
intent(in) :: xval
5443 integer,
intent(in) :: igrid,idim,ixi^
l,ixstart
5444 integer,
intent(out) :: ixlo,status
5445 double precision,
intent(out) :: frac,dxc
5447 double precision :: xlo,xhi,tol
5448 integer :: i,ilo,ihi,idir
5471 i=max(ilo,min(ixstart,ihi))
5475 xlo=ps(igrid)%x(i,iximin2,iximin3,1)
5476 xhi=ps(igrid)%x(i+1,iximin2,iximin3,1)
5478 xlo=ps(igrid)%x(iximin1,i,iximin3,2)
5479 xhi=ps(igrid)%x(iximin1,i+1,iximin3,2)
5481 xlo=ps(igrid)%x(iximin1,iximin2,i,3)
5482 xhi=ps(igrid)%x(iximin1,iximin2,i+1,3)
5485 tol=100.d0*epsilon(one)*max(one,max(abs(xlo),abs(xhi)))
5486 if (abs(dxc)>smalldouble .and. &
5487 xval>=min(xlo,xhi)-tol .and. &
5488 xval<=max(xlo,xhi)+tol)
then
5490 frac=max(zero,min(one,(xval-xlo)/dxc))
5495 if (abs(dxc)<=smalldouble)
then
5497 else if (xval<min(xlo,xhi)-tol)
then
5504 if (i<ilo .or. i>ihi)
exit
5507 end subroutine trace_interp_index_3d_near
5509 subroutine trace_spherical_local_cell_widths(x,igrid,dxloc,status)
5510 double precision,
intent(in) :: x(
ndim)
5511 integer,
intent(in) :: igrid
5512 double precision,
intent(out) :: dxloc(
ndim)
5513 integer,
intent(out) :: status
5515 type(trace_sph_interp_ctx) :: ctx
5519 if (
ndim/=3 .or. geo_coordinate/=geo_spherical .or. igrid<0)
return
5522 call trace_spherical_interp_ctx_build(x,igrid,ctx,status)
5524 dxloc(1:3)=ctx%dxloc(1:3)
5526 end subroutine trace_spherical_local_cell_widths
5528 subroutine trace_debug_locate_point(x,igrid,status)
5531 double precision,
intent(in) :: x(
ndim)
5532 integer,
intent(out) :: igrid,status
5534 double precision :: x3d(3)
5535 integer :: indomain,ipe,j
5540 {
if (x(^db)>=xprobmin^db .and. x(^db)<xprobmax^db) indomain=indomain+1\}
5541 if (indomain/=
ndim)
then
5551 if (igrid<0 .or. ipe/=
mype)
then
5554 end subroutine trace_debug_locate_point
5556 subroutine trace_locate_point_with_hint(x,igrid_hint,igrid,status)
5557 double precision,
intent(in) :: x(
ndim)
5558 integer,
intent(in) :: igrid_hint
5559 integer,
intent(out) :: igrid,status
5561 double precision :: xbmin^
d,xbmax^
d
5566 if (igrid_hint>=0)
then
5570 {
if (x(^db)>xbmin^db .and. x(^db)<xbmax^db) inblock=inblock+1\}
5571 if (inblock==
ndim)
then
5577 call trace_debug_locate_point(x,igrid,status)
5578 end subroutine trace_locate_point_with_hint
5580 subroutine trace_tangent_rhs(x,u,v,igrid,threshold,kx,ku,kv,status, &
5582 double precision,
intent(in) :: x(
ndim),u(
ndim),v(
ndim),threshold
5583 integer,
intent(in) :: igrid
5584 double precision,
intent(out) :: kx(
ndim),ku(
ndim),kv(
ndim)
5585 integer,
intent(out) :: status
5586 double precision,
intent(in),
optional :: p(
ndim),q(
ndim)
5587 double precision,
intent(out),
optional :: kp(
ndim),kq(
ndim)
5588 type(trace_sph_interp_ctx),
intent(in),
optional :: sph_ctx
5590 double precision :: bhat(3),grad_bhat(3,3)
5591 double precision :: u3(3),v3(3),p3(3),q3(3)
5592 double precision :: ku3(3),kv3(3),kp3(3),kq3(3)
5598 if (
present(kp)) kp=zero
5599 if (
present(kq)) kq=zero
5602 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_rhs()
5605 if (geo_coordinate==geo_spherical)
then
5607 if (
present(sph_ctx))
then
5608 use_ctx=sph_ctx%valid .and. sph_ctx%igrid==igrid .and. &
5609 maxval(abs(sph_ctx%x(1:3)-x(1:3))) <= &
5610 100.d0*epsilon(one)*max(one,maxval(abs(x(1:3))))
5613 call trace_spherical_sample_bhat_gradbhat_covariant_ctx(sph_ctx, &
5614 threshold,bhat,grad_bhat,status)
5616 call trace_spherical_sample_bhat_gradbhat_covariant(x,igrid, &
5617 threshold,bhat,grad_bhat,status)
5620 if (trace_spherical_profile_enabled)
then
5621 call trace_spherical_profile_add_count(trace_profile_grad_fallbacks, &
5624 call trace_spherical_sample_bhat_gradbhat_cartfd(x,igrid,threshold, &
5625 bhat,grad_bhat,status)
5628 call trace_spherical_bhat_cart_to_rhs(x,bhat,kx,status)
5631 call sample_bhat_gradbhat_at_point(x,igrid,threshold,bhat,grad_bhat,status)
5641 ku3=matmul(grad_bhat,u3)
5642 kv3=matmul(grad_bhat,v3)
5645 if (
present(p) .and.
present(q) .and.
present(kp) .and. &
5651 kp3=matmul(grad_bhat,p3)
5652 kq3=matmul(grad_bhat,q3)
5657 end subroutine trace_tangent_rhs
5659 subroutine trace_advance_tangent_state_rk2(x,u,v,igrid,h,threshold,status)
5660 double precision,
intent(inout) :: x(
ndim),u(
ndim),v(
ndim)
5661 integer,
intent(inout) :: igrid
5662 double precision,
intent(in) :: h,threshold
5663 integer,
intent(out) :: status
5666 integer :: igrid_mid,igrid_new
5668 call trace_tangent_rk2_trial(x,u,v,igrid,h,threshold,xnew,unew,vnew, &
5672 call trace_debug_locate_point(xnew,igrid_new,status)
5679 end subroutine trace_advance_tangent_state_rk2
5681 subroutine trace_tangent_rk2_trial(x,u,v,igrid,h,threshold,xnew,unew, &
5683 double precision,
intent(in) :: x(
ndim),u(
ndim),v(
ndim),h,threshold
5684 integer,
intent(in) :: igrid
5685 double precision,
intent(out) :: xnew(
ndim),unew(
ndim),vnew(
ndim)
5686 integer,
intent(out) :: status
5690 call trace_tangent_rhs(x,u,v,igrid,threshold,kx1,ku1,kv1,status)
5693 call trace_tangent_rk2_trial_from_rhs(x,u,v,igrid,h,threshold, &
5694 kx1,ku1,kv1,xnew,unew,vnew,status)
5695 end subroutine trace_tangent_rk2_trial
5697 subroutine trace_tangent_rk2_trial_from_rhs(x,u,v,igrid,h,threshold, &
5698 kx1,ku1,kv1,xnew,unew,vnew,status,p,q,kp1,kq1,pnew,qnew, &
5699 sph_cache,clamp_stage)
5700 double precision,
intent(in) :: x(
ndim),u(
ndim),v(
ndim),h,threshold
5701 double precision,
intent(in) :: kx1(
ndim),ku1(
ndim),kv1(
ndim)
5702 integer,
intent(in) :: igrid
5703 double precision,
intent(out) :: xnew(
ndim),unew(
ndim),vnew(
ndim)
5704 integer,
intent(out) :: status
5705 double precision,
intent(in),
optional :: p(
ndim),q(
ndim)
5706 double precision,
intent(in),
optional :: kp1(
ndim),kq1(
ndim)
5707 double precision,
intent(out),
optional :: pnew(
ndim),qnew(
ndim)
5708 type(trace_sph_interp_ctx),
intent(inout),
optional :: sph_cache
5709 logical,
intent(in),
optional :: clamp_stage
5712 double precision :: xmid(
ndim),xmid_sample(
ndim)
5714 type(trace_sph_interp_ctx) :: ctx_mid
5715 integer :: igrid_mid
5716 integer :: ctx_status
5717 logical :: use_clamped_stage
5722 use_clamped_stage=.false.
5723 if (
present(clamp_stage)) use_clamped_stage=clamp_stage
5725 if (use_clamped_stage)
then
5726 ^
d&xmid_sample(^
d)=max(xprobmin^
d,min(xmid_sample(^
d), &
5727 xprobmax^
d-100.d0*epsilon(one)*max(one,abs(xprobmax^
d))));
5729 call trace_locate_point_with_hint(xmid_sample,igrid,igrid_mid,status)
5732 if (geo_coordinate==geo_spherical)
then
5733 if (
present(sph_cache))
then
5734 call trace_spherical_interp_ctx_build_cached(xmid_sample,igrid_mid, &
5735 sph_cache,ctx_mid,ctx_status)
5737 call trace_spherical_interp_ctx_build(xmid_sample,igrid_mid,ctx_mid, &
5742 if (
present(p) .and.
present(q) .and.
present(kp1) .and. &
5743 present(kq1) .and.
present(pnew) .and.
present(qnew))
then
5747 call trace_tangent_rhs(xmid_sample,umid,vmid,igrid_mid,threshold,kx2,ku2, &
5748 kv2,status,pmid,qmid,kp2,kq2,sph_ctx=ctx_mid)
5750 call trace_tangent_rhs(xmid_sample,umid,vmid,igrid_mid,threshold,kx2,ku2, &
5751 kv2,status,pmid,qmid,kp2,kq2)
5755 call trace_tangent_rhs(xmid_sample,umid,vmid,igrid_mid,threshold,kx2,ku2, &
5756 kv2,status,sph_ctx=ctx_mid)
5758 call trace_tangent_rhs(xmid_sample,umid,vmid,igrid_mid,threshold,kx2,ku2, &
5767 if (
present(pnew) .and.
present(qnew))
then
5771 end subroutine trace_tangent_rk2_trial_from_rhs
5773 subroutine trace_project_to_perp_bhat(vec,bhat,vec_perp)
5774 double precision,
intent(in) :: vec(
ndim),bhat(
ndim)
5775 double precision,
intent(out) :: vec_perp(
ndim)
5777 vec_perp=vec-sum(vec*bhat)*bhat
5778 end subroutine trace_project_to_perp_bhat
5780 subroutine trace_endpoint_b_bhat(x,face_id,igrid,threshold,B,bhat,status)
5781 double precision,
intent(in) :: x(
ndim),threshold
5782 integer,
intent(in) :: face_id,igrid
5783 double precision,
intent(out) :: b(
ndim),bhat(
ndim)
5784 integer,
intent(out) :: status
5786 double precision :: b3(3),bhat3(3)
5787 integer :: sample_igrid
5791 if (geo_coordinate==geo_spherical)
then
5792 call trace_spherical_endpoint_b_bhat(x,face_id,igrid,threshold,b,bhat, &
5796 call trace_locate_face_limit_grid(x,face_id,igrid,sample_igrid,status)
5798 call trace_sample_b_on_domain_face_limit(x,face_id,sample_igrid,threshold, &
5804 end subroutine trace_endpoint_b_bhat
5806 subroutine trace_locate_face_limit_grid(x,face_id,igrid_in,igrid_out, &
5808 double precision,
intent(in) :: x(
ndim)
5809 integer,
intent(in) :: face_id,igrid_in
5810 integer,
intent(out) :: igrid_out,status
5812 double precision :: xprobe(
ndim),xface
5814 integer :: normal_dim,side
5818 if (
ndim/=3 .or. .not.trace_cartesian_like_geometry() .or. &
5823 if (.not.trace_face_is_boundary(face_id))
return
5826 select case(face_id)
5857 select case(normal_dim)
5860 xprobe(normal_dim)=ps(igrid_in)%x(ixomin1,ixomin2,ixomin3,1)
5862 xprobe(normal_dim)=ps(igrid_in)%x(ixomax1,ixomin2,ixomin3,1)
5866 xprobe(normal_dim)=ps(igrid_in)%x(ixomin1,ixomin2,ixomin3,2)
5868 xprobe(normal_dim)=ps(igrid_in)%x(ixomin1,ixomax2,ixomin3,2)
5872 xprobe(normal_dim)=ps(igrid_in)%x(ixomin1,ixomin2,ixomin3,3)
5874 xprobe(normal_dim)=ps(igrid_in)%x(ixomin1,ixomin2,ixomax3,3)
5877 call trace_debug_locate_point(xprobe,igrid_out,status)
5879 end subroutine trace_locate_face_limit_grid
5881 subroutine trace_sample_b_on_domain_face_limit(xhit,face_id,igrid, &
5882 threshold,B,bhat,status)
5886 double precision,
intent(in) :: xhit(
ndim),threshold
5887 integer,
intent(in) :: face_id,igrid
5888 double precision,
intent(out) :: b(3),bhat(3)
5889 integer,
intent(out) :: status
5891 double precision :: bnear(3),binner(3)
5892 double precision :: xface,xnear,xinner
5893 double precision :: xnear_pt(
ndim),xinner_pt(
ndim)
5894 double precision :: bnorm
5896 integer :: normal_dim,side
5897 integer :: igrid_near,igrid_inner
5902 if (
ndim/=3 .or. .not.trace_cartesian_like_geometry() .or. igrid<0)
then
5906 if (.not.trace_face_is_boundary(face_id))
return
5909 select case(face_id)
5939 select case(normal_dim)
5942 xnear=ps(igrid)%x(ixomin1,ixomin2,ixomin3,1)
5943 xinner=ps(igrid)%x(ixomin1+1,ixomin2,ixomin3,1)
5945 xnear=ps(igrid)%x(ixomax1,ixomin2,ixomin3,1)
5946 xinner=ps(igrid)%x(ixomax1-1,ixomin2,ixomin3,1)
5950 xnear=ps(igrid)%x(ixomin1,ixomin2,ixomin3,2)
5951 xinner=ps(igrid)%x(ixomin1,ixomin2+1,ixomin3,2)
5953 xnear=ps(igrid)%x(ixomin1,ixomax2,ixomin3,2)
5954 xinner=ps(igrid)%x(ixomin1,ixomax2-1,ixomin3,2)
5958 xnear=ps(igrid)%x(ixomin1,ixomin2,ixomin3,3)
5959 xinner=ps(igrid)%x(ixomin1,ixomin2,ixomin3+1,3)
5961 xnear=ps(igrid)%x(ixomin1,ixomin2,ixomax3,3)
5962 xinner=ps(igrid)%x(ixomin1,ixomin2,ixomax3-1,3)
5967 xnear_pt(normal_dim)=xnear
5968 xinner_pt(normal_dim)=xinner
5970 call trace_debug_locate_point(xnear_pt,igrid_near,status)
5972 call sample_b_at_point(xnear_pt,igrid_near,threshold,bnear,status)
5974 call trace_debug_locate_point(xinner_pt,igrid_inner,status)
5976 call sample_b_at_point(xinner_pt,igrid_inner,threshold,binner,status)
5979 b=bnear+(bnear-binner)/(xnear-xinner)*(xface-xnear)
5980 bnorm=dsqrt(sum(b**2))
5981 if (bnorm<=zero .or. bnorm<threshold)
then
5988 end subroutine trace_sample_b_on_domain_face_limit
5990 subroutine trace_face_normal(face_id,normal,ok)
5991 integer,
intent(in) :: face_id
5992 double precision,
intent(out) :: normal(
ndim)
5993 logical,
intent(out) :: ok
5997 select case(face_id)
6027 end subroutine trace_face_normal
6029 subroutine trace_project_to_boundary_face(vec,bhat,face_id,vec_face)
6030 double precision,
intent(in) :: vec(
ndim),bhat(
ndim)
6031 integer,
intent(in) :: face_id
6032 double precision,
intent(out) :: vec_face(
ndim)
6034 double precision :: normal(
ndim),bn
6038 call trace_face_normal(face_id,normal,ok)
6041 if (abs(bn)<=smalldouble)
return
6042 vec_face=vec-sum(vec*normal)/bn*bhat
6043 end subroutine trace_project_to_boundary_face
6045 subroutine trace_make_perp_basis(bhat,u0,v0,status)
6046 double precision,
intent(in) :: bhat(3)
6047 double precision,
intent(out) :: u0(
ndim),v0(
ndim)
6048 integer,
intent(out) :: status
6050 double precision :: ref(3),u3(3),v3(3),b3(3),unorm,bnorm
6062 bnorm=dsqrt(sum(b3**2))
6063 if (bnorm<=zero)
then
6070 if (abs(b3(2))<abs(b3(iref))) iref=2
6071 if (abs(b3(3))<abs(b3(iref))) iref=3
6075 u3=ref-sum(ref*b3)*b3
6076 unorm=dsqrt(sum(u3**2))
6077 if (unorm<=smalldouble)
then
6083 v3(1)=b3(2)*u3(3)-b3(3)*u3(2)
6084 v3(2)=b3(3)*u3(1)-b3(1)*u3(3)
6085 v3(3)=b3(1)*u3(2)-b3(2)*u3(1)
6086 v3=v3/dsqrt(sum(v3**2))
6090 end subroutine trace_make_perp_basis
6092 double precision function trace_debug_nan()
6093 trace_debug_nan=ieee_value(0.d0,ieee_quiet_nan)
6094 end function trace_debug_nan
6096 subroutine trace_summary_seed(seed,dL,max_steps,result,b_min)
6097 double precision,
intent(in) :: seed(
ndim),dl
6098 integer,
intent(in) :: max_steps
6100 double precision,
intent(in),
optional :: b_min
6102 double precision :: field_min
6103 integer :: common_status,igrid
6105 call trace_summary_validate(dl,max_steps,common_status)
6107 call trace_summary_init_result(seed,result,common_status)
6111 field_min=smalldouble
6112 if (
present(b_min)) field_min=max(b_min,zero)
6114 call trace_summary_locate_seed(seed,result,igrid)
6116 call trace_summary_trace_seed(igrid,dl,max_steps,field_min,result)
6117 end subroutine trace_summary_seed
6119 subroutine trace_summary_twist_seed(seed,dL,max_steps,result,b_min)
6120 double precision,
intent(in) :: seed(
ndim),dl
6121 integer,
intent(in) :: max_steps
6123 double precision,
intent(in),
optional :: b_min
6125 double precision :: field_min
6126 integer :: common_status,igrid
6128 call trace_summary_validate(dl,max_steps,common_status)
6133 call trace_summary_init_twist_result(seed,result,common_status)
6137 field_min=smalldouble
6138 if (
present(b_min)) field_min=max(b_min,zero)
6140 call trace_summary_locate_seed(seed,result%line,igrid)
6141 result%forward_twist=zero
6142 result%backward_twist=zero
6143 result%total_twist=zero
6144 result%valid_twist=.false.
6145 result%status_twist=result%line%forward_status
6147 call trace_summary_trace_twist_seed(igrid,dl,max_steps,field_min,result)
6148 end subroutine trace_summary_twist_seed
6150 subroutine trace_summary_mapping_seed(seed,dL,max_steps,result,b_min, &
6152 double precision,
intent(in) :: seed(
ndim),dl
6153 integer,
intent(in) :: max_steps
6155 double precision,
intent(in),
optional :: b_min
6156 double precision,
intent(in),
optional :: source_normal(3)
6158 type(trace_summary_state) :: forward_state,backward_state
6160 double precision :: field_min,normal(3)
6161 integer :: common_status,igrid
6162 logical :: have_normal
6164 call trace_summary_validate(dl,max_steps,common_status)
6169 call trace_summary_init_mapping_result(seed,result,common_status)
6173 field_min=smalldouble
6174 if (
present(b_min)) field_min=max(b_min,zero)
6176 have_normal=
present(source_normal)
6177 if (have_normal) normal=source_normal
6179 call trace_summary_locate_seed(seed,located,igrid)
6180 call trace_summary_init_mapping_result(seed,result,located%forward_status)
6183 call trace_summary_init_state(seed,igrid,.true.,1,.false.,forward_state)
6184 call trace_summary_trace_state_to_end(forward_state,dl,max_steps,field_min)
6185 call trace_summary_init_state(seed,igrid,.false.,1,.false.,backward_state)
6186 call trace_summary_trace_state_to_end(backward_state,dl,max_steps,field_min)
6187 call trace_summary_fill_mapping(seed,igrid,forward_state,backward_state, &
6188 field_min,have_normal,normal,result)
6189 end subroutine trace_summary_mapping_seed
6191 subroutine trace_summary_multi(seeds,nseed,dL,max_steps,results,field_min)
6192 integer,
intent(in) :: nseed,max_steps
6193 double precision,
intent(in) :: seeds(nseed,
ndim),dl,field_min
6196 type(trace_summary_state),
allocatable :: states(:)
6197 double precision :: seed_local(
ndim)
6198 integer :: common_status,iseed,igrid,iforward,ibackward
6200 if (nseed<=0)
return
6202 call trace_summary_validate(dl,max_steps,common_status)
6205 seed_local=seeds(iseed,:)
6206 call trace_summary_init_result(seed_local,results(iseed),common_status)
6211 allocate(states(2*nseed))
6213 seed_local=seeds(iseed,:)
6214 call trace_summary_locate_seed(seed_local,results(iseed),igrid)
6217 call trace_summary_init_state(seed_local,igrid,.true.,iseed,.false., &
6219 call trace_summary_init_state(seed_local,igrid,.false.,iseed,.false., &
6222 states(iforward)%status=results(iseed)%forward_status
6223 states(iforward)%active=.false.
6224 states(ibackward)%status=results(iseed)%backward_status
6225 states(ibackward)%active=.false.
6229 call trace_summary_trace_states_grouped(states,2*nseed,dl,max_steps, &
6235 results(iseed)%forward_footpoint=states(iforward)%footpoint
6236 results(iseed)%forward_length=states(iforward)%length
6237 results(iseed)%forward_nstep=states(iforward)%nstep
6238 results(iseed)%forward_status=states(iforward)%status
6239 results(iseed)%backward_footpoint=states(ibackward)%footpoint
6240 results(iseed)%backward_length=states(ibackward)%length
6241 results(iseed)%backward_nstep=states(ibackward)%nstep
6242 results(iseed)%backward_status=states(ibackward)%status
6243 results(iseed)%total_length=results(iseed)%forward_length &
6244 +results(iseed)%backward_length
6247 end subroutine trace_summary_multi
6249 subroutine trace_summary_twist_multi(seeds,nseed,dL,max_steps,results, &
6251 integer,
intent(in) :: nseed,max_steps
6252 double precision,
intent(in) :: seeds(nseed,
ndim),dl,field_min
6255 type(trace_summary_state),
allocatable :: states(:)
6256 double precision :: seed_local(
ndim)
6257 integer :: common_status,iseed,igrid,iforward,ibackward
6259 if (nseed<=0)
return
6261 call trace_summary_validate(dl,max_steps,common_status)
6267 seed_local=seeds(iseed,:)
6268 call trace_summary_init_twist_result(seed_local,results(iseed), &
6274 allocate(states(2*nseed))
6276 seed_local=seeds(iseed,:)
6277 call trace_summary_locate_seed(seed_local,results(iseed)%line,igrid)
6278 results(iseed)%forward_twist=zero
6279 results(iseed)%backward_twist=zero
6280 results(iseed)%total_twist=zero
6281 results(iseed)%valid_twist=.false.
6282 results(iseed)%status_twist=results(iseed)%line%forward_status
6285 call trace_summary_init_state(seed_local,igrid,.true.,iseed,.true., &
6287 call trace_summary_init_state(seed_local,igrid,.false.,iseed,.true., &
6290 states(iforward)%status=results(iseed)%line%forward_status
6291 states(iforward)%active=.false.
6292 states(ibackward)%status=results(iseed)%line%backward_status
6293 states(ibackward)%active=.false.
6297 call trace_summary_trace_states_grouped(states,2*nseed,dl,max_steps, &
6303 results(iseed)%line%forward_footpoint=states(iforward)%footpoint
6304 results(iseed)%line%forward_length=states(iforward)%length
6305 results(iseed)%line%forward_nstep=states(iforward)%nstep
6306 results(iseed)%line%forward_status=states(iforward)%status
6307 results(iseed)%line%backward_footpoint=states(ibackward)%footpoint
6308 results(iseed)%line%backward_length=states(ibackward)%length
6309 results(iseed)%line%backward_nstep=states(ibackward)%nstep
6310 results(iseed)%line%backward_status=states(ibackward)%status
6311 results(iseed)%line%total_length=results(iseed)%line%forward_length &
6312 +results(iseed)%line%backward_length
6313 results(iseed)%forward_twist=states(iforward)%twist
6314 results(iseed)%backward_twist=states(ibackward)%twist
6315 results(iseed)%total_twist=results(iseed)%forward_twist &
6316 +results(iseed)%backward_twist
6317 results(iseed)%status_twist=trace_summary_twist_status_from_states( &
6318 states(iforward),states(ibackward))
6319 results(iseed)%valid_twist=results(iseed)%status_twist &
6323 end subroutine trace_summary_twist_multi
6325 subroutine trace_summary_mapping_multi(seeds,nseed,dL,max_steps,results, &
6326 field_min,have_source_normal,source_normal)
6327 integer,
intent(in) :: nseed,max_steps
6328 double precision,
intent(in) :: seeds(nseed,
ndim),dl,field_min
6329 logical,
intent(in) :: have_source_normal
6330 double precision,
intent(in) :: source_normal(3)
6333 type(trace_summary_state),
allocatable :: states(:)
6334 integer,
allocatable :: source_igrids(:)
6336 double precision :: seed_local(
ndim)
6337 integer :: common_status,iseed,igrid,iforward,ibackward
6339 if (nseed<=0)
return
6341 call trace_summary_validate(dl,max_steps,common_status)
6347 seed_local=seeds(iseed,:)
6348 call trace_summary_init_mapping_result(seed_local,results(iseed), &
6354 allocate(states(2*nseed))
6355 allocate(source_igrids(nseed))
6358 seed_local=seeds(iseed,:)
6359 call trace_summary_locate_seed(seed_local,located,igrid)
6360 source_igrids(iseed)=igrid
6361 call trace_summary_init_mapping_result(seed_local,results(iseed), &
6362 located%forward_status)
6365 call trace_summary_init_state(seed_local,igrid,.true.,iseed,.false., &
6367 call trace_summary_init_state(seed_local,igrid,.false.,iseed,.false., &
6370 states(iforward)%status=located%forward_status
6371 states(iforward)%active=.false.
6372 states(ibackward)%status=located%backward_status
6373 states(ibackward)%active=.false.
6377 call trace_summary_trace_states_grouped(states,2*nseed,dl,max_steps, &
6383 if (source_igrids(iseed)>=0)
then
6384 call trace_summary_fill_mapping(results(iseed)%seed, &
6385 source_igrids(iseed),states(iforward),states(ibackward), &
6386 field_min,have_source_normal,source_normal,results(iseed))
6389 deallocate(source_igrids,states)
6390 end subroutine trace_summary_mapping_multi
6392 subroutine trace_summary_topology_multi(seeds,nseed,dL,max_steps,results, &
6393 field_min,need_twist,need_mapping,have_source_normal,source_normal)
6394 integer,
intent(in) :: nseed,max_steps
6395 double precision,
intent(in) :: seeds(nseed,
ndim),dl,field_min
6396 logical,
intent(in) :: need_twist,need_mapping,have_source_normal
6397 double precision,
intent(in) :: source_normal(3)
6400 type(trace_summary_state),
allocatable :: states(:)
6401 type(trace_summary_state),
allocatable :: map_states(:)
6402 integer,
allocatable :: source_igrids(:)
6405 double precision :: seed_local(
ndim)
6406 integer :: common_status,iseed,igrid,iforward,ibackward,idim
6408 if (nseed<=0)
return
6410 call trace_summary_validate(dl,max_steps,common_status)
6412 (need_twist .or. need_mapping) .and.
ndim/=3)
then
6418 seed_local(idim)=seeds(iseed,idim)
6420 call trace_summary_init_topology_result(seed_local,results(iseed), &
6421 common_status,need_twist,need_mapping)
6426 allocate(states(2*nseed))
6429 if (need_mapping .and. need_twist)
allocate(map_states(2*nseed))
6430 allocate(source_igrids(nseed))
6434 seed_local(idim)=seeds(iseed,idim)
6436 call trace_summary_locate_seed(seed_local,located,igrid)
6437 source_igrids(iseed)=igrid
6438 call trace_summary_init_topology_result(seed_local,results(iseed), &
6439 located%forward_status,need_twist,need_mapping)
6442 call trace_summary_init_state(seed_local,igrid,.true.,iseed, &
6443 need_twist,states(iforward))
6444 call trace_summary_init_state(seed_local,igrid,.false.,iseed, &
6445 need_twist,states(ibackward))
6446 if (
allocated(map_states))
then
6447 call trace_summary_init_state(seed_local,igrid,.true.,iseed, &
6448 .false.,map_states(iforward))
6449 call trace_summary_init_state(seed_local,igrid,.false.,iseed, &
6450 .false.,map_states(ibackward))
6453 states(iforward)%status=located%forward_status
6454 states(iforward)%active=.false.
6455 states(ibackward)%status=located%backward_status
6456 states(ibackward)%active=.false.
6457 if (
allocated(map_states))
then
6458 map_states(iforward)%status=located%forward_status
6459 map_states(iforward)%active=.false.
6460 map_states(ibackward)%status=located%backward_status
6461 map_states(ibackward)%active=.false.
6466 call trace_summary_trace_states_grouped(states,2*nseed,dl,max_steps, &
6468 if (
allocated(map_states))
then
6469 call trace_summary_trace_states_grouped(map_states,2*nseed,dl, &
6470 max_steps,field_min)
6476 results(iseed)%forward_endpoint=states(iforward)%footpoint
6477 results(iseed)%backward_endpoint=states(ibackward)%footpoint
6478 results(iseed)%length_forward=states(iforward)%length
6479 results(iseed)%length_backward=states(ibackward)%length
6480 results(iseed)%length_total=results(iseed)%length_forward &
6481 +results(iseed)%length_backward
6482 results(iseed)%forward_nstep=states(iforward)%nstep
6483 results(iseed)%backward_nstep=states(ibackward)%nstep
6484 results(iseed)%forward_face=states(iforward)%face
6485 results(iseed)%backward_face=states(ibackward)%face
6486 results(iseed)%forward_status=states(iforward)%status
6487 results(iseed)%backward_status=states(ibackward)%status
6488 if (need_twist)
then
6489 results(iseed)%twist_forward=states(iforward)%twist
6490 results(iseed)%twist_backward=states(ibackward)%twist
6491 results(iseed)%twist_total=results(iseed)%twist_forward &
6492 +results(iseed)%twist_backward
6493 results(iseed)%status_twist=trace_summary_twist_status_from_states( &
6494 states(iforward),states(ibackward))
6495 results(iseed)%valid_twist=results(iseed)%status_twist &
6502 results(iseed)%valid=.true.
6504 results(iseed)%valid=.false.
6506 results(iseed)%status=states(iforward)%status
6508 results(iseed)%status=states(ibackward)%status
6512 if (need_mapping .and. source_igrids(iseed)>=0)
then
6513 if (
allocated(map_states))
then
6514 call trace_summary_fill_mapping(results(iseed)%seed, &
6515 source_igrids(iseed),map_states(iforward), &
6516 map_states(ibackward),field_min,have_source_normal, &
6517 source_normal,mapping)
6519 call trace_summary_fill_mapping(results(iseed)%seed, &
6520 source_igrids(iseed),states(iforward),states(ibackward), &
6521 field_min,have_source_normal,source_normal,mapping)
6523 results(iseed)%source_B=mapping%source_B
6524 results(iseed)%forward_B=mapping%forward_B
6525 results(iseed)%backward_B=mapping%backward_B
6526 results(iseed)%source_Bn=mapping%source_Bn
6527 results(iseed)%forward_Bn=mapping%forward_Bn
6528 results(iseed)%backward_Bn=mapping%backward_Bn
6529 results(iseed)%map_forward_endpoint=mapping%forward_footpoint
6530 results(iseed)%map_backward_endpoint=mapping%backward_footpoint
6531 results(iseed)%map_forward_length=mapping%forward_length
6532 results(iseed)%map_backward_length=mapping%backward_length
6533 results(iseed)%map_forward_face=mapping%forward_face
6534 results(iseed)%map_backward_face=mapping%backward_face
6535 results(iseed)%map_forward_status=mapping%forward_status
6536 results(iseed)%map_backward_status=mapping%backward_status
6537 results(iseed)%forward_status=mapping%forward_status
6538 results(iseed)%backward_status=mapping%backward_status
6539 results(iseed)%valid=mapping%valid
6540 if (mapping%valid)
then
6543 results(iseed)%status=mapping%forward_status
6545 results(iseed)%status=mapping%backward_status
6549 if (
allocated(map_states))
deallocate(map_states)
6550 deallocate(source_igrids,states)
6551 end subroutine trace_summary_topology_multi
6553 subroutine trace_summary_validate(dL,max_steps,status)
6554 double precision,
intent(in) :: dl
6555 integer,
intent(in) :: max_steps
6556 integer,
intent(out) :: status
6561 else if (dl<=zero .or. max_steps<0)
then
6563 else if (.not.trace_is_supported_summary_geometry())
then
6566 end subroutine trace_summary_validate
6568 logical function trace_is_supported_summary_geometry()
result(is_supported)
6569 is_supported=.false.
6572 select case (geo_coordinate)
6573 case (geo_cartesian,geo_cartesian_stretched)
6575 case (geo_spherical)
6581 end function trace_is_supported_summary_geometry
6583 subroutine trace_summary_init_result(seed,result,status)
6584 double precision,
intent(in) :: seed(
ndim)
6586 integer,
intent(in) :: status
6589 result%forward_footpoint=seed
6590 result%backward_footpoint=seed
6591 result%forward_length=zero
6592 result%backward_length=zero
6593 result%total_length=zero
6594 result%forward_nstep=0
6595 result%backward_nstep=0
6596 result%forward_status=status
6597 result%backward_status=status
6598 end subroutine trace_summary_init_result
6600 subroutine trace_summary_init_twist_result(seed,result,status)
6601 double precision,
intent(in) :: seed(
ndim)
6603 integer,
intent(in) :: status
6605 call trace_summary_init_result(seed,result%line,status)
6606 result%forward_twist=zero
6607 result%backward_twist=zero
6608 result%total_twist=zero
6609 result%valid_twist=.false.
6610 result%status_twist=status
6611 end subroutine trace_summary_init_twist_result
6613 subroutine trace_summary_init_mapping_result(seed,result,status)
6614 double precision,
intent(in) :: seed(
ndim)
6616 integer,
intent(in) :: status
6619 result%source_B=zero
6620 result%forward_footpoint=seed
6621 result%backward_footpoint=seed
6622 result%forward_B=zero
6623 result%backward_B=zero
6624 result%forward_length=zero
6625 result%backward_length=zero
6626 result%source_Bn=zero
6627 result%forward_Bn=zero
6628 result%backward_Bn=zero
6631 result%forward_status=status
6632 result%backward_status=status
6633 result%valid=.false.
6634 end subroutine trace_summary_init_mapping_result
6636 subroutine trace_summary_init_topology_result(seed,result,status, &
6637 need_twist,need_mapping)
6638 double precision,
intent(in) :: seed(
ndim)
6640 integer,
intent(in) :: status
6641 logical,
intent(in) :: need_twist,need_mapping
6644 result%length_forward=zero
6645 result%length_backward=zero
6646 result%length_total=zero
6647 result%twist_forward=zero
6648 result%twist_backward=zero
6649 result%twist_total=zero
6650 result%forward_endpoint=seed
6651 result%backward_endpoint=seed
6652 result%forward_nstep=0
6653 result%backward_nstep=0
6656 result%forward_status=status
6657 result%backward_status=status
6658 result%map_forward_endpoint=seed
6659 result%map_backward_endpoint=seed
6660 result%map_forward_length=zero
6661 result%map_backward_length=zero
6664 result%map_forward_status=status
6665 result%map_backward_status=status
6666 result%source_B=zero
6667 result%forward_B=zero
6668 result%backward_B=zero
6669 result%source_Bn=zero
6670 result%forward_Bn=zero
6671 result%backward_Bn=zero
6672 result%has_twist=need_twist
6673 result%has_mapping=need_mapping
6674 result%valid_twist=.false.
6675 result%valid=.false.
6676 result%status_twist=status
6677 result%status=status
6678 end subroutine trace_summary_init_topology_result
6680 subroutine trace_summary_locate_seed(seed,result,igrid)
6683 double precision,
intent(in) :: seed(
ndim)
6685 integer,
intent(out) :: igrid
6687 double precision :: x3d(3),domain_min(
ndim),domain_max(
ndim),tol
6688 integer :: indomain,ipe,j
6693 ^
d&domain_min(^
d)=xprobmin^
d;
6694 ^
d&domain_max(^
d)=xprobmax^
d;
6695 tol=100.d0*epsilon(one)*max(one,maxval(abs(domain_max-domain_min)))
6697 if (seed(j)>=domain_min(j)-tol .and. &
6698 seed(j)<=domain_max(j)+tol) indomain=indomain+1
6700 if (indomain/=
ndim)
then
6708 x3d(j)=min(max(seed(j),domain_min(j)+tol),domain_max(j)-tol)
6711 if (igrid<0 .or. ipe/=
mype)
then
6716 end subroutine trace_summary_locate_seed
6718 subroutine trace_summary_trace_seed(igrid,dL,max_steps,field_min,result)
6719 integer,
intent(in) :: igrid,max_steps
6720 double precision,
intent(in) :: dl,field_min
6723 type(trace_summary_state) :: forward_state,backward_state
6725 call trace_summary_init_state(result%seed,igrid,.true.,1,.false.,forward_state)
6726 call trace_summary_trace_state_to_end(forward_state,dl,max_steps,field_min)
6727 call trace_summary_init_state(result%seed,igrid,.false.,1,.false.,backward_state)
6728 call trace_summary_trace_state_to_end(backward_state,dl,max_steps,field_min)
6730 result%forward_footpoint=forward_state%footpoint
6731 result%forward_length=forward_state%length
6732 result%forward_nstep=forward_state%nstep
6733 result%forward_status=forward_state%status
6734 result%backward_footpoint=backward_state%footpoint
6735 result%backward_length=backward_state%length
6736 result%backward_nstep=backward_state%nstep
6737 result%backward_status=backward_state%status
6738 result%total_length=result%forward_length+result%backward_length
6739 end subroutine trace_summary_trace_seed
6741 subroutine trace_summary_trace_twist_seed(igrid,dL,max_steps,field_min, &
6743 integer,
intent(in) :: igrid,max_steps
6744 double precision,
intent(in) :: dl,field_min
6747 type(trace_summary_state) :: forward_state,backward_state
6749 call trace_summary_init_state(result%line%seed,igrid,.true.,1,.true., &
6751 call trace_summary_trace_state_to_end(forward_state,dl,max_steps,field_min)
6752 call trace_summary_init_state(result%line%seed,igrid,.false.,1,.true., &
6754 call trace_summary_trace_state_to_end(backward_state,dl,max_steps,field_min)
6756 result%line%forward_footpoint=forward_state%footpoint
6757 result%line%forward_length=forward_state%length
6758 result%line%forward_nstep=forward_state%nstep
6759 result%line%forward_status=forward_state%status
6760 result%line%backward_footpoint=backward_state%footpoint
6761 result%line%backward_length=backward_state%length
6762 result%line%backward_nstep=backward_state%nstep
6763 result%line%backward_status=backward_state%status
6764 result%line%total_length=result%line%forward_length &
6765 +result%line%backward_length
6766 result%forward_twist=forward_state%twist
6767 result%backward_twist=backward_state%twist
6768 result%total_twist=result%forward_twist+result%backward_twist
6769 result%status_twist=trace_summary_twist_status_from_states( &
6770 forward_state,backward_state)
6772 end subroutine trace_summary_trace_twist_seed
6774 subroutine trace_summary_init_state(xseed,igrid,forward,seed_id, &
6775 accumulate_twist,state)
6776 double precision,
intent(in) :: xseed(
ndim)
6777 integer,
intent(in) :: igrid,seed_id
6778 logical,
intent(in) :: forward,accumulate_twist
6779 type(trace_summary_state),
intent(out) :: state
6782 state%footpoint=xseed
6789 state%seed_id=seed_id
6791 state%forward=forward
6793 state%accumulate_twist=accumulate_twist
6795 state%sph_cache%valid=.false.
6796 if (trace_rk45_position_integrator())
then
6797 call trace_rk45_stats_note_direction()
6799 if (trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical) &
6800 call trace_spherical_profile_add_count(trace_profile_directions,1_8)
6801 end subroutine trace_summary_init_state
6803 subroutine trace_summary_trace_state_to_end(state,ds,max_nstep,threshold)
6804 type(trace_summary_state),
intent(inout) :: state
6805 double precision,
intent(in) :: ds,threshold
6806 integer,
intent(in) :: max_nstep
6808 do while(state%active .and. state%nstep<max_nstep)
6809 call trace_summary_advance_state(state,ds,threshold)
6812 if (state%active)
then
6814 state%active=.false.
6816 state%footpoint=state%x
6817 if (trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical) &
6818 call trace_spherical_profile_note_trace_steps(state%nstep)
6819 end subroutine trace_summary_trace_state_to_end
6821 subroutine trace_summary_trace_states_grouped(states,nstate,ds,max_nstep,threshold)
6822 integer,
intent(in) :: nstate,max_nstep
6823 type(trace_summary_state),
intent(inout) :: states(nstate)
6824 double precision,
intent(in) :: ds,threshold
6826 logical,
allocatable :: processed(:)
6827 integer :: istate,jstate,target_grid
6828 logical :: any_active
6830 allocate(processed(nstate))
6834 if (states(istate)%active)
then
6839 if (.not.any_active)
exit
6843 if (.not.states(istate)%active .or. processed(istate)) cycle
6844 target_grid=states(istate)%igrid
6846 if (.not.states(jstate)%active .or. processed(jstate)) cycle
6847 if (states(jstate)%igrid/=target_grid) cycle
6848 call trace_summary_advance_state_in_grid(states(jstate),target_grid, &
6849 ds,max_nstep,threshold)
6850 processed(jstate)=.true.
6854 deallocate(processed)
6855 end subroutine trace_summary_trace_states_grouped
6857 subroutine trace_summary_advance_state_in_grid(state,igrid,ds,max_nstep,threshold)
6858 type(trace_summary_state),
intent(inout) :: state
6859 integer,
intent(in) :: igrid,max_nstep
6860 double precision,
intent(in) :: ds,threshold
6862 do while(state%active .and. state%igrid==igrid .and. &
6863 state%nstep<max_nstep)
6864 call trace_summary_advance_state(state,ds,threshold)
6867 if (state%active .and. state%nstep>=max_nstep)
then
6869 state%active=.false.
6870 state%footpoint=state%x
6871 if (trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical) &
6872 call trace_spherical_profile_note_trace_steps(state%nstep)
6874 end subroutine trace_summary_advance_state_in_grid
6876 subroutine trace_summary_advance_state(state,ds,threshold)
6877 type(trace_summary_state),
intent(inout) :: state
6878 double precision,
intent(in) :: ds,threshold
6880 double precision :: xnext(
ndim),xhit(
ndim),ds_actual,segment_length
6881 double precision :: alpha_hit
6882 double precision :: xbmin^
d,xbmax^
d
6883 double precision :: domain_min(
ndim),domain_max(
ndim)
6884 double precision :: near_tol,best_dist,face_dist
6885 integer :: igrid_next,ipe_next,inblock,step_status,face_id
6886 integer :: idim,best_dim,best_side
6887 integer :: point_domain
6888 double precision :: rk45_twist_increment
6889 integer :: rk45_twist_status
6890 logical :: newpe,stop_trace,hit_ok
6891 logical :: rk45_step,rk45_twist_integrated
6893 if (.not.state%active)
return
6896 rk45_twist_increment=zero
6898 rk45_twist_integrated=.false.
6899 if (trace_integrator_mode==trace_integrator_rk45_cartesian .and. &
6900 trace_cartesian_like_geometry())
then
6902 call trace_summary_rk45_cartesian_step(state%x,state%igrid,ds, &
6903 state%forward,threshold,state%rk45_h,xnext,ds_actual, &
6904 step_status,state%accumulate_twist,rk45_twist_increment, &
6905 rk45_twist_status,rk45_twist_integrated)
6906 else if (trace_integrator_mode==trace_integrator_rk45_spherical .and. &
6907 geo_coordinate==geo_spherical)
then
6909 call trace_summary_rk45_spherical_step(state%x,state%igrid,ds, &
6910 state%forward,threshold,state%rk45_h,state%sph_cache,xnext, &
6911 ds_actual,step_status,state%accumulate_twist, &
6912 rk45_twist_increment,rk45_twist_status,rk45_twist_integrated)
6914 call trace_summary_rk2_step(state%x,state%igrid,ds,state%forward, &
6915 threshold,xnext,ds_actual,step_status,sph_cache=state%sph_cache)
6919 trace_rk45_position_integrator())
then
6920 call trace_boundary_face_at_point(state%x,state%face,hit_ok)
6921 if (.not.hit_ok)
then
6922 ^
d&domain_min(^
d)=xprobmin^
d;
6923 ^
d&domain_max(^
d)=xprobmax^
d;
6924 near_tol=max(100.d0*epsilon(one)* &
6925 max(one,maxval(abs(domain_max-domain_min))), &
6926 1.
d-5*max(one,abs(ds)))
6931 face_dist=abs(state%x(idim)-domain_min(idim))
6932 if (face_dist<best_dist)
then
6937 face_dist=abs(state%x(idim)-domain_max(idim))
6938 if (face_dist<best_dist)
then
6944 if (best_dim>0 .and. best_dist<=near_tol)
then
6945 if (best_side<0)
then
6946 state%x(best_dim)=domain_min(best_dim)
6948 state%x(best_dim)=domain_max(best_dim)
6950 state%footpoint=state%x
6951 state%face=trace_face_from_dim_side(best_dim,best_side)
6957 state%active=.false.
6961 state%status=step_status
6962 state%active=.false.
6967 {
if (xnext(^db)>=xprobmin^db .and. xnext(^db)<xprobmax^db) point_domain=point_domain+1\}
6968 if (point_domain/=
ndim)
then
6969 call trace_intersect_domain(state%x,xnext,xhit,hit_ok,face_id, &
6972 if (trace_rk45_position_integrator() .and. &
6974 segment_length=abs(ds_actual)
6976 segment_length=trace_segment_length(state%x,xhit,ds_actual, &
6979 if (state%accumulate_twist .and. &
6981 if (rk45_step .and. rk45_twist_integrated)
then
6982 state%twist=state%twist+rk45_twist_increment
6984 state%twist_status=rk45_twist_status
6986 call trace_summary_accumulate_twist(state,xhit,segment_length, &
6987 threshold,step_status)
6989 state%twist_status=step_status
6993 state%length=state%length+segment_length
6995 state%nstep=state%nstep+1
6996 if (trace_spherical_profile_enabled .and. &
6997 geo_coordinate==geo_spherical)
then
6998 call trace_spherical_profile_add_count(trace_profile_steps,1_8)
7001 state%footpoint=state%x
7004 if (trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical) &
7005 call trace_spherical_profile_add_count(trace_profile_boundary_events, &
7008 state%active=.false.
7009 if (trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical) &
7010 call trace_spherical_profile_note_trace_steps(state%nstep)
7014 if (state%accumulate_twist .and. &
7016 if (rk45_step .and. rk45_twist_integrated)
then
7017 state%twist=state%twist+rk45_twist_increment
7019 state%twist_status=rk45_twist_status
7021 call trace_summary_accumulate_twist(state,xnext,ds_actual,threshold, &
7024 state%twist_status=step_status
7029 state%length=state%length+abs(ds_actual)
7031 state%length=state%length+trace_segment_length(state%x,xnext, &
7034 state%nstep=state%nstep+1
7035 if (trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical) &
7036 call trace_spherical_profile_add_count(trace_profile_steps,1_8)
7038 state%footpoint=state%x
7043 {
if (state%x(^db)>=xbmin^db .and. state%x(^db)<xbmax^db) inblock=inblock+1\}
7044 if (inblock==
ndim)
return
7046 igrid_next=state%igrid
7050 call find_next_grid(state%igrid,igrid_next,ipe_next,state%x,newpe,stop_trace)
7051 if (stop_trace)
then
7053 state%active=.false.
7054 if (trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical) &
7055 call trace_spherical_profile_add_count(trace_profile_boundary_events, &
7057 if (trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical) &
7058 call trace_spherical_profile_note_trace_steps(state%nstep)
7061 if (newpe .or. ipe_next/=
mype)
then
7062 if (trace_rk45_position_integrator())
then
7063 call trace_boundary_face_at_point(state%x,state%face,hit_ok)
7064 if (.not.hit_ok)
then
7065 ^
d&domain_min(^
d)=xprobmin^
d;
7066 ^
d&domain_max(^
d)=xprobmax^
d;
7067 near_tol=max(100.d0*epsilon(one)* &
7068 max(one,maxval(abs(domain_max-domain_min))), &
7069 1.
d-6*max(one,abs(ds_actual)))
7074 face_dist=abs(state%x(idim)-domain_min(idim))
7075 if (face_dist<best_dist)
then
7080 face_dist=abs(state%x(idim)-domain_max(idim))
7081 if (face_dist<best_dist)
then
7087 if (best_dim>0 .and. best_dist<=near_tol)
then
7088 if (best_side<0)
then
7089 state%x(best_dim)=domain_min(best_dim)
7091 state%x(best_dim)=domain_max(best_dim)
7093 state%footpoint=state%x
7094 state%face=trace_face_from_dim_side(best_dim,best_side)
7100 state%active=.false.
7105 state%active=.false.
7106 if (trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical) &
7107 call trace_spherical_profile_note_trace_steps(state%nstep)
7110 state%igrid=igrid_next
7111 end subroutine trace_summary_advance_state
7113 subroutine trace_summary_accumulate_twist(state,xend,segment_length, &
7115 type(trace_summary_state),
intent(inout) :: state
7116 double precision,
intent(in) :: xend(
ndim),segment_length,threshold
7117 integer,
intent(out) :: status
7119 double precision :: xmid(
ndim),b(3),curlb(3),b2,twist_density
7122 if (segment_length<=zero)
return
7124 xmid=half*(state%x+xend)
7125 call sample_b_curlb_at_point(xmid,state%igrid,threshold,b,curlb,status, &
7126 sph_cache=state%sph_cache)
7130 twist_density=sum(curlb*b)/(4.d0*dpi*b2)
7132 state%twist=state%twist+twist_density*segment_length
7133 end subroutine trace_summary_accumulate_twist
7135 subroutine trace_twist_density_at_point(x,igrid,threshold,twist_density, &
7137 double precision,
intent(in) :: x(
ndim),threshold
7138 integer,
intent(in) :: igrid
7139 double precision,
intent(out) :: twist_density
7140 integer,
intent(out) :: status
7141 type(trace_sph_interp_ctx),
intent(inout),
optional :: sph_cache
7143 double precision :: b(3),curlb(3),b2
7146 call sample_b_curlb_at_point(x,igrid,threshold,b,curlb,status, &
7147 sph_cache=sph_cache)
7155 twist_density=sum(curlb*b)/(4.d0*dpi*b2)
7156 end subroutine trace_twist_density_at_point
7158 subroutine trace_tangent_accumulate_twist(state,xend,segment_length, &
7160 type(trace_tangent_state),
intent(inout) :: state
7161 double precision,
intent(in) :: xend(
ndim),segment_length,threshold
7163 double precision :: xmid(
ndim),twist_density
7165 if (.not.state%accumulate_twist)
return
7167 if (segment_length<=zero)
return
7168 xmid=half*(state%x+xend)
7169 call trace_twist_density_at_point(xmid,state%igrid,threshold, &
7170 twist_density,state%twist_status,sph_cache=state%sph_cache)
7172 state%twist=state%twist+twist_density*segment_length
7173 end subroutine trace_tangent_accumulate_twist
7175 integer function trace_summary_twist_status_from_states(forward_state, &
7176 backward_state)
result(status_twist)
7177 type(trace_summary_state),
intent(in) :: forward_state,backward_state
7181 status_twist=forward_state%status
7183 status_twist=backward_state%status
7185 status_twist=forward_state%twist_status
7187 status_twist=backward_state%twist_status
7189 end function trace_summary_twist_status_from_states
7191 subroutine trace_tangent_fill_twist_result(seed,forward_state, &
7192 backward_state,result)
7193 double precision,
intent(in) :: seed(
ndim)
7194 type(trace_tangent_state),
intent(in) :: forward_state,backward_state
7197 result%line%seed=seed
7198 result%line%forward_footpoint=forward_state%endpoint
7199 result%line%backward_footpoint=backward_state%endpoint
7200 result%line%forward_length=forward_state%length
7201 result%line%backward_length=backward_state%length
7202 result%line%total_length=forward_state%length+backward_state%length
7203 result%line%forward_nstep=forward_state%nstep
7204 result%line%backward_nstep=backward_state%nstep
7205 result%line%forward_status=forward_state%status
7206 result%line%backward_status=backward_state%status
7207 result%forward_twist=forward_state%twist
7208 result%backward_twist=backward_state%twist
7209 result%total_twist=forward_state%twist+backward_state%twist
7212 result%status_twist=forward_state%status
7214 result%status_twist=backward_state%status
7216 result%status_twist=forward_state%twist_status
7218 result%status_twist=backward_state%twist_status
7221 end subroutine trace_tangent_fill_twist_result
7223 subroutine trace_total_b_at_cell(igrid,ix1,ix2,ix3,B,status)
7224 integer,
intent(in) :: igrid,ix1,ix2,ix3
7225 double precision,
intent(out) :: b(3)
7226 integer,
intent(out) :: status
7230 if (
ndim/=3 .or. igrid<0)
return
7233 if (.not.
b0field .and. .not.
allocated(iw_mag))
return
7234 if (
allocated(iw_mag))
then
7235 b(1:3)=ps(igrid)%w(ix1,ix2,ix3,iw_mag(1:3))
7238 b(1:3)=b(1:3)+ps(igrid)%B0(ix1,ix2,ix3,1:3,0)
7242 end subroutine trace_total_b_at_cell
7244 subroutine trace_bhat_at_cell(igrid,ix1,ix2,ix3,threshold,bhat,status)
7245 integer,
intent(in) :: igrid,ix1,ix2,ix3
7246 double precision,
intent(in) :: threshold
7247 double precision,
intent(out) :: bhat(3)
7248 integer,
intent(out) :: status
7250 double precision :: b(3),bnorm
7253 call trace_total_b_at_cell(igrid,ix1,ix2,ix3,b,status)
7256 bnorm=dsqrt(sum(b**2))
7257 if (bnorm<=zero .or. bnorm<threshold)
then
7262 end subroutine trace_bhat_at_cell
7264 subroutine sample_bhat_gradbhat_at_point(x,igrid,threshold,bhat, &
7267 double precision,
intent(in) :: x(
ndim),threshold
7268 integer,
intent(in) :: igrid
7269 double precision,
intent(out) :: bhat(3),grad_bhat(3,3)
7270 integer,
intent(out) :: status
7272 call sample_bhat_gradbhat_interpderiv_at_point(x,igrid,threshold,bhat, &
7274 end subroutine sample_bhat_gradbhat_at_point
7276 subroutine sample_bhat_gradbhat_cellfd_at_point(x,igrid,threshold,bhat, &
7279 double precision,
intent(in) :: x(
ndim),threshold
7280 integer,
intent(in) :: igrid
7281 double precision,
intent(out) :: bhat(3),grad_bhat(3,3)
7282 integer,
intent(out) :: status
7284 double precision :: dxb^
d,dxc^
d,xd^
d
7285 double precision :: bhat_cell(0:1^
d&,3)
7286 double precision :: grad_cell(0:1^
d&,3,3)
7287 double precision :: factor(0:1^
d&)
7288 double precision :: bhat_center(3),bhat_plus(3),bhat_minus(3)
7289 integer :: ixi^
l,ixbl^
d,ix^
d,j,k
7294 if (
ndim/=3 .or. igrid<0)
return
7299 ^
d&ixbl^
d=floor((x(^
d)-ps(igrid)%x(iximin^dd,^
d))/dxb^
d)+iximin^
d;
7300 ^
d&xd^
d=(x(^
d)-ps(igrid)%x(ixbl^dd,^
d))/dxb^
d;
7302 if (ixbl1-1<iximin1 .or. ixbl1+2>iximax1 .or. &
7303 ixbl2-1<iximin2 .or. ixbl2+2>iximax2 .or. &
7304 ixbl3-1<iximin3 .or. ixbl3+2>iximax3)
return
7309 call trace_bhat_at_cell(igrid,ixbl1+ix1,ixbl2+ix2, &
7310 ixbl3+ix3,threshold,bhat_center,status)
7312 bhat_cell(ix^
d,1:3)=bhat_center
7314 call trace_bhat_at_cell(igrid,ixbl1+ix1+1,ixbl2+ix2, &
7315 ixbl3+ix3,threshold,bhat_plus,status)
7317 call trace_bhat_at_cell(igrid,ixbl1+ix1-1,ixbl2+ix2, &
7318 ixbl3+ix3,threshold,bhat_minus,status)
7320 grad_cell(ix^
d,1:3,1)=(bhat_plus-bhat_minus)/(2.d0*dxb1)
7322 call trace_bhat_at_cell(igrid,ixbl1+ix1,ixbl2+ix2+1, &
7323 ixbl3+ix3,threshold,bhat_plus,status)
7325 call trace_bhat_at_cell(igrid,ixbl1+ix1,ixbl2+ix2-1, &
7326 ixbl3+ix3,threshold,bhat_minus,status)
7328 grad_cell(ix^
d,1:3,2)=(bhat_plus-bhat_minus)/(2.d0*dxb2)
7330 call trace_bhat_at_cell(igrid,ixbl1+ix1,ixbl2+ix2, &
7331 ixbl3+ix3+1,threshold,bhat_plus,status)
7333 call trace_bhat_at_cell(igrid,ixbl1+ix1,ixbl2+ix2, &
7334 ixbl3+ix3-1,threshold,bhat_minus,status)
7336 grad_cell(ix^
d,1:3,3)=(bhat_plus-bhat_minus)/(2.d0*dxb3)
7340 factor(ix^
d)={abs(1-ix^
d-xd^
d)*}
7344 bhat(j)=bhat(j)+bhat_cell(ix^
d,j)*factor(ix^
d)
7346 grad_bhat(j,k)=grad_bhat(j,k)+grad_cell(ix^
d,j,k)*factor(ix^
d)
7353 end subroutine sample_bhat_gradbhat_cellfd_at_point
7355 subroutine sample_bhat_gradbhat_xeps_at_point(x,eps,threshold,bhat, &
7358 double precision,
intent(in) :: x(
ndim),eps,threshold
7359 double precision,
intent(out) :: bhat(3),grad_bhat(3,3)
7360 integer,
intent(out) :: status
7362 double precision :: xp(
ndim),xm(
ndim)
7363 double precision :: b(3),bp(3),bm(3),bhat_p(3),bhat_m(3)
7364 double precision :: bnorm,bpnorm,bmnorm
7365 integer :: igrid,idir,point_domain
7379 call trace_debug_locate_point(x,igrid,status)
7381 call sample_b_at_point(x,igrid,threshold,b,status)
7383 bnorm=dsqrt(sum(b**2))
7384 if (bnorm<=zero .or. bnorm<threshold)
then
7393 xp(idir)=xp(idir)+eps
7394 xm(idir)=xm(idir)-eps
7397 {
if (xp(^db)>=xprobmin^db .and. xp(^db)<xprobmax^db) point_domain=point_domain+1\}
7398 if (point_domain/=
ndim)
then
7402 call trace_debug_locate_point(xp,igrid,status)
7404 call sample_b_at_point(xp,igrid,threshold,bp,status)
7406 bpnorm=dsqrt(sum(bp**2))
7407 if (bpnorm<=zero .or. bpnorm<threshold)
then
7414 {
if (xm(^db)>=xprobmin^db .and. xm(^db)<xprobmax^db) point_domain=point_domain+1\}
7415 if (point_domain/=
ndim)
then
7419 call trace_debug_locate_point(xm,igrid,status)
7421 call sample_b_at_point(xm,igrid,threshold,bm,status)
7423 bmnorm=dsqrt(sum(bm**2))
7424 if (bmnorm<=zero .or. bmnorm<threshold)
then
7430 grad_bhat(1:3,idir)=(bhat_p-bhat_m)/(2.d0*eps)
7434 end subroutine sample_bhat_gradbhat_xeps_at_point
7436 subroutine sample_bhat_gradbhat_interpderiv_at_point(x,igrid,threshold, &
7437 bhat,grad_bhat,status)
7439 double precision,
intent(in) :: x(
ndim),threshold
7440 integer,
intent(in) :: igrid
7441 double precision,
intent(out) :: bhat(3),grad_bhat(3,3)
7442 integer,
intent(out) :: status
7444 double precision :: dxb^
d,dxc^
d,xd^
d
7445 double precision :: field(0:1^
d&,3)
7446 double precision :: b(3),dbdx(3,3)
7447 double precision :: wx(0:1),wy(0:1),wz(0:1)
7448 double precision :: dwx(0:1),dwy(0:1),dwz(0:1)
7449 double precision :: weight,bnorm,projected
7450 integer :: ixi^
l,ixbl^
d,ix^
d,j
7455 if (
ndim/=3 .or. .not.trace_cartesian_like_geometry() .or. igrid<0)
then
7462 call trace_interp_weights_block(x,igrid,ixi^
l,ixbl^
d,xd^
d,dxc^
d, &
7466 if (ixbl1<iximin1 .or. ixbl1+1>iximax1 .or. &
7467 ixbl2<iximin2 .or. ixbl2+1>iximax2 .or. &
7468 ixbl3<iximin3 .or. ixbl3+1>iximax3)
return
7471 if (.not.
b0field .and. .not.
allocated(iw_mag))
return
7475 if (
allocated(iw_mag))
then
7476 field(ix^
d,1:3)=ps(igrid)%w(ixbl1+ix1,ixbl2+ix2, &
7477 ixbl3+ix3,iw_mag(1:3))
7480 field(ix^
d,1:3)=field(ix^
d,1:3) &
7481 +ps(igrid)%B0(ixbl1+ix1,ixbl2+ix2,ixbl3+ix3,1:3,0)
7501 weight=wx(ix1)*wy(ix2)*wz(ix3)
7502 b(1:3)=b(1:3)+field(ix^
d,1:3)*weight
7503 dbdx(1:3,1)=dbdx(1:3,1)+field(ix^
d,1:3)* &
7504 dwx(ix1)*wy(ix2)*wz(ix3)
7505 dbdx(1:3,2)=dbdx(1:3,2)+field(ix^
d,1:3)* &
7506 wx(ix1)*dwy(ix2)*wz(ix3)
7507 dbdx(1:3,3)=dbdx(1:3,3)+field(ix^
d,1:3)* &
7508 wx(ix1)*wy(ix2)*dwz(ix3)
7511 bnorm=dsqrt(sum(b**2))
7512 if (bnorm<=zero .or. bnorm<threshold)
then
7519 projected=sum(bhat*dbdx(1:3,j))
7520 grad_bhat(1:3,j)=(dbdx(1:3,j)-bhat(1:3)*projected)/bnorm
7525 end subroutine sample_bhat_gradbhat_interpderiv_at_point
7527 subroutine sample_b_curlb_at_point(x,igrid,threshold,B,curlB,status, &
7530 double precision,
intent(in) :: x(
ndim),threshold
7531 integer,
intent(in) :: igrid
7532 double precision,
intent(out) :: b(3),curlb(3)
7533 integer,
intent(out) :: status
7534 type(trace_sph_interp_ctx),
intent(inout),
optional :: sph_cache
7536 double precision :: dxb^
d,dxc^
d,xd^
d
7537 double precision :: field(0:1^
d&,3),current(0:1^D&,3)
7538 double precision :: factor(0:1^
d&),B2
7539 double precision :: dx1c,dx2c,dx3c
7540 integer :: ixi^
l,ixj^
l,ixbl^
d,ix^
d,j
7547 if (geo_coordinate==geo_spherical)
then
7548 if (
present(sph_cache))
then
7549 call sample_b_curlb_spherical_at_point(x,igrid,threshold,b,curlb, &
7550 status,sph_cache=sph_cache)
7552 call sample_b_curlb_spherical_at_point(x,igrid,threshold,b,curlb, &
7561 call trace_interp_weights_block(x,igrid,ixi^
l,ixbl^
d,xd^
d,dxc^
d, &
7565 if (ixbl1-1<iximin1 .or. ixbl1+2>iximax1 .or. &
7566 ixbl2-1<iximin2 .or. ixbl2+2>iximax2 .or. &
7567 ixbl3-1<iximin3 .or. ixbl3+2>iximax3)
return
7569 if (ixbl1<ixjmin1 .or. ixbl1+1>ixjmax1 .or. &
7570 ixbl2<ixjmin2 .or. ixbl2+1>ixjmax2 .or. &
7571 ixbl3<ixjmin3 .or. ixbl3+1>ixjmax3)
return
7574 if (.not.
b0field .and. .not.
allocated(iw_mag))
return
7579 if (
allocated(iw_mag))
then
7580 field(ix^
d,1:3)=ps(igrid)%w(ixbl1+ix1,ixbl2+ix2, &
7581 ixbl3+ix3,iw_mag(1:3))
7584 field(ix^
d,1:3)=field(ix^
d,1:3) &
7585 +ps(igrid)%B0(ixbl1+ix1,ixbl2+ix2,ixbl3+ix3,1:3,0)
7587 if (
allocated(iw_mag))
then
7588 dx1c=ps(igrid)%x(ixbl1+ix1+1,ixbl2+ix2,ixbl3+ix3,1) &
7589 -ps(igrid)%x(ixbl1+ix1-1,ixbl2+ix2,ixbl3+ix3,1)
7590 dx2c=ps(igrid)%x(ixbl1+ix1,ixbl2+ix2+1,ixbl3+ix3,2) &
7591 -ps(igrid)%x(ixbl1+ix1,ixbl2+ix2-1,ixbl3+ix3,2)
7592 dx3c=ps(igrid)%x(ixbl1+ix1,ixbl2+ix2,ixbl3+ix3+1,3) &
7593 -ps(igrid)%x(ixbl1+ix1,ixbl2+ix2,ixbl3+ix3-1,3)
7594 if (abs(dx1c)<=smalldouble .or. abs(dx2c)<=smalldouble .or. &
7595 abs(dx3c)<=smalldouble)
then
7599 current(ix^
d,1)=half*( &
7600 (ps(igrid)%w(ixbl1+ix1,ixbl2+ix2+1,ixbl3+ix3,iw_mag(3)) &
7601 -ps(igrid)%w(ixbl1+ix1,ixbl2+ix2-1,ixbl3+ix3,iw_mag(3)))/dx2c &
7602 -(ps(igrid)%w(ixbl1+ix1,ixbl2+ix2,ixbl3+ix3+1,iw_mag(2)) &
7603 -ps(igrid)%w(ixbl1+ix1,ixbl2+ix2,ixbl3+ix3-1,iw_mag(2)))/dx3c)
7604 current(ix^
d,2)=half*( &
7605 (ps(igrid)%w(ixbl1+ix1,ixbl2+ix2,ixbl3+ix3+1,iw_mag(1)) &
7606 -ps(igrid)%w(ixbl1+ix1,ixbl2+ix2,ixbl3+ix3-1,iw_mag(1)))/dx3c &
7607 -(ps(igrid)%w(ixbl1+ix1+1,ixbl2+ix2,ixbl3+ix3,iw_mag(3)) &
7608 -ps(igrid)%w(ixbl1+ix1-1,ixbl2+ix2,ixbl3+ix3,iw_mag(3)))/dx1c)
7609 current(ix^
d,3)=half*( &
7610 (ps(igrid)%w(ixbl1+ix1+1,ixbl2+ix2,ixbl3+ix3,iw_mag(2)) &
7611 -ps(igrid)%w(ixbl1+ix1-1,ixbl2+ix2,ixbl3+ix3,iw_mag(2)))/dx1c &
7612 -(ps(igrid)%w(ixbl1+ix1,ixbl2+ix2+1,ixbl3+ix3,iw_mag(1)) &
7613 -ps(igrid)%w(ixbl1+ix1,ixbl2+ix2-1,ixbl3+ix3,iw_mag(1)))/dx2c)
7616 current(ix^
d,1:3)=current(ix^
d,1:3) &
7617 +ps(igrid)%J0(ixbl^
d+ix^
d,1:3)
7622 factor(ix^
d)={abs(1-ix^
d-xd^
d)*}
7626 b(j)=b(j)+field(ix^
d,j)*factor(ix^
d)
7627 curlb(j)=curlb(j)+current(ix^
d,j)*factor(ix^
d)
7632 if (b2<=zero .or. dsqrt(b2)<threshold)
then
7638 end subroutine sample_b_curlb_at_point
7640 subroutine sample_b_curlb_spherical_at_point(x,igrid,threshold,B,curlB, &
7644 double precision,
intent(in) :: x(
ndim),threshold
7645 integer,
intent(in) :: igrid
7646 double precision,
intent(out) :: b(3),curlb(3)
7647 integer,
intent(out) :: status
7648 type(trace_sph_interp_ctx),
intent(inout),
optional :: sph_cache
7650 double precision :: dxb^
d,dxc^
d,xd^
d
7651 double precision :: bvec(ixg^t,1:3),current(ixg^t,1:3)
7652 double precision :: factor(0:1^
d&),B2
7653 type(trace_sph_interp_ctx) :: ctx
7654 integer :: ixi^
l,ixo^
l,ixa^
l,ixj^
l,ixbl^
d,ix^
d,j,idirmin
7659 if (
ndim/=3 .or. geo_coordinate/=geo_spherical .or. igrid<0)
return
7662 if (
present(sph_cache))
then
7663 call trace_spherical_interp_ctx_build_cached(x,igrid,sph_cache,ctx, &
7666 call trace_spherical_interp_ctx_build(x,igrid,ctx,status)
7669 call trace_spherical_sample_bsph_ctx(ctx,threshold,b,status)
7671 if (trace_spherical_curl_cache_ready)
then
7672 call trace_spherical_sample_cached_curlb_ctx(ctx,curlb,status)
7675 if (b2<=zero .or. dsqrt(b2)<threshold)
then
7686 ^
d&dxc^
d=ctx%dxc(^
d);
7688 ^
d&ixbl^
d=ctx%ixbl(^
d);
7690 ^
d&ixomax^
d=ixbl^
d+1;
7694 if (iximin1>ixamin1 .or. iximax1<ixamax1 .or. &
7695 iximin2>ixamin2 .or. iximax2<ixamax2 .or. &
7696 iximin3>ixamin3 .or. iximax3<ixamax3)
return
7698 if (ixjmin1>ixomin1 .or. ixjmax1<ixomax1 .or. &
7699 ixjmin2>ixomin2 .or. ixjmax2<ixomax2 .or. &
7700 ixjmin3>ixomin3 .or. ixjmax3<ixomax3)
return
7703 if (.not.
b0field .and. .not.
allocated(iw_mag))
return
7707 if (
allocated(iw_mag))
then
7708 bvec(ixa^s,1:3)=ps(igrid)%w(ixa^s,iw_mag(1:3))
7714 current(ixo^s,1:3)=current(ixo^s,1:3)+ps(igrid)%J0(ixo^s,1:3)
7718 factor(ix^
d)={abs(1-ix^
d-xd^
d)*}
7722 curlb(j)=curlb(j)+current(ixbl^
d+ix^
d,j)*factor(ix^
d)
7727 if (b2<=zero .or. dsqrt(b2)<threshold)
then
7733 end subroutine sample_b_curlb_spherical_at_point
7735 subroutine sample_b_at_point(x,igrid,threshold,B,status)
7737 double precision,
intent(in) :: x(
ndim),threshold
7738 integer,
intent(in) :: igrid
7739 double precision,
intent(out) :: b(3)
7740 integer,
intent(out) :: status
7742 double precision :: dxb^
d,dxc^
d,xd^
d
7743 double precision :: field(0:1^
d&,3),factor(0:1^D&),B2
7744 double precision :: bcell(3)
7745 type(trace_sph_interp_ctx) :: ctx
7746 integer :: ixi^
l,ixbl^
d,ix^
d,j
7750 if (
ndim/=3 .or. igrid<0)
return
7754 if (geo_coordinate==geo_spherical)
then
7755 call trace_spherical_interp_ctx_build(x,igrid,ctx,status)
7757 call trace_spherical_sample_bsph_ctx(ctx,threshold,b,status)
7760 call trace_interp_weights_block(x,igrid,ixi^
l,ixbl^
d,xd^
d,dxc^
d, &
7765 if (ixbl1<iximin1 .or. ixbl1+1>iximax1 .or. &
7766 ixbl2<iximin2 .or. ixbl2+1>iximax2 .or. &
7767 ixbl3<iximin3 .or. ixbl3+1>iximax3)
return
7770 call trace_total_b_at_cell(igrid,ixbl1+ix1,ixbl2+ix2, &
7771 ixbl3+ix3,bcell,status)
7773 field(ix^
d,1:3)=bcell
7777 factor(ix^
d)={abs(1-ix^
d-xd^
d)*}
7781 b(j)=b(j)+field(ix^
d,j)*factor(ix^
d)
7786 if (b2<=zero .or. dsqrt(b2)<threshold)
then
7792 end subroutine sample_b_at_point
7794 subroutine trace_summary_fill_mapping(seed,source_igrid,forward_state, &
7795 backward_state,threshold,have_source_normal,source_normal,result)
7796 double precision,
intent(in) :: seed(
ndim),threshold,source_normal(3)
7797 integer,
intent(in) :: source_igrid
7798 logical,
intent(in) :: have_source_normal
7799 type(trace_summary_state),
intent(in) :: forward_state,backward_state
7806 result%forward_footpoint=forward_state%footpoint
7807 result%backward_footpoint=backward_state%footpoint
7808 result%forward_length=forward_state%length
7809 result%backward_length=backward_state%length
7810 result%forward_face=forward_state%face
7811 result%backward_face=backward_state%face
7812 result%forward_status=forward_state%status
7813 result%backward_status=backward_state%status
7815 call sample_b_at_point(seed,source_igrid,threshold,result%source_B,status)
7817 result%forward_status=status
7818 result%backward_status=status
7819 result%valid=.false.
7822 if (have_source_normal)
then
7823 result%source_Bn=sum(result%source_B*source_normal)
7827 call sample_b_at_point(forward_state%footpoint,forward_state%igrid, &
7828 threshold,result%forward_B,status)
7832 call sample_b_at_point(backward_state%footpoint,backward_state%igrid, &
7833 threshold,result%backward_B,status)
7837 result%forward_Bn=trace_face_bn(result%forward_face,result%forward_B)
7838 result%backward_Bn=trace_face_bn(result%backward_face,result%backward_B)
7841 trace_face_is_boundary(result%forward_face) .and. &
7842 trace_face_is_boundary(result%backward_face)
7843 end subroutine trace_summary_fill_mapping
7845 double precision function trace_face_bn(face_id,B)
result(Bn)
7846 integer,
intent(in) :: face_id
7847 double precision,
intent(in) :: b(3)
7850 select case(face_id)
7864 end function trace_face_bn
7866 logical function trace_face_is_boundary(face_id)
result(is_boundary)
7867 integer,
intent(in) :: face_id
7870 end function trace_face_is_boundary
7872 subroutine trace_boundary_face_at_point(x,face_id,on_boundary)
7873 double precision,
intent(in) :: x(
ndim)
7874 integer,
intent(out) :: face_id
7875 logical,
intent(out) :: on_boundary
7877 double precision :: domain_min(
ndim),domain_max(
ndim),tol
7878 integer :: idim,nface,candidate_face
7880 ^
d&domain_min(^
d)=xprobmin^
d;
7881 ^
d&domain_max(^
d)=xprobmax^
d;
7882 tol=100.d0*epsilon(one)*max(one,maxval(abs(domain_max-domain_min)))
7886 if (abs(x(idim)-domain_min(idim))<=tol)
then
7887 candidate_face=trace_face_from_dim_side(idim,-1)
7890 face_id=candidate_face
7891 else if (candidate_face/=face_id)
then
7895 if (abs(x(idim)-domain_max(idim))<=tol)
then
7896 candidate_face=trace_face_from_dim_side(idim,1)
7899 face_id=candidate_face
7900 else if (candidate_face/=face_id)
then
7906 end subroutine trace_boundary_face_at_point
7908 subroutine trace_intersect_domain(xinside,xoutside,xhit,hit_ok,face_id, &
7910 double precision,
intent(in) :: xinside(
ndim),xoutside(
ndim)
7911 double precision,
intent(out) :: xhit(
ndim)
7912 logical,
intent(out) :: hit_ok
7913 integer,
intent(out) :: face_id
7914 double precision,
intent(out),
optional :: alpha_out
7916 double precision :: alpha,alpha_hit,alpha_tol,delta
7917 double precision :: domain_min(
ndim),domain_max(
ndim)
7918 integer :: idim,hit_dim,hit_side,candidate_face
7920 ^
d&domain_min(^
d)=xprobmin^
d;
7921 ^
d&domain_max(^
d)=xprobmax^
d;
7923 alpha_tol=100.d0*epsilon(one)
7928 delta=xoutside(idim)-xinside(idim)
7929 if (xoutside(idim)<domain_min(idim) .and. abs(delta)>smalldouble)
then
7930 alpha=(domain_min(idim)-xinside(idim))/delta
7931 if (alpha>=zero .and. alpha<=one)
then
7932 candidate_face=trace_face_from_dim_side(idim,-1)
7933 if (alpha<alpha_hit-alpha_tol)
then
7937 face_id=candidate_face
7938 else if (abs(alpha-alpha_hit)<=alpha_tol .and. &
7939 candidate_face/=face_id)
then
7943 else if (xoutside(idim)>=domain_max(idim) .and. &
7944 abs(delta)>smalldouble)
then
7945 alpha=(domain_max(idim)-xinside(idim))/delta
7946 if (alpha>=zero .and. alpha<=one)
then
7947 candidate_face=trace_face_from_dim_side(idim,1)
7948 if (alpha<alpha_hit-alpha_tol)
then
7952 face_id=candidate_face
7953 else if (abs(alpha-alpha_hit)<=alpha_tol .and. &
7954 candidate_face/=face_id)
then
7963 if (
present(alpha_out)) alpha_out=zero
7964 if (.not.hit_ok)
return
7966 xhit=xinside+alpha_hit*(xoutside-xinside)
7968 xhit(idim)=min(max(xhit(idim),domain_min(idim)),domain_max(idim))
7970 if (hit_side<0)
then
7971 xhit(hit_dim)=domain_min(hit_dim)
7973 xhit(hit_dim)=domain_max(hit_dim)
7975 if (
present(alpha_out)) alpha_out=alpha_hit
7976 end subroutine trace_intersect_domain
7978 integer function trace_face_from_dim_side(idim,side)
result(face_id)
7979 integer,
intent(in) :: idim,side
8002 end function trace_face_from_dim_side
8004 subroutine trace_cartesian_local_cell_size(x,igrid,hcell,status)
8005 double precision,
intent(in) :: x(
ndim)
8006 integer,
intent(in) :: igrid
8007 double precision,
intent(out) :: hcell
8008 integer,
intent(out) :: status
8010 double precision :: dxc^
d,xd^
d
8011 integer :: ixi^
l,ixbl^
d
8015 if (.not.trace_cartesian_like_geometry() .or. igrid<0)
return
8019 call trace_interp_weights_block(x,igrid,ixi^
l,ixbl^
d,xd^
d,dxc^
d, &
8022 hcell=min(abs(dxc1),abs(dxc2))
8023 hcell=min(hcell,abs(dxc3))
8026 end subroutine trace_cartesian_local_cell_size
8028 subroutine trace_cartesian_rhs_bhat(x,igrid_hint,threshold,bhat,igrid, &
8030 double precision,
intent(in) :: x(
ndim),threshold
8031 integer,
intent(in) :: igrid_hint
8032 double precision,
intent(out) :: bhat(
ndim)
8033 integer,
intent(out) :: igrid,status
8035 double precision :: dxc^
d,xd^
d
8036 double precision :: field(0:1^
d&,3),factor(0:1^D&)
8037 double precision :: bcell(3),b(3),bnorm
8038 integer :: ixi^
l,ixbl^
d,ix^
d,j
8043 if (.not.trace_cartesian_like_geometry())
return
8046 call trace_locate_point_with_hint(x,igrid_hint,igrid,status)
8050 call trace_interp_weights_block(x,igrid,ixi^
l,ixbl^
d,xd^
d,dxc^
d, &
8056 call trace_total_b_at_cell(igrid,ixbl1+ix1,ixbl2+ix2, &
8057 ixbl3+ix3,bcell,status)
8059 field(ix^
d,1:3)=bcell
8063 factor(ix^
d)={abs(1-ix^
d-xd^
d)*}
8069 b(j)=b(j)+field(ix^
d,j)*factor(ix^
d)
8073 bnorm=dsqrt(sum(b**2))
8074 if (bnorm<=zero .or. bnorm<threshold)
then
8078 bhat=b(1:
ndim)/bnorm
8081 end subroutine trace_cartesian_rhs_bhat
8083 subroutine trace_rk45_try_boundary_finish(xnow,xstage,hfloor,xnext, &
8084 ds_actual,h_suggest,status,finished)
8085 double precision,
intent(in) :: xnow(
ndim),xstage(
ndim),hfloor
8086 double precision,
intent(out) :: xnext(
ndim),ds_actual
8087 double precision,
intent(inout) :: h_suggest
8088 integer,
intent(out) :: status
8089 logical,
intent(out) :: finished
8091 double precision :: xhit(
ndim)
8096 call trace_intersect_domain(xnow,xstage,xhit,hit_ok,face_id)
8097 if (.not.hit_ok)
return
8100 ds_actual=dsqrt(sum((xnext-xnow)**2))
8103 call trace_rk45_stats_note_attempt(.true.,.true.,ds_actual)
8105 end subroutine trace_rk45_try_boundary_finish
8107 subroutine trace_summary_rk45_cartesian_step(xnow,igrid,ds,forward, &
8108 threshold,h_suggest,xnext,ds_actual,status,accumulate_twist, &
8109 twist_increment,twist_status,twist_integrated)
8110 double precision,
intent(in) :: xnow(
ndim),ds,threshold
8111 integer,
intent(in) :: igrid
8112 logical,
intent(in) :: forward
8113 double precision,
intent(inout) :: h_suggest
8114 double precision,
intent(out) :: xnext(
ndim),ds_actual
8115 integer,
intent(out) :: status
8116 logical,
intent(in) :: accumulate_twist
8117 double precision,
intent(out) :: twist_increment
8118 integer,
intent(out) :: twist_status
8119 logical,
intent(out) :: twist_integrated
8121 double precision,
parameter :: b21=1.d0/5.d0
8122 double precision,
parameter :: b31=3.d0/40.d0,b32=9.d0/40.d0
8123 double precision,
parameter :: b41=3.d0/10.d0,b42=-9.d0/10.d0, &
8125 double precision,
parameter :: b51=-11.d0/54.d0,b52=5.d0/2.d0, &
8126 b53=-70.d0/27.d0,b54=35.d0/27.d0
8127 double precision,
parameter :: b61=1631.d0/55296.d0, &
8128 b62=175.d0/512.d0,b63=575.d0/13824.d0, &
8129 b64=44275.d0/110592.d0,b65=253.d0/4096.d0
8130 double precision,
parameter :: c1=37.d0/378.d0,c3=250.d0/621.d0, &
8131 c4=125.d0/594.d0,c6=512.d0/1771.d0
8132 double precision,
parameter :: cs1=2825.d0/27648.d0, &
8133 cs3=18575.d0/48384.d0,cs4=13525.d0/55296.d0, &
8134 cs5=277.d0/14336.d0,cs6=one/4.d0
8139 double precision :: h,hmax,hfloor,hcell,tol,err,grow,sgn
8140 double precision :: tw1,tw3,tw4,tw6
8141 double precision :: domain_min(
ndim),domain_max(
ndim)
8142 integer :: igrid1,igrid2,igrid3,igrid4,igrid5,igrid6
8143 integer :: iter,point_domain,face_id
8144 integer :: reject_reason
8145 logical :: hit_ok,boundary_limited,boundary_finished
8150 twist_increment=zero
8152 twist_integrated=.false.
8153 if (.not.trace_cartesian_like_geometry())
then
8159 if (hmax<=zero)
then
8166 hfloor=max(trace_step_min,100.d0*epsilon(one)*max(one,hmax))
8169 if (.not.forward) sgn=-one
8170 ^
d&domain_min(^
d)=xprobmin^
d;
8171 ^
d&domain_max(^
d)=xprobmax^
d;
8174 h=max(hfloor,min(h,hmax))
8175 call trace_cartesian_rhs_bhat(xnow,igrid,threshold,k1,igrid1,status)
8178 x2=xnow+sgn*h*b21*k1
8179 call trace_cartesian_rhs_bhat(x2,igrid1,threshold,k2,igrid2,status)
8184 call trace_rk45_try_boundary_finish(xnow,x2,hfloor,xnext, &
8185 ds_actual,h_suggest,status,boundary_finished)
8186 if (boundary_finished)
return
8188 reject_reason=trace_rk45_reject_stage_failure
8191 reject_reason=trace_rk45_reject_stage_outside
8192 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
8194 if (h<=hfloor*(one+epsilon(one)))
exit
8195 h=max(hfloor,half*h)
8199 x3=xnow+sgn*h*(b31*k1+b32*k2)
8200 call trace_cartesian_rhs_bhat(x3,igrid2,threshold,k3,igrid3,status)
8205 call trace_rk45_try_boundary_finish(xnow,x3,hfloor,xnext, &
8206 ds_actual,h_suggest,status,boundary_finished)
8207 if (boundary_finished)
return
8209 reject_reason=trace_rk45_reject_stage_failure
8212 reject_reason=trace_rk45_reject_stage_outside
8213 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
8215 if (h<=hfloor*(one+epsilon(one)))
exit
8216 h=max(hfloor,half*h)
8220 x4=xnow+sgn*h*(b41*k1+b42*k2+b43*k3)
8221 call trace_cartesian_rhs_bhat(x4,igrid3,threshold,k4,igrid4,status)
8226 call trace_rk45_try_boundary_finish(xnow,x4,hfloor,xnext, &
8227 ds_actual,h_suggest,status,boundary_finished)
8228 if (boundary_finished)
return
8230 reject_reason=trace_rk45_reject_stage_failure
8233 reject_reason=trace_rk45_reject_stage_outside
8234 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
8236 if (h<=hfloor*(one+epsilon(one)))
exit
8237 h=max(hfloor,half*h)
8241 x5s=xnow+sgn*h*(b51*k1+b52*k2+b53*k3+b54*k4)
8242 call trace_cartesian_rhs_bhat(x5s,igrid4,threshold,k5,igrid5,status)
8247 call trace_rk45_try_boundary_finish(xnow,x5s,hfloor,xnext, &
8248 ds_actual,h_suggest,status,boundary_finished)
8249 if (boundary_finished)
return
8251 reject_reason=trace_rk45_reject_stage_failure
8254 reject_reason=trace_rk45_reject_stage_outside
8255 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
8257 if (h<=hfloor*(one+epsilon(one)))
exit
8258 h=max(hfloor,half*h)
8262 x6=xnow+sgn*h*(b61*k1+b62*k2+b63*k3+b64*k4+b65*k5)
8263 call trace_cartesian_rhs_bhat(x6,igrid5,threshold,k6,igrid6,status)
8268 call trace_rk45_try_boundary_finish(xnow,x6,hfloor,xnext, &
8269 ds_actual,h_suggest,status,boundary_finished)
8270 if (boundary_finished)
return
8272 reject_reason=trace_rk45_reject_stage_failure
8275 reject_reason=trace_rk45_reject_stage_outside
8276 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
8278 if (h<=hfloor*(one+epsilon(one)))
exit
8279 h=max(hfloor,half*h)
8283 x5=xnow+sgn*h*(c1*k1+c3*k3+c4*k4+c6*k6)
8284 x4err=xnow+sgn*h*(cs1*k1+cs3*k3+cs4*k4+cs5*k5+cs6*k6)
8287 {
if (x5(^db)>=domain_min(^db) .and. x5(^db)<domain_max(^db)) point_domain=point_domain+1\}
8288 if (point_domain/=
ndim)
then
8289 call trace_intersect_domain(xnow,x5,xhit,hit_ok,face_id)
8292 ds_actual=dsqrt(sum((xnext-xnow)**2))
8295 call trace_rk45_stats_note_attempt(.true.,.true.,ds_actual)
8298 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
8299 trace_rk45_reject_boundary)
8304 call trace_cartesian_local_cell_size(xnow,igrid1,hcell,status)
8306 err=dsqrt(sum((x5-x4err)**2))
8307 tol=trace_rk45_atol+trace_rk45_rtol*max(h,hcell)
8308 if (err<=tol .or. h<=hfloor*(one+epsilon(one)))
then
8311 if (accumulate_twist)
then
8312 call trace_twist_density_at_point(xnow,igrid1,threshold,tw1, &
8315 call trace_twist_density_at_point(x3,igrid3,threshold,tw3, &
8318 call trace_twist_density_at_point(x4,igrid4,threshold,tw4, &
8321 call trace_twist_density_at_point(x6,igrid6,threshold,tw6, &
8324 twist_increment=h*(c1*tw1+c3*tw3+c4*tw4+c6*tw6)
8325 twist_integrated=.true.
8328 if (err>zero .and. tol>zero)
then
8329 grow=trace_rk45_safety*(tol/err)**0.2d0
8330 grow=max(trace_rk45_min_shrink,min(trace_rk45_max_grow,grow))
8332 grow=trace_rk45_max_grow
8334 h_suggest=min(hmax,max(hfloor,h*grow))
8335 call trace_rk45_stats_note_attempt(.true.,.false.,h)
8340 grow=trace_rk45_safety*(tol/max(err,smalldouble))**0.25d0
8341 grow=max(trace_rk45_min_shrink,min(one,grow))
8342 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
8343 trace_rk45_reject_error)
8344 h=max(hfloor,h*grow)
8347 call trace_intersect_domain(xnow,xnow+sgn*h*k1,xhit,hit_ok,face_id)
8349 boundary_limited=.true.
8351 ds_actual=dsqrt(sum((xnext-xnow)**2))
8353 call trace_rk45_stats_note_attempt(.true.,boundary_limited,ds_actual)
8358 end subroutine trace_summary_rk45_cartesian_step
8360 subroutine trace_summary_rk45_spherical_step(xnow,igrid,ds,forward, &
8361 threshold,h_suggest,sph_cache,xnext,ds_actual,status, &
8362 accumulate_twist,twist_increment,twist_status,twist_integrated)
8363 double precision,
intent(in) :: xnow(
ndim),ds,threshold
8364 integer,
intent(in) :: igrid
8365 logical,
intent(in) :: forward
8366 double precision,
intent(inout) :: h_suggest
8367 type(trace_sph_interp_ctx),
intent(inout) :: sph_cache
8368 double precision,
intent(out) :: xnext(
ndim),ds_actual
8369 integer,
intent(out) :: status
8370 logical,
intent(in) :: accumulate_twist
8371 double precision,
intent(out) :: twist_increment
8372 integer,
intent(out) :: twist_status
8373 logical,
intent(out) :: twist_integrated
8375 double precision,
parameter :: b21=1.d0/5.d0
8376 double precision,
parameter :: b31=3.d0/40.d0,b32=9.d0/40.d0
8377 double precision,
parameter :: b41=3.d0/10.d0,b42=-9.d0/10.d0, &
8379 double precision,
parameter :: b51=-11.d0/54.d0,b52=5.d0/2.d0, &
8380 b53=-70.d0/27.d0,b54=35.d0/27.d0
8381 double precision,
parameter :: b61=1631.d0/55296.d0, &
8382 b62=175.d0/512.d0,b63=575.d0/13824.d0, &
8383 b64=44275.d0/110592.d0,b65=253.d0/4096.d0
8384 double precision,
parameter :: c1=37.d0/378.d0,c3=250.d0/621.d0, &
8385 c4=125.d0/594.d0,c6=512.d0/1771.d0
8386 double precision,
parameter :: cs1=2825.d0/27648.d0, &
8387 cs3=18575.d0/48384.d0,cs4=13525.d0/55296.d0, &
8388 cs5=277.d0/14336.d0,cs6=one/4.d0
8393 double precision :: h,hmax,hfloor,hcell,tol,err,grow,sgn
8394 double precision :: tw1,tw3,tw4,tw6
8395 double precision :: r_metric,sin_theta_metric,alpha_hit
8396 double precision :: domain_min(
ndim),domain_max(
ndim)
8397 type(trace_sph_interp_ctx) :: ctx1,ctx2,ctx3,ctx4,ctx5,ctx6
8398 integer :: igrid1,igrid2,igrid3,igrid4,igrid5,igrid6
8399 integer :: iter,point_domain,face_id,ctx_status
8400 integer :: reject_reason
8401 logical :: hit_ok,field_ok
8402 character(len=std_len) :: field_type
8407 twist_increment=zero
8409 twist_integrated=.false.
8410 if (geo_coordinate/=geo_spherical)
then
8416 if (hmax<=zero)
then
8423 hfloor=max(trace_step_min,100.d0*epsilon(one)*max(one,hmax))
8426 if (.not.forward) sgn=-one
8428 ^
d&domain_min(^
d)=xprobmin^
d;
8429 ^
d&domain_max(^
d)=xprobmax^
d;
8432 h=max(hfloor,min(h,hmax))
8433 call trace_spherical_interp_ctx_build_cached(xnow,igrid,sph_cache, &
8439 call get_k_spherical_ctx(ctx1,k1,field_type,threshold,field_ok)
8440 if (.not.field_ok)
then
8447 x2=xnow+sgn*h*b21*k1
8448 call trace_spherical_interp_ctx_build_cached(x2,igrid1,sph_cache, &
8451 reject_reason=trace_rk45_reject_stage_failure
8454 reject_reason=trace_rk45_reject_stage_outside
8455 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
8457 if (h<=hfloor*(one+epsilon(one)))
exit
8458 h=max(hfloor,half*h)
8461 call get_k_spherical_ctx(ctx2,k2,field_type,threshold,field_ok)
8462 if (.not.field_ok)
then
8468 x3=xnow+sgn*h*(b31*k1+b32*k2)
8469 call trace_spherical_interp_ctx_build_cached(x3,igrid2,sph_cache, &
8472 reject_reason=trace_rk45_reject_stage_failure
8475 reject_reason=trace_rk45_reject_stage_outside
8476 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
8478 if (h<=hfloor*(one+epsilon(one)))
exit
8479 h=max(hfloor,half*h)
8482 call get_k_spherical_ctx(ctx3,k3,field_type,threshold,field_ok)
8483 if (.not.field_ok)
then
8489 x4=xnow+sgn*h*(b41*k1+b42*k2+b43*k3)
8490 call trace_spherical_interp_ctx_build_cached(x4,igrid3,sph_cache, &
8493 reject_reason=trace_rk45_reject_stage_failure
8496 reject_reason=trace_rk45_reject_stage_outside
8497 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
8499 if (h<=hfloor*(one+epsilon(one)))
exit
8500 h=max(hfloor,half*h)
8503 call get_k_spherical_ctx(ctx4,k4,field_type,threshold,field_ok)
8504 if (.not.field_ok)
then
8510 x5s=xnow+sgn*h*(b51*k1+b52*k2+b53*k3+b54*k4)
8511 call trace_spherical_interp_ctx_build_cached(x5s,igrid4,sph_cache, &
8514 reject_reason=trace_rk45_reject_stage_failure
8517 reject_reason=trace_rk45_reject_stage_outside
8518 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
8520 if (h<=hfloor*(one+epsilon(one)))
exit
8521 h=max(hfloor,half*h)
8524 call get_k_spherical_ctx(ctx5,k5,field_type,threshold,field_ok)
8525 if (.not.field_ok)
then
8531 x6=xnow+sgn*h*(b61*k1+b62*k2+b63*k3+b64*k4+b65*k5)
8532 call trace_spherical_interp_ctx_build_cached(x6,igrid5,sph_cache, &
8535 reject_reason=trace_rk45_reject_stage_failure
8538 reject_reason=trace_rk45_reject_stage_outside
8539 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
8541 if (h<=hfloor*(one+epsilon(one)))
exit
8542 h=max(hfloor,half*h)
8545 call get_k_spherical_ctx(ctx6,k6,field_type,threshold,field_ok)
8546 if (.not.field_ok)
then
8551 x5=xnow+sgn*h*(c1*k1+c3*k3+c4*k4+c6*k6)
8552 x4err=xnow+sgn*h*(cs1*k1+cs3*k3+cs4*k4+cs5*k5+cs6*k6)
8555 {
if (x5(^db)>=domain_min(^db) .and. x5(^db)<domain_max(^db)) point_domain=point_domain+1\}
8556 if (point_domain/=
ndim)
then
8557 call trace_intersect_domain(xnow,x5,xhit,hit_ok,face_id, &
8561 ds_actual=max(zero,min(one,alpha_hit))*h
8564 call trace_rk45_stats_note_attempt(.true.,.true.,ds_actual)
8567 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
8568 trace_rk45_reject_boundary)
8575 r_metric=max(abs(xnow(1)),smalldouble)
8576 sin_theta_metric=max(abs(dsin(xnow(2))),smalldouble)
8577 err=dsqrt((x5(1)-x4err(1))**2+ &
8578 (r_metric*(x5(2)-x4err(2)))**2+ &
8579 (r_metric*sin_theta_metric*(x5(3)-x4err(3)))**2)
8581 if (hcell<=zero) hcell=hmax
8582 tol=trace_rk45_atol+trace_rk45_rtol*max(h,hcell)
8583 if (err<=tol .or. h<=hfloor*(one+epsilon(one)))
then
8586 if (accumulate_twist)
then
8587 call trace_twist_density_at_point(xnow,ctx1%igrid,threshold,tw1, &
8588 twist_status,sph_cache)
8590 call trace_twist_density_at_point(x3,ctx3%igrid,threshold,tw3, &
8591 twist_status,sph_cache)
8593 call trace_twist_density_at_point(x4,ctx4%igrid,threshold,tw4, &
8594 twist_status,sph_cache)
8596 call trace_twist_density_at_point(x6,ctx6%igrid,threshold,tw6, &
8597 twist_status,sph_cache)
8599 twist_increment=h*(c1*tw1+c3*tw3+c4*tw4+c6*tw6)
8600 twist_integrated=.true.
8603 if (err>zero .and. tol>zero)
then
8604 grow=trace_rk45_safety*(tol/err)**0.2d0
8605 grow=max(trace_rk45_min_shrink,min(trace_rk45_max_grow,grow))
8607 grow=trace_rk45_max_grow
8609 h_suggest=min(hmax,max(hfloor,h*grow))
8610 call trace_rk45_stats_note_attempt(.true.,.false.,h)
8615 grow=trace_rk45_safety*(tol/max(err,smalldouble))**0.25d0
8616 grow=max(trace_rk45_min_shrink,min(one,grow))
8617 call trace_rk45_stats_note_attempt(.false.,.false.,h, &
8618 trace_rk45_reject_error)
8619 h=max(hfloor,h*grow)
8623 end subroutine trace_summary_rk45_spherical_step
8625 subroutine trace_summary_rk2_step(xnow,igrid,ds,forward,threshold, &
8626 xnext,ds_actual,status,sph_cache)
8627 double precision,
intent(in) :: xnow(
ndim),ds,threshold
8628 integer,
intent(in) :: igrid
8629 logical,
intent(in) :: forward
8630 double precision,
intent(out) :: xnext(
ndim),ds_actual
8631 integer,
intent(out) :: status
8632 type(trace_sph_interp_ctx),
intent(inout),
optional :: sph_cache
8635 double precision :: ds_step
8636 double precision :: dxb^
d
8637 type(trace_sph_interp_ctx) :: ctx_now,ctx_stage
8639 integer :: igrid_stage
8640 integer :: ctx_status
8642 character(len=std_len) :: field_type
8651 if (geo_coordinate==geo_spherical)
then
8652 if (
present(sph_cache))
then
8653 call trace_spherical_interp_ctx_build_cached(xnow,igrid,sph_cache, &
8656 call trace_spherical_interp_ctx_build(xnow,igrid,ctx_now,ctx_status)
8662 ds_step=trace_spherical_effective_step_ctx(ds,ctx_now)
8663 call get_k_spherical_ctx(ctx_now,k1,field_type,threshold,field_ok)
8665 ds_step=trace_effective_step(xnow,ds,igrid,dxb^
d)
8666 call get_k(xnow,igrid,k1,ixi^
l,dxb^
d,field_type,threshold,field_ok)
8668 if (.not.field_ok)
then
8674 xstage=xnow+ds_step*k1
8676 xstage=xnow-ds_step*k1
8678 xstage_sample=xstage
8679 ^
d&xstage_sample(^
d)=max(xprobmin^
d,min(xstage_sample(^
d), &
8680 xprobmax^
d-100.d0*epsilon(one)*max(one,abs(xprobmax^
d))));
8681 call trace_locate_point_with_hint(xstage_sample,igrid,igrid_stage,status)
8684 if (geo_coordinate==geo_spherical)
then
8685 if (
present(sph_cache))
then
8686 call trace_spherical_interp_ctx_build_cached(xstage_sample, &
8687 igrid_stage,sph_cache,ctx_stage,ctx_status)
8689 call trace_spherical_interp_ctx_build(xstage_sample,igrid_stage, &
8690 ctx_stage,ctx_status)
8696 call get_k_spherical_ctx(ctx_stage,k2,field_type,threshold,field_ok)
8698 call get_k(xstage_sample,igrid_stage,k2,ixi^
l,dxb^
d,field_type, &
8701 if (.not.field_ok)
then
8707 xnext=xnow+ds_step*(half*k1+half*k2)
8709 xnext=xnow-ds_step*(half*k1+half*k2)
8711 if (geo_coordinate==geo_spherical)
then
8712 ds_actual=abs(ds_step)
8714 ds_actual=dsqrt(sum((xnext-xnow)**2))
8716 end subroutine trace_summary_rk2_step
8718 double precision function trace_effective_step(x,ds,igrid,dxb^D) &
8720 double precision,
intent(in) :: x(
ndim),ds
8721 integer,
intent(in) :: igrid
8722 double precision,
intent(in) :: dxb^
d
8724 double precision :: r,sin_theta,cell_scale,dxloc(
ndim),step_cap,hcell
8725 type(trace_sph_interp_ctx) :: ctx
8729 if (trace_cartesian_like_geometry())
then
8730 if (trace_step_control_mode==trace_step_control_cell_fraction)
then
8732 call trace_cartesian_local_cell_size(x,igrid,hcell,status)
8734 ds_eff=dsign(min(step_cap,trace_step_fraction*hcell),ds)
8735 if (trace_step_min>zero)
then
8736 ds_eff=dsign(max(abs(ds_eff),min(trace_step_min,step_cap)),ds)
8738 if (trace_rk2_stats_enabled)
call trace_rk2_stats_note_step_limit(step_cap, &
8739 trace_step_fraction*hcell,abs(ds_eff))
8744 if (geo_coordinate/=geo_spherical)
return
8747 call trace_spherical_interp_ctx_build(x,igrid,ctx,status)
8749 ds_eff=trace_spherical_effective_step_ctx(ds,ctx)
8754 call trace_spherical_local_cell_widths(x,igrid,dxloc,status)
8756 r=max(abs(x(1)),smalldouble)
8757 sin_theta=abs(dsin(x(2)))
8758 cell_scale=min(abs(dxloc(1)),r*abs(dxloc(2)))
8759 cell_scale=min(cell_scale,r*max(sin_theta,smalldouble)*abs(dxloc(3)))
8760 if (cell_scale>zero)
then
8761 select case (trace_step_control_mode)
8762 case (trace_step_control_cell_fraction)
8763 ds_eff=min(step_cap,trace_step_fraction*cell_scale)
8764 if (trace_step_min>zero) ds_eff=max(ds_eff,min(trace_step_min,step_cap))
8766 ds_eff=min(step_cap,cell_scale)
8770 end function trace_effective_step
8772 logical function trace_spherical_metric_ok(x)
result(is_ok)
8773 double precision,
intent(in) :: x(
ndim)
8775 double precision :: metric_tol
8780 metric_tol=100.d0*epsilon(one)
8781 is_ok=x(1)>metric_tol .and. abs(dsin(x(2)))>metric_tol
8783 end function trace_spherical_metric_ok
8785 double precision function trace_segment_length(xa,xb,ds_full,alpha) &
8787 double precision,
intent(in) :: xa(
ndim),xb(
ndim),ds_full
8788 double precision,
intent(in),
optional :: alpha
8790 if (geo_coordinate==geo_spherical)
then
8791 if (
present(alpha))
then
8792 length=max(zero,min(one,alpha))*abs(ds_full)
8797 length=dsqrt(sum((xb-xa)**2))
8799 end function trace_segment_length
8803 integer,
intent(in) :: nseed,max_steps
8804 double precision,
intent(in) :: seeds(nseed,
ndim),dl
8806 double precision,
intent(in),
optional :: b_min
8808 double precision :: field_min
8810 field_min=smalldouble
8811 if (
present(b_min)) field_min=max(b_min,zero)
8812 call trace_summary_multi(seeds,nseed,dl,max_steps,results,field_min)
8817 integer,
intent(in) :: nseed,max_steps
8818 double precision,
intent(in) :: seeds(nseed,
ndim),dl
8820 double precision,
intent(in),
optional :: b_min
8822 double precision :: field_min
8824 field_min=smalldouble
8825 if (
present(b_min)) field_min=max(b_min,zero)
8826 call trace_summary_twist_multi(seeds,nseed,dl,max_steps,results,field_min)
8830 b_min,source_normal)
8832 integer,
intent(in) :: nseed,max_steps
8833 double precision,
intent(in) :: seeds(nseed,
ndim),dl
8835 double precision,
intent(in),
optional :: b_min
8836 double precision,
intent(in),
optional :: source_normal(3)
8838 double precision :: field_min,normal(3)
8839 logical :: have_normal
8841 field_min=smalldouble
8842 if (
present(b_min)) field_min=max(b_min,zero)
8844 have_normal=
present(source_normal)
8845 if (have_normal) normal=source_normal
8846 call trace_summary_mapping_multi(seeds,nseed,dl,max_steps,results, &
8847 field_min,have_normal,normal)
8851 need_twist,need_mapping,b_min,source_normal)
8853 integer,
intent(in) :: nseed,max_steps
8854 double precision,
intent(in) :: seeds(nseed,
ndim),dl
8856 logical,
intent(in),
optional :: need_twist,need_mapping
8857 double precision,
intent(in),
optional :: b_min
8858 double precision,
intent(in),
optional :: source_normal(3)
8860 double precision :: field_min,normal(3)
8861 logical :: do_twist,do_mapping,have_normal
8863 field_min=smalldouble
8864 if (
present(b_min)) field_min=max(b_min,zero)
8867 if (
present(need_twist)) do_twist=need_twist
8868 if (
present(need_mapping)) do_mapping=need_mapping
8870 have_normal=
present(source_normal)
8871 if (have_normal) normal=source_normal
8873 call trace_summary_topology_multi(seeds,nseed,dl,max_steps,results, &
8874 field_min,do_twist,do_mapping,have_normal,normal)
8880 integer,
intent(in) :: nseed,max_steps
8881 double precision,
intent(in) :: seeds(nseed,
ndim),dl
8883 double precision,
intent(in),
optional :: b_min
8886 type(trace_tangent_state),
allocatable :: states(:)
8887 double precision :: field_min
8888 double precision :: seed_local(
ndim),zero_vec(
ndim)
8889 integer :: common_status,iseed,idim,igrid,iforward,ibackward
8890 integer :: seed_status
8893 if (nseed<=0)
return
8895 field_min=smalldouble
8896 if (
present(b_min)) field_min=max(b_min,zero)
8898 do_twist=
present(twist_results)
8903 else if (
ndim/=3 .or. .not.trace_cartesian_like_geometry())
then
8905 else if (dl<=zero .or. max_steps<=0)
then
8911 seed_local(idim)=seeds(iseed,idim)
8913 call trace_init_qperp_result(seed_local,results(iseed))
8914 results(iseed)%status=common_status
8915 if (do_twist)
call trace_summary_init_twist_result(seed_local, &
8916 twist_results(iseed),common_status)
8921 allocate(states(2*nseed))
8924 seed_local(idim)=seeds(iseed,idim)
8926 call trace_qperp_prepare_seed_result(seed_local,field_min, &
8927 results(iseed),igrid,seed_status)
8931 call trace_tangent_state_init(seed_local,results(iseed)%u0, &
8932 results(iseed)%v0,igrid,iseed,1,states(iforward), &
8933 accumulate_twist=do_twist)
8934 call trace_tangent_state_init(seed_local,results(iseed)%u0, &
8935 results(iseed)%v0,igrid,iseed,-1,states(ibackward), &
8936 accumulate_twist=do_twist)
8937 if (trace_integrator_mode==trace_integrator_rk45_cartesian .or. &
8938 trace_integrator_mode==trace_integrator_rk45_spherical)
then
8939 call trace_rk45_stats_note_direction()
8940 call trace_rk45_stats_note_direction()
8941 else if (trace_integrator_mode==trace_integrator_rk2)
then
8942 call trace_rk2_stats_note_direction()
8943 call trace_rk2_stats_note_direction()
8946 call trace_tangent_state_init(seed_local,zero_vec,zero_vec,igrid, &
8947 iseed,1,states(iforward),accumulate_twist=do_twist)
8948 call trace_tangent_state_init(seed_local,zero_vec,zero_vec,igrid, &
8949 iseed,-1,states(ibackward),accumulate_twist=do_twist)
8950 states(iforward)%active=.false.
8951 states(ibackward)%active=.false.
8952 states(iforward)%status=seed_status
8953 states(ibackward)%status=seed_status
8957 select case (trace_integrator_mode)
8958 case (trace_integrator_rk45_cartesian)
8959 call trace_tangent_trace_states_grouped(states,2*nseed,dl,max_steps, &
8960 field_min,trace_mode=trace_tangent_group_rk45_cartesian)
8961 case (trace_integrator_rk45_spherical)
8962 call trace_tangent_trace_states_grouped_rk45_spherical(states, &
8963 2*nseed,dl,max_steps,field_min)
8965 call trace_tangent_trace_states_grouped(states,2*nseed,dl,max_steps, &
8973 call trace_qperp_finalize_from_states(states(iforward), &
8974 states(ibackward),results(iseed),field_min)
8976 if (do_twist)
call trace_tangent_fill_twist_result(seeds(iseed,:), &
8977 states(iforward),states(ibackward),twist_results(iseed))
8983 max_steps,results,b_min,twist_results)
8988 integer,
intent(in) :: nseed,max_steps
8989 double precision,
intent(in) :: seeds(nseed,
ndim),dl
8991 double precision,
intent(in),
optional :: b_min
8994 type(trace_tangent_state),
allocatable :: states(:)
8995 double precision :: field_min
8996 double precision :: seed_local(
ndim),zero_vec(
ndim)
8997 integer :: common_status,iseed,idim,igrid,iforward,ibackward
8998 integer :: seed_status
9001 if (nseed<=0)
return
9003 field_min=smalldouble
9004 if (
present(b_min)) field_min=max(b_min,zero)
9006 do_twist=
present(twist_results)
9011 else if (
ndim/=3 .or. .not.trace_cartesian_like_geometry())
then
9013 else if (dl<=zero .or. max_steps<=0)
then
9019 seed_local(idim)=seeds(iseed,idim)
9021 call trace_init_qperp_result(seed_local,results(iseed))
9022 results(iseed)%status=common_status
9023 results(iseed)%status_q0=common_status
9024 if (do_twist)
call trace_summary_init_twist_result(seed_local, &
9025 twist_results(iseed),common_status)
9030 allocate(states(2*nseed))
9033 seed_local(idim)=seeds(iseed,idim)
9035 call trace_qperp_prepare_seed_result(seed_local,field_min, &
9036 results(iseed),igrid,seed_status)
9040 call trace_tangent_state_init(seed_local,results(iseed)%u0, &
9041 results(iseed)%v0,igrid,iseed,1,states(iforward), &
9042 accumulate_twist=do_twist)
9043 call trace_tangent_state_init(seed_local,results(iseed)%u0, &
9044 results(iseed)%v0,igrid,iseed,-1,states(ibackward), &
9045 accumulate_twist=do_twist)
9046 call trace_rk45_stats_note_direction()
9047 call trace_rk45_stats_note_direction()
9049 call trace_tangent_state_init(seed_local,zero_vec,zero_vec,igrid, &
9050 iseed,1,states(iforward),accumulate_twist=do_twist)
9051 call trace_tangent_state_init(seed_local,zero_vec,zero_vec,igrid, &
9052 iseed,-1,states(ibackward),accumulate_twist=do_twist)
9053 states(iforward)%active=.false.
9054 states(ibackward)%active=.false.
9055 states(iforward)%status=seed_status
9056 states(ibackward)%status=seed_status
9057 results(iseed)%status_q0=seed_status
9061 call trace_tangent_trace_states_grouped(states,2*nseed,dl,max_steps, &
9062 field_min,trace_mode=trace_tangent_group_rk45_cartesian)
9068 call trace_q0_finalize_from_states(states(iforward), &
9069 states(ibackward),results(iseed),field_min)
9071 if (do_twist)
call trace_tangent_fill_twist_result(seeds(iseed,:), &
9072 states(iforward),states(ibackward),twist_results(iseed))
9078 max_steps,results,b_min)
9079 integer,
intent(in) :: nseed,max_steps
9080 double precision,
intent(in) :: seeds(nseed,
ndim),dl
9082 double precision,
intent(in),
optional :: b_min
9084 if (
present(b_min))
then
9094 results,b_min,twist_results)
9096 integer,
intent(in) :: nseed,max_steps
9097 double precision,
intent(in) :: seeds(nseed,
ndim),dl
9099 double precision,
intent(in),
optional :: b_min
9102 type(trace_tangent_state),
allocatable :: states(:)
9103 double precision :: field_min
9104 double precision :: seed_local(
ndim),zero_vec(
ndim)
9105 integer :: common_status,iseed,idim,igrid,iforward,ibackward
9106 integer :: seed_status
9109 if (nseed<=0)
return
9110 if (trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical) &
9111 call trace_spherical_profile_add_count(trace_profile_q_tangent_systems, &
9112 int(2*nseed,kind=8))
9114 field_min=smalldouble
9115 if (
present(b_min)) field_min=max(b_min,zero)
9117 do_twist=
present(twist_results)
9122 else if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
then
9124 else if (dl<=zero .or. max_steps<=0)
then
9130 seed_local(idim)=seeds(iseed,idim)
9132 call trace_init_qperp_result(seed_local,results(iseed))
9133 results(iseed)%status=common_status
9134 results(iseed)%status_q0=common_status
9135 if (do_twist)
call trace_summary_init_twist_result(seed_local, &
9136 twist_results(iseed),common_status)
9141 allocate(states(2*nseed))
9144 seed_local(idim)=seeds(iseed,idim)
9146 call trace_spherical_rmin_q_prepare_seed_result(seed_local,field_min, &
9147 results(iseed),igrid,seed_status)
9151 call trace_tangent_state_init(seed_local,results(iseed)%u0, &
9152 results(iseed)%v0,igrid,iseed,1,states(iforward), &
9153 accumulate_twist=do_twist)
9154 call trace_tangent_state_init(seed_local,results(iseed)%u0, &
9155 results(iseed)%v0,igrid,iseed,-1,states(ibackward), &
9156 accumulate_twist=do_twist)
9157 if (trace_integrator_mode==trace_integrator_rk45_spherical)
then
9158 call trace_rk45_stats_note_direction()
9159 call trace_rk45_stats_note_direction()
9160 else if (trace_integrator_mode==trace_integrator_rk2)
then
9161 call trace_rk2_stats_note_direction()
9162 call trace_rk2_stats_note_direction()
9165 call trace_tangent_state_init(seed_local,zero_vec,zero_vec,igrid, &
9166 iseed,1,states(iforward),accumulate_twist=do_twist)
9167 call trace_tangent_state_init(seed_local,zero_vec,zero_vec,igrid, &
9168 iseed,-1,states(ibackward),accumulate_twist=do_twist)
9169 states(iforward)%active=.false.
9170 states(ibackward)%active=.false.
9171 states(iforward)%status=seed_status
9172 states(ibackward)%status=seed_status
9176 if (trace_integrator_mode==trace_integrator_rk45_spherical)
then
9177 call trace_tangent_trace_states_grouped_rk45_spherical(states, &
9178 2*nseed,dl,max_steps,field_min)
9180 call trace_tangent_trace_states_grouped(states,2*nseed,dl,max_steps, &
9188 call trace_spherical_rmin_q_finalize_from_states(states(iforward), &
9189 states(ibackward),results(iseed),field_min)
9191 if (do_twist)
call trace_tangent_fill_twist_result(seeds(iseed,:), &
9192 states(iforward),states(ibackward),twist_results(iseed))
9198 max_steps,results,b_min,twist_results)
9201 integer,
intent(in) :: nseed,max_steps
9202 double precision,
intent(in) :: seeds(nseed,
ndim),dl
9204 double precision,
intent(in),
optional :: b_min
9207 type(trace_tangent_state),
allocatable :: states(:)
9208 double precision :: field_min
9209 double precision :: seed_local(
ndim),zero_vec(
ndim)
9210 integer :: common_status,iseed,idim,igrid,iforward,ibackward
9211 integer :: seed_status
9212 logical :: do_twist,is_spherical
9214 if (nseed<=0)
return
9216 field_min=smalldouble
9217 if (
present(b_min)) field_min=max(b_min,zero)
9219 do_twist=
present(twist_results)
9220 is_spherical=(geo_coordinate==geo_spherical)
9225 else if (
ndim/=3)
then
9227 else if (geo_coordinate==geo_cartesian .and. .not.
slab_uniform)
then
9229 else if (geo_coordinate/=geo_cartesian .and. &
9230 geo_coordinate/=geo_spherical)
then
9232 else if (dl<=zero .or. max_steps<=0)
then
9238 seed_local(idim)=seeds(iseed,idim)
9240 call trace_init_qperp_result(seed_local,results(iseed))
9241 results(iseed)%status=common_status
9242 results(iseed)%status_q0=common_status
9243 if (do_twist)
call trace_summary_init_twist_result(seed_local, &
9244 twist_results(iseed),common_status)
9249 allocate(states(2*nseed))
9252 seed_local(idim)=seeds(iseed,idim)
9254 if (is_spherical)
then
9255 call trace_spherical_rmin_q_prepare_seed_result(seed_local,field_min, &
9256 results(iseed),igrid,seed_status)
9258 call trace_qperp_prepare_seed_result(seed_local,field_min, &
9259 results(iseed),igrid,seed_status)
9264 call trace_tangent_state_init(seed_local,results(iseed)%u0, &
9265 results(iseed)%v0,igrid,iseed,1,states(iforward), &
9266 accumulate_twist=do_twist)
9267 call trace_tangent_state_init(seed_local,results(iseed)%u0, &
9268 results(iseed)%v0,igrid,iseed,-1,states(ibackward), &
9269 accumulate_twist=do_twist)
9270 if (trace_integrator_mode==trace_integrator_rk45_spherical)
then
9271 call trace_rk45_stats_note_direction()
9272 call trace_rk45_stats_note_direction()
9273 else if (trace_integrator_mode==trace_integrator_rk2)
then
9274 call trace_rk2_stats_note_direction()
9275 call trace_rk2_stats_note_direction()
9278 call trace_tangent_state_init(seed_local,zero_vec,zero_vec,igrid, &
9279 iseed,1,states(iforward),accumulate_twist=do_twist)
9280 call trace_tangent_state_init(seed_local,zero_vec,zero_vec,igrid, &
9281 iseed,-1,states(ibackward),accumulate_twist=do_twist)
9282 states(iforward)%active=.false.
9283 states(ibackward)%active=.false.
9284 states(iforward)%status=seed_status
9285 states(ibackward)%status=seed_status
9286 results(iseed)%status_q0=seed_status
9290 call trace_tangent_trace_states_grouped(states,2*nseed,dl,max_steps, &
9291 field_min,trace_mode=trace_tangent_group_rk2_short_boundary)
9297 if (is_spherical)
then
9298 call trace_spherical_rmin_q_finalize_from_states(states(iforward), &
9299 states(ibackward),results(iseed),field_min)
9301 call trace_q0_finalize_from_states(states(iforward), &
9302 states(ibackward),results(iseed),field_min)
9305 if (do_twist)
call trace_tangent_fill_twist_result(seeds(iseed,:), &
9306 states(iforward),states(ibackward),twist_results(iseed))
9312 results,b_min,twist_results)
9314 integer,
intent(in) :: nseed,max_steps
9315 double precision,
intent(in) :: seeds(nseed,
ndim),dl
9317 double precision,
intent(in),
optional :: b_min
9320 type(trace_tangent_state),
allocatable :: states(:)
9321 double precision :: field_min
9322 double precision :: seed_local(
ndim),zero_vec(
ndim)
9323 integer :: common_status,iseed,idim,igrid,iforward,ibackward
9324 integer :: seed_status
9325 integer :: cache_status
9328 if (nseed<=0)
return
9329 if (trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical) &
9330 call trace_spherical_profile_add_count( &
9331 trace_profile_qperp_tangent_systems,int(2*nseed,kind=8))
9333 field_min=smalldouble
9334 if (
present(b_min)) field_min=max(b_min,zero)
9336 do_twist=
present(twist_results)
9341 else if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
then
9343 else if (dl<=zero .or. max_steps<=0)
then
9349 seed_local(idim)=seeds(iseed,idim)
9351 call trace_init_qperp_result(seed_local,results(iseed))
9352 results(iseed)%status=common_status
9353 results(iseed)%status_qperp0=common_status
9354 if (do_twist)
call trace_summary_init_twist_result(seed_local, &
9355 twist_results(iseed),common_status)
9365 seed_local(idim)=seeds(iseed,idim)
9367 call trace_init_qperp_result(seed_local,results(iseed))
9368 results(iseed)%status=cache_status
9369 results(iseed)%status_qperp0=cache_status
9370 call trace_summary_init_twist_result(seed_local, &
9371 twist_results(iseed),cache_status)
9377 allocate(states(2*nseed))
9380 seed_local(idim)=seeds(iseed,idim)
9382 call trace_spherical_qperp_prepare_seed_result(seed_local,field_min, &
9383 results(iseed),igrid,seed_status)
9387 call trace_tangent_state_init(seed_local,results(iseed)%u0, &
9388 results(iseed)%v0,igrid,iseed,1,states(iforward), &
9389 accumulate_twist=do_twist)
9390 call trace_tangent_state_init(seed_local,results(iseed)%u0, &
9391 results(iseed)%v0,igrid,iseed,-1,states(ibackward), &
9392 accumulate_twist=do_twist)
9393 if (trace_integrator_mode==trace_integrator_rk45_spherical)
then
9394 call trace_rk45_stats_note_direction()
9395 call trace_rk45_stats_note_direction()
9396 else if (trace_integrator_mode==trace_integrator_rk2)
then
9397 call trace_rk2_stats_note_direction()
9398 call trace_rk2_stats_note_direction()
9401 call trace_tangent_state_init(seed_local,zero_vec,zero_vec,igrid, &
9402 iseed,1,states(iforward),accumulate_twist=do_twist)
9403 call trace_tangent_state_init(seed_local,zero_vec,zero_vec,igrid, &
9404 iseed,-1,states(ibackward),accumulate_twist=do_twist)
9405 states(iforward)%active=.false.
9406 states(ibackward)%active=.false.
9407 states(iforward)%status=seed_status
9408 states(ibackward)%status=seed_status
9412 if (trace_integrator_mode==trace_integrator_rk45_spherical)
then
9413 call trace_tangent_trace_states_grouped_rk45_spherical(states, &
9414 2*nseed,dl,max_steps,field_min)
9416 call trace_tangent_trace_states_grouped(states,2*nseed,dl,max_steps, &
9424 call trace_spherical_qperp_finalize_from_states(states(iforward), &
9425 states(ibackward),results(iseed),field_min)
9427 if (do_twist)
call trace_tangent_fill_twist_result(seeds(iseed,:), &
9428 states(iforward),states(ibackward),twist_results(iseed))
9435 max_steps,q_results,qperp_results,b_min,twist_results)
9437 integer,
intent(in) :: nseed,max_steps
9438 double precision,
intent(in) :: seeds(nseed,
ndim),dl
9441 double precision,
intent(in),
optional :: b_min
9444 type(trace_tangent_state),
allocatable :: states(:)
9445 type(trace_tangent_state) :: qperp_forward_state,qperp_backward_state
9446 double precision :: field_min
9447 double precision :: seed_local(
ndim),zero_vec(
ndim)
9448 integer :: common_status,iseed,idim,igrid_q,igrid_qperp
9449 integer :: iforward,ibackward,seed_status_q,seed_status_qperp
9452 if (nseed<=0)
return
9453 if (trace_spherical_profile_enabled .and. geo_coordinate==geo_spherical)
then
9454 call trace_spherical_profile_add_count(trace_profile_q_tangent_systems, &
9455 int(2*nseed,kind=8))
9456 call trace_spherical_profile_add_count( &
9457 trace_profile_qperp_tangent_systems,int(2*nseed,kind=8))
9458 call trace_spherical_profile_add_count( &
9459 trace_profile_combined_tangent_systems,int(2*nseed,kind=8))
9462 field_min=smalldouble
9463 if (
present(b_min)) field_min=max(b_min,zero)
9465 do_twist=
present(twist_results)
9470 else if (
ndim/=3 .or. geo_coordinate/=geo_spherical)
then
9472 else if (dl<=zero .or. max_steps<=0)
then
9478 seed_local(idim)=seeds(iseed,idim)
9480 call trace_init_qperp_result(seed_local,q_results(iseed))
9481 q_results(iseed)%status=common_status
9482 q_results(iseed)%status_q0=common_status
9483 call trace_init_qperp_result(seed_local,qperp_results(iseed))
9484 qperp_results(iseed)%status=common_status
9485 qperp_results(iseed)%status_qperp0=common_status
9486 if (do_twist)
call trace_summary_init_twist_result(seed_local, &
9487 twist_results(iseed),common_status)
9492 allocate(states(2*nseed))
9495 seed_local(idim)=seeds(iseed,idim)
9497 call trace_spherical_rmin_q_prepare_seed_result(seed_local,field_min, &
9498 q_results(iseed),igrid_q,seed_status_q)
9499 call trace_spherical_qperp_prepare_seed_result(seed_local,field_min, &
9500 qperp_results(iseed),igrid_qperp,seed_status_qperp)
9506 call trace_tangent_state_init(seed_local,q_results(iseed)%u0, &
9507 q_results(iseed)%v0,igrid_q,iseed,1,states(iforward), &
9508 accumulate_twist=do_twist)
9509 call trace_tangent_state_init(seed_local,q_results(iseed)%u0, &
9510 q_results(iseed)%v0,igrid_q,iseed,-1,states(ibackward), &
9511 accumulate_twist=do_twist)
9512 states(iforward)%has_extra=.true.
9513 states(ibackward)%has_extra=.true.
9514 states(iforward)%p=qperp_results(iseed)%u0
9515 states(iforward)%q=qperp_results(iseed)%v0
9516 states(ibackward)%p=qperp_results(iseed)%u0
9517 states(ibackward)%q=qperp_results(iseed)%v0
9518 if (trace_integrator_mode==trace_integrator_rk45_spherical)
then
9519 call trace_rk45_stats_note_direction()
9520 call trace_rk45_stats_note_direction()
9521 else if (trace_integrator_mode==trace_integrator_rk2)
then
9522 call trace_rk2_stats_note_direction()
9523 call trace_rk2_stats_note_direction()
9526 call trace_tangent_state_init(seed_local,zero_vec,zero_vec,igrid_q, &
9527 iseed,1,states(iforward),accumulate_twist=do_twist)
9528 call trace_tangent_state_init(seed_local,zero_vec,zero_vec,igrid_q, &
9529 iseed,-1,states(ibackward),accumulate_twist=do_twist)
9530 states(iforward)%active=.false.
9531 states(ibackward)%active=.false.
9533 states(iforward)%status=seed_status_q
9534 states(ibackward)%status=seed_status_q
9536 states(iforward)%status=seed_status_qperp
9537 states(ibackward)%status=seed_status_qperp
9542 if (trace_integrator_mode==trace_integrator_rk45_spherical)
then
9543 call trace_tangent_trace_states_grouped_rk45_spherical(states, &
9544 2*nseed,dl,max_steps,field_min)
9546 call trace_tangent_trace_states_grouped(states,2*nseed,dl,max_steps, &
9554 call trace_spherical_rmin_q_finalize_from_states(states(iforward), &
9555 states(ibackward),q_results(iseed),field_min)
9558 qperp_forward_state=states(iforward)
9559 qperp_backward_state=states(ibackward)
9560 qperp_forward_state%u_perp=states(iforward)%p_perp
9561 qperp_forward_state%v_perp=states(iforward)%q_perp
9562 qperp_backward_state%u_perp=states(ibackward)%p_perp
9563 qperp_backward_state%v_perp=states(ibackward)%q_perp
9564 call trace_spherical_qperp_finalize_from_states(qperp_forward_state, &
9565 qperp_backward_state,qperp_results(iseed),field_min)
9567 if (do_twist)
call trace_tangent_fill_twist_result(seeds(iseed,:), &
9568 states(iforward),states(ibackward),twist_results(iseed))
9573 subroutine trace_field_multi(xfm,wPm,wLm,dL,numL,numP,nwP,nwL,forwardm,ftype,tcondi)
9601 integer,
intent(in) :: numL,numP,nwP,nwL
9602 double precision,
intent(inout) :: xfm(numL,numP,ndim),wPm(numL,numP,nwP),wLm(numL,1+nwL)
9603 double precision,
intent(in) :: dL
9604 logical,
intent(in) :: forwardm(numL)
9605 character(len=std_len),
intent(in) :: ftype,tcondi
9607 double precision :: x3d(3),statusF(4+ndim),statusL(numL,4+ndim+nwL),statusS(numL,4+ndim+nwL)
9608 double precision :: xf(numP,ndim),wP(numP,nwP),wL(1+nwL)
9609 double precision,
allocatable :: data_send(:,:,:),data_recv(:,:,:)
9610 integer :: indomain,ipe_now,igrid_now,igrid,j,iL
9611 integer :: ipoint_in,ipoint_out,numSend,nRT,nRTmax
9612 integer :: ipointm(numL),igridm(numL)
9613 logical :: continueL(numL),myL(numL)
9614 logical :: stopT,forward
9616 if (tcondi/=
'TRAC')
then
9622 xfm(1:numl,2:nump,:)=zero
9632 {
if (xfm(il,1,^db)>=xprobmin^db .and. xfm(il,1,^db)<xprobmax^db) indomain=indomain+1\}
9633 if (indomain==ndim)
then
9634 if (tcondi/=
'TRAC') wlm(il,1)=1
9635 continuel(il)=.true.
9644 igridm(il)=igrid_now
9645 if (
mype==ipe_now)
then
9651 continuel(il)=.false.
9656 do while(stopt .eqv. .false.)
9660 if (myl(il) .and. continuel(il))
then
9662 ipoint_in=ipointm(il)
9663 xf(ipoint_in,:)=xfm(il,ipoint_in,:)
9665 forward=forwardm(il)
9667 call find_points_in_pe(igrid,ipoint_in,xf,wp,wl,dl,nump,nwp,nwl,forward,ftype,tcondi,statusf)
9668 ipoint_out=int(statusf(1))
9669 xfm(il,ipoint_in:ipoint_out-1,:)=xf(ipoint_in:ipoint_out-1,:)
9670 wpm(il,ipoint_in:ipoint_out-1,:)=wp(ipoint_in:ipoint_out-1,:)
9680 statuss(il,1:4+ndim)=statusf(1:4+ndim)
9681 statuss(il,4+ndim+1:4+ndim+nwl)=wl(2:1+nwl)
9682 if (tcondi==
'TRAC') wlm(il,1)=ipoint_out-1
9687 numsend=numl*(4+ndim+nwl)
9688 call mpi_allreduce(statuss,statusl,numsend,mpi_double_precision,&
9695 if (continuel(il))
then
9696 ipointm(il)=int(statusl(il,1))
9697 if (
mype==int(statusl(il,2))) myl(il)=.true.
9698 igridm(il)=int(statusl(il,3))
9702 continuel(il)=.false.
9704 if (myl(il)) xfm(il,ipointm(il),1:ndim)=statusl(il,4+1:4+ndim)
9705 if (tcondi/=
'TRAC')
then
9707 wlm(il,1)=ipointm(il)
9709 wlm(il,1)=ipointm(il)-1
9712 wlm(il,2:1+nwl)=statusl(il,4+ndim+1:4+ndim+nwl)
9718 if (tcondi/=
'TRAC')
then
9721 if (nrtmax<int(wlm(il,1))) nrtmax=int(wlm(il,1))
9723 numsend=numl*nrtmax*(ndim+nwp)
9725 allocate(data_send(numl,nrtmax,ndim+nwp),data_recv(numl,nrtmax,ndim+nwp))
9726 data_send(:,:,:)=zero
9729 data_send(il,1:nrt,1:ndim)=xfm(il,1:nrt,1:ndim)
9730 if (nwp>0) data_send(il,1:nrt,1+ndim:ndim+nwp)=wpm(il,1:nrt,1:nwp)
9732 call mpi_allreduce(data_send,data_recv,numsend,mpi_double_precision,&
9736 xfm(il,1:nrt,1:ndim)=data_recv(il,1:nrt,1:ndim)
9737 if (nwp>0) wpm(il,1:nrt,1:nwp)=data_recv(il,1:nrt,1+ndim:ndim+nwp)
9739 deallocate(data_send,data_recv)
9772 integer,
intent(in) :: numP,nwP,nwL
9773 double precision,
intent(inout) :: xf(numP,ndim),wP(numP,nwP),wL(1+nwL)
9774 double precision,
intent(in) :: dL
9775 logical,
intent(in) :: forward
9776 character(len=std_len),
intent(in) :: ftype,tcondi
9778 double precision :: x3d(3),statusF(4+ndim),status_bcast(4+ndim+nwL)
9779 double precision,
allocatable :: data_send(:,:),data_recv(:,:)
9780 integer :: indomain,ipoint_in,ipe_now,igrid_now,igrid,j
9781 integer :: ipoint_out,ipe_next,igrid_next,numRT
9792 {
if (xf(1,^db)>=xprobmin^db .and. xf(1,^db)<xprobmax^db) indomain=indomain+1\}
9793 if (indomain==ndim)
then
9804 if (
mype/=ipe_now) xf(1,:)=zero
9807 call mpistop(
'Field tracing error: given point is not in simulation box!')
9813 do while(stopt .eqv. .false.)
9815 if (
mype==ipe_now)
then
9818 call find_points_in_pe(igrid,ipoint_in,xf,wp,wl,dl,nump,nwp,nwl,forward,ftype,tcondi,statusf)
9819 status_bcast(1:4+ndim)=statusf(1:4+ndim)
9820 status_bcast(4+ndim+1:4+ndim+nwl)=wl(2:1+nwl)
9823 call mpi_bcast(status_bcast,4+ndim+nwl,mpi_double_precision,ipe_now,
icomm,
ierrmpi)
9824 statusf(1:4+ndim)=status_bcast(1:4+ndim)
9825 wl(2:1+nwl)=status_bcast(4+ndim+1:4+ndim+nwl)
9828 ipoint_out=int(statusf(1))
9829 ipe_next=int(statusf(2))
9830 igrid_next=int(statusf(3))
9839 if (
mype==ipe_next)
then
9841 xf(ipoint_out,j)=statusf(4+j)
9844 xf(ipoint_out,:)=zero
9849 igrid_now=igrid_next
9850 ipoint_in=ipoint_out
9853 if (tcondi/=
'TRAC')
then
9855 allocate(data_send(numrt,ndim+nwp),data_recv(numrt,ndim+nwp))
9858 data_send(1:numrt,1:ndim)=xf(1:numrt,1:ndim)
9859 if (nwp>0) data_send(1:numrt,1+ndim:ndim+nwp)=wp(1:numrt,1:nwp)
9860 call mpi_allreduce(data_send,data_recv,numrt*(ndim+nwp),mpi_double_precision,&
9862 xf(1:numrt,1:ndim)=data_recv(1:numrt,1:ndim)
9863 if (nwp>0) wp(1:numrt,1:nwp)=data_recv(1:numrt,1+ndim:ndim+nwp)
9864 deallocate(data_send,data_recv)
9869 subroutine find_points_in_pe(igrid,ipoint_in,xf,wP,wL,dL,numP,nwP,nwL,forward,ftype,tcondi,statusF)
9871 integer,
intent(inout) :: igrid
9872 integer,
intent(in) :: ipoint_in,numP,nwP,nwL
9873 double precision,
intent(inout) :: xf(numP,ndim),wP(numP,nwP),wL(1+nwL)
9874 double precision,
intent(in) :: dL
9875 logical,
intent(in) :: forward
9876 character(len=std_len),
intent(in) :: ftype,tcondi
9877 double precision,
intent(inout) :: statusF(4+ndim)
9879 double precision :: xfout(ndim)
9880 integer :: ipe_next,igrid_next,ip_in,ip_out,j,indomain,trace_status
9881 logical :: newpe,stopT
9889 do while(newpe .eqv. .false.)
9892 dl,forward,ftype,tcondi,trace_status)
9901 {
if (xf(ip_out,^db)>=xprobmin^db .and. xf(ip_out,^db)<=xprobmax^db) indomain=indomain+1\}
9902 if (ip_out<nump .and. indomain==ndim)
then
9903 if (tcondi/=
'TRAC')
then
9923 if (ip_out>=nump)
then
9934 statusf(3)=igrid_next
9936 if (stopt) statusf(4)=trace_status
9938 statusf(4+j)=xf(ip_out,j)
9942 if (newpe .eqv. .false.) igrid=igrid_next
9953 integer,
intent(inout) :: igrid,igrid_next,ipe_next
9954 double precision,
intent(in) :: xf1(ndim)
9955 logical,
intent(inout) :: newpe,stopT
9957 double precision :: dxb^D,xb^L,xbmid^D
9958 double precision :: xbn^L
9959 integer :: idn^D,my_neighbor_type,inblock
9960 integer :: ic^D,inc^D,ipe_neighbor,igrid_neighbor
9971 {
if (xf1(^d)<=xbmin^d) idn^d=-1\}
9972 {
if (xf1(^d)>=xbmax^d) idn^d=1\}
9974 igrid_neighbor=
neighbor(1,idn^d,igrid)
9975 ipe_neighbor=
neighbor(2,idn^d,igrid)
9978 select case(my_neighbor_type)
9986 igrid_next=igrid_neighbor
9987 ipe_next=ipe_neighbor
9988 if (
mype==ipe_neighbor)
then
9996 igrid_next=igrid_neighbor
9997 ipe_next=ipe_neighbor
9998 if (
mype==ipe_neighbor)
then
10006 {xbmid^d=(xbmin^d+xbmax^d)/2.d0\}
10008 {
if (xf1(^d)<=xbmin^d) inc^d=0\}
10009 {
if (xf1(^d)>xbmin^d .and. xf1(^d)<=xbmid^d) inc^d=1\}
10010 {
if (xf1(^d)>xbmid^d .and. xf1(^d)<xbmax^d) inc^d=2\}
10011 {
if (xf1(^d)>=xbmax^d) inc^d=3\}
10014 if (
mype==ipe_next)
then
10024 dL,forward,ftype,tcondi,trace_status)
10028 integer,
intent(in) :: igrid,ip_in,numP,nwP,nwL
10029 integer,
intent(inout) :: ip_out
10030 double precision,
intent(inout) :: xf(numP,ndim),wP(numP,nwP),wL(1+nwL)
10031 double precision,
intent(in) :: dL
10032 logical,
intent(in) :: forward
10033 character(len=std_len),
intent(in) :: ftype,tcondi
10034 integer,
intent(out) :: trace_status
10036 double precision :: dxb^D,xb^L
10037 double precision :: field(ixg^T,ndir)
10038 double precision :: xs1(ndim),xs2(ndim),K1(ndim),K2(ndim)
10039 double precision :: xfpre(ndim),xfnow(ndim),xfnext(ndim)
10040 double precision :: Tpre,Tnow,Tnext,dTds,Lt,Lr,ds,T_bott,trac_delta
10041 integer :: ip,inblock,ixI^L,ixO^L,j
10042 logical :: field_ok
10052 if (tcondi/=
'TRAC')
then
10061 mainloop:
do ip=ip_in,nump-1
10065 call get_k(xs1,igrid,k1,ixi^l,dxb^d,ftype,smalldouble,field_ok)
10066 if (.not.field_ok)
then
10072 xs2(:)=xf(ip,:)+ds*k1(:)
10074 xs2(:)=xf(ip,:)-ds*k1(:)
10076 call get_k(xs2,igrid,k2,ixi^l,dxb^d,ftype,smalldouble,field_ok)
10077 if (.not.field_ok)
then
10083 xf(ip+1,:)=xf(ip,:)+ds*(0.5*k1(:)+0.5*k2(:))
10085 xf(ip+1,:)=xf(ip,:)-ds*(0.5*k1(:)+0.5*k2(:))
10090 if (tcondi/=
'TRAC')
then
10092 call usr_set_field_w(igrid,ip,xf,wp,wl,nump,nwp,nwl,dl,forward,ftype,tcondi)
10097 if (ip==ip_in)
then
10099 xfpre(:)=xf(ip,:)-ds*k1(:)
10101 xfpre(:)=xf(ip,:)+ds*k1(:)
10104 xfnext(:)=xf(ip+1,:)
10111 xfnext(:)=xf(ip+1,:)
10116 dtds=abs(tnext-tpre)/(2*ds)
10123 if (dtds>0.d0)
then
10127 if(lr>trac_delta*lt)
then
10128 if (tnow>wl(2)) wl(2)=tnow
10131 if (tnow>wl(3)) wl(3)=tnow
10137 {
if (xf(ip+1,^db)>=xbmin^db .and. xf(ip+1,^db)<xbmax^db) inblock=inblock+1\}
10138 if (tcondi==
'TRAC' .and. xf(ip+1,ndim)>
phys_trac_mask) inblock=0
10139 if (inblock/=ndim)
exit mainloop
10145 subroutine get_k(xfn,igrid,K,ixI^L,dxb^D,ftype,b_min,field_ok)
10148 integer :: ixI^L,igrid
10149 double precision :: dxb^D
10150 double precision :: xfn(ndim),K(ndim)
10151 character(len=std_len) :: ftype
10152 double precision,
intent(in),
optional :: b_min
10153 logical,
intent(out),
optional :: field_ok
10155 double precision :: dxc^D,xd^D
10156 double precision :: field(0:1^D&,ndir),Fx(ndim),factor(0:1^D&)
10157 double precision :: Ftotal,field_min
10158 logical :: valid_field
10159 integer :: ixb^D,ix^D,ixbl^D,j,status_interp
10161 if (geo_coordinate==geo_spherical)
then
10162 call trace_interp_weights_block(xfn,igrid,ixi^l,ixbl^d,xd^d,dxc^d, &
10165 if (
present(field_ok)) field_ok=.false.
10170 ^d&ixbl^d=floor((xfn(^d)-ps(igrid)%x(iximin^dd,^d))/dxb^d)+iximin^d;
10171 ^d&xd^d=(xfn(^d)-ps(igrid)%x(ixbl^dd,^d))/dxb^d;
10175 if(ftype==
'Bfield')
then
10177 if(
allocated(iw_mag))
then
10179 field(ix^d,1:ndir)=ps(igrid)%w(ixbl^d+ix^d,iw_mag(1:ndir)) &
10180 +ps(igrid)%B0(ixbl^d+ix^d,1:ndir,0)
10184 field(ix^d,1:ndir)=ps(igrid)%B0(ixbl^d+ix^d,1:ndir,0)
10189 field(ix^d,1:ndir)=ps(igrid)%w(ixbl^d+ix^d,iw_mag(1:ndir))
10192 else if (ftype==
'Vfield')
then
10194 double precision :: w_stencil(ixbl^D:ixbl^D+1^D&,1:nw)
10195 double precision :: x_stencil(ixbl^D:ixbl^D+1^D&,1:ndim)
10196 double precision :: vector_stencil(ixbl^D:ixbl^D+1^D&,1:ndir)
10199 ^d&ixsmin^d=ixbl^d;
10200 ^d&ixsmax^d=ixbl^d+1;
10201 w_stencil(ixs^s,1:nw)=ps(igrid)%w(ixs^s,1:nw)
10202 x_stencil(ixs^s,1:ndim)=ps(igrid)%x(ixs^s,1:ndim)
10203 call phys_get_v(w_stencil,x_stencil,ixs^l,ixs^l,vector_stencil)
10205 field(ix^d,1:ndir)=vector_stencil(ixbl^d+ix^d,1:ndir)
10210 factor(ix^d)={abs(1-ix^d-xd^d)*}
10213 if (ftype==
'Bfield' .or. ftype==
'Vfield')
then
10217 fx(j)=fx(j)+field(ix^d,j)*factor(ix^d)
10220 else if (
associated(usr_set_field))
then
10221 call usr_set_field(xfn,igrid,fx,ftype)
10223 call mpistop(
'Field tracing error: wrong field type!')
10228 ftotal=ftotal+(fx(j))**2
10230 ftotal=dsqrt(ftotal)
10232 field_min=smalldouble
10233 if (
present(b_min)) field_min=max(b_min,zero)
10234 valid_field=ftotal>zero .and. ftotal>=field_min
10235 if (
present(field_ok)) field_ok=valid_field
10238 if (valid_field)
then
10239 select case (geo_coordinate)
10240 case (geo_spherical)
10242 if (.not.trace_spherical_metric_ok(xfn))
then
10243 valid_field=.false.
10244 if (
present(field_ok)) field_ok=.false.
10248 k(2)=fx(2)/(xfn(1)*ftotal)
10249 k(3)=fx(3)/(xfn(1)*dsin(xfn(2))*ftotal)
10252 k(1:ndim)=fx(1:ndim)/ftotal
10256 end subroutine get_k
10261 integer,
intent(in) :: igrid,ixI^L
10262 double precision,
intent(inout) :: xloc(ndim)
10263 double precision,
intent(inout) :: Tloc
10264 double precision,
intent(in) :: dxb^D
10266 double precision :: xd^D
10267 double precision :: factor(0:1^D&),Tnear(0:1^D&)
10268 integer :: ixb^D,ix^D,ixbl^D,j,ixO^L
10270 ^d&ixbl^d=floor((xloc(^d)-ps(igrid)%x(iximin^dd,^d))/dxb^d)+iximin^d;
10271 ^d&xd^d=(xloc(^d)-ps(igrid)%x(ixbl^dd,^d))/dxb^d;
10272 ^d&ixomin^d=ixbl^d;
10273 ^d&ixomax^d=ixomin^d+1;
10276 factor(ix^d)={abs(1-ix^d-xd^d)*}
10277 tnear(ix^d)=ps(igrid)%wextra(ixbl^d+ix^d,iw_tcoff)
10283 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