MPI-AMRVAC 3.2
The MPI - Adaptive Mesh Refinement - Versatile Advection Code (development version)
Loading...
Searching...
No Matches
mod_magnetic_topology.t
Go to the documentation of this file.
2 use, intrinsic :: ieee_arithmetic, only: ieee_value,ieee_quiet_nan, &
3 ieee_is_finite
5 xprobmin1,xprobmax1,global_time,ps,iwstart,nwgc,par_files
6 {^ifthreed
7 use mod_global_parameters, only: xprobmin2,xprobmax2,xprobmin3,xprobmax3
8 }
9 use mod_comm_lib, only: mpistop
10 use mod_geometry, only: geo_coordinate => coordinate, &
11 geo_cartesian => cartesian, geo_spherical => spherical, &
12 geo_cartesian_stretched => cartesian_stretched
47 implicit none
48 private
49
55 public :: mt_mapping_plane_xy
64
65 integer, parameter :: mt_vti_kind_float64 = 1
66 integer, parameter :: mt_vti_kind_int32 = 2
67 integer, parameter :: mt_vti_name_len = 64
68 integer, parameter :: mt_task_name_len = 128
69 double precision, parameter :: mt_unset_real = huge(1.d0)
70
71 character(len=mt_task_name_len) :: mt_mode = ''
72 character(len=mt_task_name_len) :: mt_output_file = ''
73 character(len=mt_task_name_len) :: mt_output_prefix = ''
74 character(len=mt_task_name_len) :: mt_seed_file = ''
75 character(len=mt_task_name_len) :: mt_seed_surface = ''
76 character(len=mt_task_name_len) :: mt_seed_layout = 'endpoint'
77 character(len=mt_task_name_len) :: mt_vtk_detail = 'minimal'
78 character(len=mt_task_name_len) :: mt_step_control = 'global_cell_fraction'
79 character(len=mt_task_name_len) :: mt_trace_integrator = 'rk2'
80 double precision :: mt_dL = -1.d0
81 double precision :: mt_step_fraction = 0.25d0
82 double precision :: mt_dL_min = 0.d0
83 double precision :: mt_rk45_atol = 1.d-8
84 double precision :: mt_rk45_rtol = 1.d-6
85 double precision :: mt_rk45_safety = 0.9d0
86 double precision :: mt_rk45_min_shrink = 0.2d0
87 double precision :: mt_rk45_max_grow = 5.d0
88 double precision :: mt_rk45_tangent_floor = 1.d0
89 double precision :: mt_rk45_tangent_rtol = 2.d-5
90 integer :: mt_max_steps = -1
91 double precision :: mt_max_steps_factor = 2.d0
92 double precision :: mt_b_min = -1.d0
93 double precision :: mt_seed_coord = mt_unset_real
94 double precision :: mt_seed_theta0 = mt_unset_real
95 double precision :: mt_seed_phi0 = mt_unset_real
96 double precision :: mt_seed_alpha = mt_unset_real
97 logical :: mt_compute_length = .true.
98 logical :: mt_compute_twist = .false.
99 logical :: mt_compute_q = .false.
100 logical :: mt_compute_qperp = .false.
101 logical :: mt_rk2_step_diagnostic = .false.
102 logical :: mt_rk45_step_diagnostic = .false.
103 logical :: mt_rk45_tangent_diagnostic = .false.
104 logical :: mt_rk2_fusion_diagnostic = .false.
105 logical :: mt_write_csv = .false.
106 character(len=mt_task_name_len) :: mt_plane = ''
107 double precision :: mt_origin(3) = mt_unset_real
108 double precision :: mt_e1(3) = mt_unset_real
109 double precision :: mt_e2(3) = mt_unset_real
110 double precision :: mt_xmin = mt_unset_real
111 double precision :: mt_xmax = mt_unset_real
112 double precision :: mt_ymin = mt_unset_real
113 double precision :: mt_ymax = mt_unset_real
114 double precision :: mt_zmin = mt_unset_real
115 double precision :: mt_zmax = mt_unset_real
116 double precision :: mt_x0 = mt_unset_real
117 double precision :: mt_y0 = mt_unset_real
118 double precision :: mt_z0 = mt_unset_real
119 integer :: mt_nx = -1
120 integer :: mt_ny = -1
121 integer :: mt_nz = -1
122 double precision :: mt_s1min = mt_unset_real
123 double precision :: mt_s1max = mt_unset_real
124 double precision :: mt_s2min = mt_unset_real
125 double precision :: mt_s2max = mt_unset_real
126 double precision :: mt_s3min = mt_unset_real
127 double precision :: mt_s3max = mt_unset_real
128 integer :: mt_n1 = -1
129 integer :: mt_n2 = -1
130 integer :: mt_n3 = -1
131 integer :: mt_chunk_nz = -1
132 logical :: mt_profile_spherical = .false.
133 logical :: mt_params_loaded = .false.
134
135 type, private :: mt_vti_array_desc
136 character(len=mt_vti_name_len) :: name
137 integer :: kind
138 integer(kind=8) :: nbytes
139 integer(kind=8) :: offset
140 end type mt_vti_array_desc
141
142 type, private :: mt_volume_products
143 double precision, allocatable :: length_total(:)
144 double precision, allocatable :: length_backward(:)
145 double precision, allocatable :: length_forward(:)
146 integer, allocatable :: nstep_backward_length(:)
147 integer, allocatable :: nstep_forward_length(:)
148 integer, allocatable :: status_backward_length(:)
149 integer, allocatable :: status_forward_length(:)
150 double precision, allocatable :: twist_total(:)
151 double precision, allocatable :: twist_backward(:)
152 double precision, allocatable :: twist_forward(:)
153 integer, allocatable :: nstep_backward_twist(:)
154 integer, allocatable :: nstep_forward_twist(:)
155 integer, allocatable :: status_backward_twist(:)
156 integer, allocatable :: status_forward_twist(:)
157 double precision, allocatable :: q(:)
158 double precision, allocatable :: logq(:)
159 double precision, allocatable :: N2_q(:)
160 double precision, allocatable :: bfactor_q(:)
161 double precision, allocatable :: length_forward_q(:)
162 double precision, allocatable :: length_backward_q(:)
163 double precision, allocatable :: Bseed_norm_q(:)
164 double precision, allocatable :: Bf_norm_q(:)
165 double precision, allocatable :: Bb_norm_q(:)
166 integer, allocatable :: valid_q(:)
167 integer, allocatable :: status_q(:)
168 integer, allocatable :: face_forward_q(:)
169 integer, allocatable :: face_backward_q(:)
170 integer, allocatable :: status_forward_q(:)
171 integer, allocatable :: status_backward_q(:)
172 double precision, allocatable :: qperp(:)
173 double precision, allocatable :: logqperp(:)
174 double precision, allocatable :: N2(:)
175 double precision, allocatable :: bfactor(:)
176 double precision, allocatable :: length_forward_qperp(:)
177 double precision, allocatable :: length_backward_qperp(:)
178 double precision, allocatable :: Bseed_norm(:)
179 double precision, allocatable :: Bf_norm(:)
180 double precision, allocatable :: Bb_norm(:)
181 integer, allocatable :: valid_qperp(:)
182 integer, allocatable :: status_qperp(:)
183 integer, allocatable :: face_forward_qperp(:)
184 integer, allocatable :: face_backward_qperp(:)
185 integer, allocatable :: status_forward_qperp(:)
186 integer, allocatable :: status_backward_qperp(:)
187 end type mt_volume_products
188
189contains
190
191 subroutine mt_params_read(files)
192 ! Read the one-task magnetic-topology namelist.
194 character(len=*), intent(in) :: files(:)
195
196 integer :: n
197
198 namelist /magnetic_topology_list/ mt_mode,mt_output_file, &
199 mt_output_prefix,mt_seed_file,mt_vtk_detail, &
200 mt_seed_surface,mt_seed_layout,mt_seed_coord, &
201 mt_seed_theta0,mt_seed_phi0,mt_seed_alpha, &
202 mt_step_control,mt_dl,mt_step_fraction,mt_dl_min, &
203 mt_trace_integrator,mt_rk45_atol,mt_rk45_rtol, &
204 mt_rk45_safety,mt_rk45_min_shrink,mt_rk45_max_grow, &
205 mt_rk45_tangent_floor,mt_rk45_tangent_rtol, &
206 mt_max_steps,mt_max_steps_factor,mt_b_min, &
207 mt_compute_length,mt_compute_twist,mt_compute_q,mt_compute_qperp, &
208 mt_rk2_step_diagnostic,mt_rk45_step_diagnostic, &
209 mt_rk45_tangent_diagnostic,mt_rk2_fusion_diagnostic, &
210 mt_write_csv,mt_plane, &
211 mt_origin,mt_e1,mt_e2,mt_xmin,mt_xmax,mt_ymin,mt_ymax, &
212 mt_zmin,mt_zmax,mt_nx,mt_ny,mt_nz,mt_x0,mt_y0,mt_z0, &
213 mt_s1min,mt_s1max,mt_n1,mt_s2min,mt_s2max,mt_n2, &
214 mt_s3min,mt_s3max,mt_n3, &
215 mt_chunk_nz,mt_profile_spherical
216
217 call mt_set_default_params()
218 do n=1,size(files)
219 open(unitpar,file=trim(files(n)),status='old')
220 read(unitpar,magnetic_topology_list,end=111)
221111 close(unitpar)
222 enddo
223 mt_params_loaded=.true.
224 end subroutine mt_params_read
225
227 ! Dispatch the namelist-selected topology/QSL postprocessing task.
228 ! This backend is deliberately single-MPI-rank and OpenMP capable.
229 use mod_comm_lib, only: mpistop
231 character(len=mt_task_name_len) :: mode
232 logical :: report_rk2,report_rk45
233
234 if (npe/=1) call mpistop(&
235 'magnetic-topology conversion requires npe=1; use OpenMP threads')
236 if (.not.mt_params_loaded) call mt_params_read(par_files)
237 call getbc(global_time,0.d0,ps,iwstart,nwgc)
238
239 mode=mt_lowercase(trim(mt_mode))
240 call mt_validate_common_params(mode)
241 call mt_validate_trace_integrator(mode)
242 call mt_apply_trace_step_control()
243 call mt_apply_auto_max_steps()
244 call trace_set_integrator(mt_trace_integrator,mt_rk45_atol, &
245 mt_rk45_rtol,mt_rk45_safety,mt_rk45_min_shrink, &
246 mt_rk45_max_grow,mt_rk45_tangent_floor,mt_rk45_tangent_rtol)
247 report_rk2=mt_lowercase(trim(mt_trace_integrator))=='rk2' .and. &
248 mt_rk2_step_diagnostic
249 report_rk45=(mt_lowercase(trim(mt_trace_integrator))=='rk45_cartesian' &
250 .or. mt_lowercase(trim(mt_trace_integrator))=='rk45_spherical') &
251 .and. mt_rk45_step_diagnostic
252 call trace_rk2_stats_set_enabled(report_rk2)
253 call trace_rk45_stats_set_enabled(report_rk45)
254 if (report_rk2) call trace_rk2_stats_reset()
255 if (report_rk45) call trace_rk45_stats_reset()
256 if (mt_profile_spherical .and. &
257 trim(mode)/='spherical_surface_products' .and. &
258 trim(mode)/='spherical_cloud_products') then
259 write(*,'(a)') 'mt_run_topology_task: mt_profile_spherical applies '// &
260 'only to spherical topology modes'
261 endif
262
263 select case (trim(mode))
264 case ('axis_plane_full_vtu')
265 call mt_run_axis_plane_full_vtu_task()
266 case ('volume_vti')
267 call mt_run_volume_vti_task()
268 case ('arbitrary_plane_products')
269 call mt_run_arbitrary_plane_products_task()
270 case ('seed_products')
271 call mt_run_seed_products_task()
272 case ('axis_plane_csv')
273 call mt_run_axis_plane_csv_task()
274 case ('spherical_surface_products')
275 call mt_run_spherical_surface_products_task()
276 case ('spherical_cloud_products')
277 call mt_run_spherical_cloud_products_task()
278 case default
279 call mpistop('mt_run_topology_task: unknown mt_mode='//trim(mt_mode))
280 end select
281 if (report_rk2) call trace_rk2_stats_report(trim(mode))
282 call trace_rk2_stats_set_enabled(.false.)
283 if (report_rk45) call trace_rk45_stats_report(trim(mode))
284 call trace_rk45_stats_set_enabled(.false.)
285 end subroutine mt_run_topology_task
286
287 subroutine mt_set_default_params()
288 mt_params_loaded=.false.
289 mt_mode=''
290 mt_output_file=''
291 mt_output_prefix=''
292 mt_seed_file=''
293 mt_seed_surface=''
294 mt_seed_layout='endpoint'
295 mt_vtk_detail='minimal'
296 mt_step_control='global_cell_fraction'
297 mt_trace_integrator='rk2'
298 mt_dl=-1.d0
299 mt_step_fraction=0.25d0
300 mt_dl_min=0.d0
301 mt_rk45_atol=1.d-8
302 mt_rk45_rtol=1.d-6
303 mt_rk45_safety=0.9d0
304 mt_rk45_min_shrink=0.2d0
305 mt_rk45_max_grow=5.d0
306 mt_rk45_tangent_floor=1.d0
307 mt_rk45_tangent_rtol=2.d-5
308 mt_max_steps=-1
309 mt_max_steps_factor=2.d0
310 mt_b_min=-1.d0
311 mt_seed_coord=mt_unset_real
312 mt_seed_theta0=mt_unset_real
313 mt_seed_phi0=mt_unset_real
314 mt_seed_alpha=mt_unset_real
315 mt_compute_length=.true.
316 mt_compute_twist=.false.
317 mt_compute_q=.false.
318 mt_compute_qperp=.false.
319 mt_rk2_step_diagnostic=.false.
320 mt_rk45_step_diagnostic=.false.
321 mt_rk45_tangent_diagnostic=.false.
322 mt_rk2_fusion_diagnostic=.false.
323 mt_write_csv=.false.
324 mt_plane=''
325 mt_origin=mt_unset_real
326 mt_e1=mt_unset_real
327 mt_e2=mt_unset_real
328 mt_xmin=mt_unset_real
329 mt_xmax=mt_unset_real
330 mt_ymin=mt_unset_real
331 mt_ymax=mt_unset_real
332 mt_zmin=mt_unset_real
333 mt_zmax=mt_unset_real
334 mt_x0=mt_unset_real
335 mt_y0=mt_unset_real
336 mt_z0=mt_unset_real
337 mt_nx=-1
338 mt_ny=-1
339 mt_nz=-1
340 mt_s1min=mt_unset_real
341 mt_s1max=mt_unset_real
342 mt_s2min=mt_unset_real
343 mt_s2max=mt_unset_real
344 mt_s3min=mt_unset_real
345 mt_s3max=mt_unset_real
346 mt_n1=-1
347 mt_n2=-1
348 mt_n3=-1
349 mt_chunk_nz=-1
350 mt_profile_spherical=.false.
351 end subroutine mt_set_default_params
352
353 subroutine mt_validate_common_params(mode)
354 character(len=*), intent(in) :: mode
355
356 if (len_trim(mode)==0) then
357 call mpistop('mt_run_topology_task requires mt_mode')
358 endif
359 select case (trim(mode))
360 case ('spherical_surface_products','spherical_cloud_products')
361 if (ndim/=3) then
362 call mpistop(trim(mode)//' requires 3D spherical geometry')
363 endif
364 {^ifthreed
365 if (geo_coordinate/=geo_spherical) then
366 call mpistop(trim(mode)//' requires 3D spherical geometry')
367 endif
368 if (periodb(3)) then
369 call mpistop(trim(mode)//' does not yet support periodic phi')
370 endif
371 }
372 case ('seed_products')
373 if (ndim/=3) then
374 call mpistop('seed_products requires 3D Cartesian or spherical geometry')
375 endif
376 {^ifthreed
377 select case (geo_coordinate)
378 case (geo_cartesian,geo_cartesian_stretched,geo_spherical)
379 case default
380 call mpistop('seed_products requires Cartesian or spherical geometry')
381 end select
382 if (geo_coordinate==geo_spherical .and. periodb(3)) then
383 call mpistop('spherical seed_products does not yet support periodic phi')
384 endif
385 }
386 case ('volume_vti')
387 if (ndim/=3) then
388 call mpistop('volume_vti requires 3D Cartesian geometry')
389 endif
390 {^ifthreed
391 select case (geo_coordinate)
392 case (geo_cartesian)
393 ! The VTI sampling grid is user-defined; tracing may interpolate
394 ! through uniform or AMR Cartesian simulation grids.
395 case (geo_cartesian_stretched)
396 ! The VTI sampling grid is uniform Cartesian; tracing may interpolate
397 ! through a stretched Cartesian simulation grid.
398 case default
399 call mpistop('volume_vti requires Cartesian geometry')
400 end select
401 }
402 case ('axis_plane_full_vtu','axis_plane_csv')
403 if (ndim/=3) then
404 call mpistop(trim(mode)//' requires 3D Cartesian geometry')
405 endif
406 {^ifthreed
407 select case (geo_coordinate)
408 case (geo_cartesian)
409 ! Axis-plane output is a seed-surface product; RK2 tracing supports
410 ! both slab-uniform and AMR Cartesian simulation grids.
411 case (geo_cartesian_stretched)
412 case default
413 call mpistop(trim(mode)//' requires Cartesian geometry')
414 end select
415 }
416 case ('arbitrary_plane_products')
417 if (ndim/=3) then
418 call mpistop('arbitrary_plane_products requires 3D Cartesian geometry')
419 endif
420 {^ifthreed
421 select case (geo_coordinate)
422 case (geo_cartesian,geo_cartesian_stretched)
423 case default
424 call mpistop('arbitrary_plane_products requires Cartesian geometry')
425 end select
426 }
427 case default
428 if (ndim/=3 .or. geo_coordinate/=geo_cartesian .or. &
429 .not.slab_uniform) then
430 call mpistop('mt_run_topology_task mode requires 3D uniform Cartesian geometry')
431 endif
432 end select
433 if (len_trim(mt_output_file)==0 .and. &
434 len_trim(mt_output_prefix)==0) then
435 call mpistop('mt_run_topology_task requires mt_output_file or mt_output_prefix')
436 endif
437 select case (mt_lowercase(trim(mt_step_control)))
438 case ('fixed')
439 if (mt_dl<=0.d0) then
440 call mpistop('mt_step_control=fixed requires mt_dL > 0')
441 endif
442 case ('cell_fraction')
443 select case (geo_coordinate)
444 case (geo_cartesian,geo_cartesian_stretched)
445 case (geo_spherical)
446 select case (trim(mode))
447 case ('seed_products','spherical_surface_products', &
448 'spherical_cloud_products')
449 case default
450 call mpistop('mt_step_control=cell_fraction is only supported '// &
451 'for spherical topology modes')
452 end select
453 case default
454 call mpistop('mt_step_control=cell_fraction requires Cartesian or '// &
455 'supported spherical geometry')
456 end select
457 if (mt_step_fraction<=0.d0) then
458 call mpistop('mt_step_control=cell_fraction requires '// &
459 'mt_step_fraction > 0')
460 endif
461 if (mt_dl_min<0.d0) then
462 call mpistop('mt_step_control=cell_fraction requires mt_dL_min >= 0')
463 endif
464 case ('global_cell_fraction')
465 if (mt_step_fraction<=0.d0) then
466 call mpistop('mt_step_control=global_cell_fraction requires '// &
467 'mt_step_fraction > 0')
468 endif
469 if (mt_dl_min<0.d0) then
470 call mpistop('mt_step_control=global_cell_fraction requires mt_dL_min >= 0')
471 endif
472 case default
473 call mpistop('mt_run_topology_task requires mt_step_control=fixed '// &
474 'or cell_fraction/global_cell_fraction')
475 end select
476 if (mt_max_steps<=0 .and. mt_max_steps_factor<=0.d0) then
477 call mpistop('mt_max_steps auto requires mt_max_steps_factor > 0')
478 endif
479 select case (mt_lowercase(trim(mt_vtk_detail)))
480 case ('minimal','full')
481 case default
482 call mpistop('mt_run_topology_task requires mt_vtk_detail=minimal or full')
483 end select
484 end subroutine mt_validate_common_params
485
486 subroutine mt_validate_trace_integrator(mode)
487 character(len=*), intent(in) :: mode
488
489 character(len=mt_task_name_len) :: integrator
490
491 integrator=mt_lowercase(trim(mt_trace_integrator))
492 select case (trim(integrator))
493 case ('rk2')
494 ! RK2 is the default tracing path; product-specific guards live below.
495 case ('rk45_cartesian')
496 if (trim(mode)/='seed_products' .and. trim(mode)/='volume_vti' .and. &
497 trim(mode)/='arbitrary_plane_products' .and. &
498 trim(mode)/='axis_plane_full_vtu' .and. &
499 trim(mode)/='axis_plane_csv') then
500 write(*,'(a)') 'mt_trace_integrator=rk45_cartesian supports '// &
501 'only Cartesian seed_products, volume_vti, arbitrary_plane_products, '// &
502 'or axis-plane products'
503 flush(6)
504 call mpistop('mt_trace_integrator=rk45_cartesian supports '// &
505 'only seed_products, volume_vti, arbitrary_plane_products, '// &
506 'or axis-plane products')
507 endif
508 if (ndim/=3) then
509 call mpistop('mt_trace_integrator=rk45_cartesian requires 3D Cartesian geometry')
510 endif
511 {^ifthreed
512 select case (geo_coordinate)
513 case (geo_cartesian,geo_cartesian_stretched)
514 case default
515 write(*,'(a)') 'mt_trace_integrator=rk45_cartesian is Cartesian-only'
516 flush(6)
517 call mpistop('mt_trace_integrator=rk45_cartesian is Cartesian-only')
518 end select
519 }
520 if (mt_rk45_atol<0.d0 .or. mt_rk45_rtol<0.d0 .or. &
521 mt_rk45_atol+mt_rk45_rtol<=0.d0) then
522 call mpistop('mt_trace_integrator=rk45_cartesian requires '// &
523 'non-negative tolerances with atol+rtol > 0')
524 endif
525 if (mt_rk45_safety<=0.d0 .or. mt_rk45_safety>1.d0) then
526 call mpistop('mt_rk45_safety must be in (0,1]')
527 endif
528 if (mt_rk45_min_shrink<=0.d0 .or. mt_rk45_min_shrink>1.d0) then
529 call mpistop('mt_rk45_min_shrink must be in (0,1]')
530 endif
531 if (mt_rk45_max_grow<1.d0) then
532 call mpistop('mt_rk45_max_grow must be >= 1')
533 endif
534 if (mt_rk45_tangent_floor<=0.d0) then
535 call mpistop('mt_rk45_tangent_floor must be > 0')
536 endif
537 if (mt_rk45_tangent_rtol<=0.d0) then
538 call mpistop('mt_rk45_tangent_rtol must be > 0')
539 endif
540 case ('rk45_spherical')
541 if (trim(mode)/='seed_products' .and. &
542 trim(mode)/='spherical_cloud_products' .and. &
543 trim(mode)/='spherical_surface_products') then
544 write(*,'(a)') 'mt_trace_integrator=rk45_spherical supports '// &
545 'only spherical seed_products, spherical_cloud_products, '// &
546 'or spherical_surface_products'
547 flush(6)
548 call mpistop('mt_trace_integrator=rk45_spherical supports '// &
549 'only seed_products, spherical_cloud_products, '// &
550 'or spherical_surface_products')
551 endif
552 if (ndim/=3) then
553 call mpistop('mt_trace_integrator=rk45_spherical requires 3D spherical geometry')
554 endif
555 {^ifthreed
556 if (geo_coordinate/=geo_spherical) then
557 write(*,'(a)') 'mt_trace_integrator=rk45_spherical is spherical-only'
558 flush(6)
559 call mpistop('mt_trace_integrator=rk45_spherical is spherical-only')
560 endif
561 if (periodb(3)) then
562 call mpistop('mt_trace_integrator=rk45_spherical does not yet support periodic phi')
563 endif
564 }
565 if (mt_compute_q) then
566 {^ifthreed
567 if (geo_coordinate/=geo_spherical) then
568 call mpistop('mt_trace_integrator=rk45_spherical standard '// &
569 'logQ currently requires spherical geometry')
570 endif
571 }
572 endif
573 if (mt_rk45_atol<0.d0 .or. mt_rk45_rtol<0.d0 .or. &
574 mt_rk45_atol+mt_rk45_rtol<=0.d0) then
575 call mpistop('mt_trace_integrator=rk45_spherical requires '// &
576 'non-negative tolerances with atol+rtol > 0')
577 endif
578 if (mt_rk45_safety<=0.d0 .or. mt_rk45_safety>1.d0) then
579 call mpistop('mt_rk45_safety must be in (0,1]')
580 endif
581 if (mt_rk45_min_shrink<=0.d0 .or. mt_rk45_min_shrink>1.d0) then
582 call mpistop('mt_rk45_min_shrink must be in (0,1]')
583 endif
584 if (mt_rk45_max_grow<1.d0) then
585 call mpistop('mt_rk45_max_grow must be >= 1')
586 endif
587 if (mt_rk45_tangent_floor<=0.d0) then
588 call mpistop('mt_rk45_tangent_floor must be > 0')
589 endif
590 if (mt_rk45_tangent_rtol<=0.d0) then
591 call mpistop('mt_rk45_tangent_rtol must be > 0')
592 endif
593 case default
594 call mpistop('mt_trace_integrator must be rk2, rk45_cartesian, or rk45_spherical')
595 end select
596 if (mt_rk45_tangent_diagnostic) then
597 if (trim(mode)/='seed_products') then
598 call mpistop('mt_rk45_tangent_diagnostic requires seed_products')
599 endif
600 if (trim(integrator)/='rk45_cartesian') then
601 call mpistop('mt_rk45_tangent_diagnostic requires '// &
602 'mt_trace_integrator=rk45_cartesian')
603 endif
604 if (mt_compute_q .or. mt_compute_qperp) then
605 call mpistop('mt_rk45_tangent_diagnostic is q0 diagnostic-only; '// &
606 'disable public Q and Qperp')
607 endif
608 if (ndim/=3 .or. .not.slab_uniform) then
609 call mpistop('mt_rk45_tangent_diagnostic requires 3D uniform Cartesian geometry')
610 endif
611 {^ifthreed
612 if (geo_coordinate/=geo_cartesian) then
613 call mpistop('mt_rk45_tangent_diagnostic requires Cartesian geometry')
614 endif
615 }
616 endif
617 if (mt_rk2_fusion_diagnostic) then
618 if (trim(mode)/='seed_products') then
619 call mpistop('mt_rk2_fusion_diagnostic requires seed_products')
620 endif
621 if (trim(integrator)/='rk2') then
622 call mpistop('mt_rk2_fusion_diagnostic requires '// &
623 'mt_trace_integrator=rk2')
624 endif
625 if (.not.mt_compute_twist) then
626 call mpistop('mt_rk2_fusion_diagnostic requires twist diagnostics')
627 endif
628 if (mt_compute_q .or. mt_compute_qperp) then
629 call mpistop('mt_rk2_fusion_diagnostic is q0 diagnostic-only; '// &
630 'disable public Q and Qperp')
631 endif
632 endif
633 end subroutine mt_validate_trace_integrator
634
635 subroutine mt_apply_trace_step_control()
636 character(len=mt_task_name_len) :: step_mode
637 double precision :: hmin,dl_eff,dl_cap
638 integer :: status
639
640 step_mode=mt_lowercase(trim(mt_step_control))
641 select case (trim(step_mode))
642 case ('cell_fraction')
643 if ((geo_coordinate==geo_cartesian .or. &
644 geo_coordinate==geo_cartesian_stretched .or. &
645 geo_coordinate==geo_spherical) .and. mt_dl<=0.d0) then
646 dl_cap=mt_domain_diagonal()
647 if (dl_cap<=0.d0) then
648 call mpistop('mt_step_control=cell_fraction could not determine '// &
649 'domain step cap')
650 endif
651 mt_dl=dl_cap
652 write(*,'(a,es16.8,a,es16.8,a,es16.8)') &
653 'mt_step_control=cell_fraction: mt_step_fraction=', &
654 mt_step_fraction,', automatic dL_cap=',mt_dl, &
655 ', mt_dL_min=',mt_dl_min
656 else
657 write(*,'(a,es16.8,a,es16.8,a,es16.8)') &
658 'mt_step_control=cell_fraction: mt_step_fraction=', &
659 mt_step_fraction,', mt_dL_cap=',mt_dl, &
660 ', mt_dL_min=',mt_dl_min
661 endif
662 call trace_set_step_control('cell_fraction',mt_step_fraction,mt_dl_min)
663 case ('global_cell_fraction')
664 select case (geo_coordinate)
665 case (geo_cartesian,geo_cartesian_stretched)
666 call trace_cartesian_global_min_cell_size(hmin,status)
667 case (geo_spherical)
668 call trace_spherical_global_min_cell_size(hmin,status)
669 case default
670 status=trace_status_unsupported_geometry
671 hmin=-1.d0
672 end select
673 if (status/=trace_status_active .or. hmin<=0.d0) then
674 call mpistop('mt_step_control=global_cell_fraction could not determine h_global_min')
675 endif
676 dl_eff=mt_step_fraction*hmin
677 if (mt_dl>0.d0) dl_eff=min(dl_eff,mt_dl)
678 if (mt_dl_min>0.d0) then
679 if (mt_dl>0.d0) then
680 dl_eff=max(dl_eff,min(mt_dl_min,mt_dl))
681 else
682 dl_eff=max(dl_eff,mt_dl_min)
683 endif
684 endif
685 if (dl_eff<=0.d0) then
686 call mpistop('mt_step_control=global_cell_fraction produced non-positive mt_dL')
687 endif
688 if (mt_dl>0.d0) then
689 write(*,'(a,es16.8,a,es16.8,a,es16.8,a,es16.8)') &
690 'mt_step_control=global_cell_fraction: h_global_min=',hmin, &
691 ', mt_step_fraction=',mt_step_fraction,', mt_dL_cap=',mt_dl, &
692 ', effective_mt_dL=',dl_eff
693 else
694 write(*,'(a,es16.8,a,es16.8,a,es16.8)') &
695 'mt_step_control=global_cell_fraction: h_global_min=',hmin, &
696 ', mt_step_fraction=',mt_step_fraction,', effective_mt_dL=',dl_eff
697 endif
698 mt_dl=dl_eff
699 call trace_set_step_control('fixed',mt_step_fraction,mt_dl_min)
700 case default
701 call trace_set_step_control('fixed',mt_step_fraction,mt_dl_min)
702 end select
703 end subroutine mt_apply_trace_step_control
704
705 subroutine mt_apply_auto_max_steps()
706 character(len=mt_task_name_len) :: step_mode
707 double precision :: hmin,step_est,ldiag,nsteps_real
708 integer :: status
709
710 if (mt_max_steps>0) return
711
712 ldiag=mt_domain_diagonal()
713 if (ldiag<=0.d0) then
714 call mpistop('mt_max_steps auto could not determine domain diagonal')
715 endif
716
717 step_mode=mt_lowercase(trim(mt_step_control))
718 select case (trim(step_mode))
719 case ('fixed')
720 step_est=mt_dl
721 case ('cell_fraction','global_cell_fraction')
722 select case (geo_coordinate)
723 case (geo_cartesian,geo_cartesian_stretched)
724 call trace_cartesian_global_min_cell_size(hmin,status)
725 case (geo_spherical)
726 call trace_spherical_global_min_cell_size(hmin,status)
727 case default
728 status=trace_status_unsupported_geometry
729 hmin=-1.d0
730 end select
731 if (status/=trace_status_active .or. hmin<=0.d0) then
732 call mpistop('mt_max_steps auto could not determine h_global_min')
733 endif
734 step_est=mt_step_fraction*hmin
735 if (mt_dl>0.d0) step_est=min(step_est,mt_dl)
736 case default
737 step_est=mt_dl
738 end select
739
740 if (step_est<=0.d0) then
741 call mpistop('mt_max_steps auto produced non-positive step estimate')
742 endif
743 nsteps_real=mt_max_steps_factor*ldiag/step_est
744 if (nsteps_real>dble(huge(mt_max_steps)-1)) then
745 call mpistop('mt_max_steps auto estimate exceeds integer range')
746 endif
747 mt_max_steps=max(1,ceiling(nsteps_real))
748 write(*,'(a,es16.8,a,es16.8,a,es16.8,a,es16.8,a,i0)') &
749 'mt_max_steps auto: Ldiag=',ldiag,', step_est=',step_est, &
750 ', factor=',mt_max_steps_factor,', nsteps_real=',nsteps_real, &
751 ', mt_max_steps=',mt_max_steps
752 end subroutine mt_apply_auto_max_steps
753
754 double precision function mt_domain_diagonal() result(Ldiag)
755 integer :: i,j,k,n,m
756 double precision :: r,theta,phi,dist
757 double precision :: corners(8,3),dx(3)
758
759 ldiag=abs(xprobmax1-xprobmin1)
760 {^ifthreed
761 if (geo_coordinate==geo_spherical) then
762 n=0
763 do i=0,1
764 if (i==0) then
765 r=xprobmin1
766 else
767 r=xprobmax1
768 endif
769 do j=0,1
770 if (j==0) then
771 theta=xprobmin2
772 else
773 theta=xprobmax2
774 endif
775 do k=0,1
776 if (k==0) then
777 phi=xprobmin3
778 else
779 phi=xprobmax3
780 endif
781 n=n+1
782 corners(n,1)=r*dsin(theta)*dcos(phi)
783 corners(n,2)=r*dsin(theta)*dsin(phi)
784 corners(n,3)=r*dcos(theta)
785 end do
786 end do
787 end do
788 ldiag=0.d0
789 do i=1,n-1
790 do j=i+1,n
791 do m=1,3
792 dx(m)=corners(i,m)-corners(j,m)
793 end do
794 dist=dsqrt(sum(dx*dx))
795 ldiag=max(ldiag,dist)
796 end do
797 end do
798 else
799 ldiag=dsqrt((xprobmax1-xprobmin1)**2+ &
800 (xprobmax2-xprobmin2)**2+(xprobmax3-xprobmin3)**2)
801 endif
802 }
803 end function mt_domain_diagonal
804
805 subroutine mt_run_axis_plane_full_vtu_task()
806 character(len=mt_task_name_len) :: plane
807 character(len=mt_task_name_len) :: output_file
808 logical :: minimal_output
809
810 plane=mt_lowercase(trim(mt_plane))
811 minimal_output=.not.mt_vtk_detail_is_full()
812 if (minimal_output) then
813 call mt_resolve_output_file('axis_plane_full_vtu','.vti', &
814 '_'//trim(plane)//'_minimal.vti',output_file)
815 else
816 call mt_resolve_output_file('axis_plane_full_vtu','.vtu', &
817 '_'//trim(plane)//'_full.vtu',output_file)
818 endif
819 if (.not.minimal_output .and. &
820 (mt_compute_twist .or. mt_compute_q .or. mt_compute_qperp)) then
821 write(*,'(a)') 'mt_run_topology_task: axis_plane_full_vtu ignores compute flags'
822 write(*,'(a)') 'mt_run_topology_task: it always writes full plane products'
823 endif
824
825 select case (trim(plane))
826 case ('xy')
827 call mt_require_real('mt_xmin',mt_xmin)
828 call mt_require_real('mt_xmax',mt_xmax)
829 call mt_require_real('mt_ymin',mt_ymin)
830 call mt_require_real('mt_ymax',mt_ymax)
831 call mt_require_real('mt_z0',mt_z0)
832 call mt_require_positive_int('mt_nx',mt_nx)
833 call mt_require_positive_int('mt_ny',mt_ny)
834 call mt_require_ordered('mt_xmin','mt_xmax',mt_xmin,mt_xmax)
835 call mt_require_ordered('mt_ymin','mt_ymax',mt_ymin,mt_ymax)
836 if (minimal_output) then
837 write(*,'(a)') 'mt_run_topology_task: writing axis-plane minimal VTI '//trim(output_file)
838 if (mt_b_min>0.d0) then
839 call mt_qsl_plane_vti_xy(mt_xmin,mt_xmax,mt_nx,mt_ymin,mt_ymax, &
840 mt_ny,mt_z0,mt_dl,mt_max_steps,trim(output_file), &
841 mt_compute_length,mt_compute_twist,mt_compute_q, &
842 mt_compute_qperp,b_min=mt_b_min)
843 else
844 call mt_qsl_plane_vti_xy(mt_xmin,mt_xmax,mt_nx,mt_ymin,mt_ymax, &
845 mt_ny,mt_z0,mt_dl,mt_max_steps,trim(output_file), &
846 mt_compute_length,mt_compute_twist,mt_compute_q, &
847 mt_compute_qperp)
848 endif
849 else
850 write(*,'(a)') 'mt_run_topology_task: writing axis-plane full VTU '//trim(output_file)
851 if (mt_b_min>0.d0) then
852 call mt_qsl_plane_vtu_xy(mt_xmin,mt_xmax,mt_nx,mt_ymin,mt_ymax, &
853 mt_ny,mt_z0,mt_dl,mt_max_steps,trim(output_file), &
854 b_min=mt_b_min)
855 else
856 call mt_qsl_plane_vtu_xy(mt_xmin,mt_xmax,mt_nx,mt_ymin,mt_ymax, &
857 mt_ny,mt_z0,mt_dl,mt_max_steps,trim(output_file))
858 endif
859 endif
860 case ('xz')
861 call mt_require_real('mt_xmin',mt_xmin)
862 call mt_require_real('mt_xmax',mt_xmax)
863 call mt_require_real('mt_zmin',mt_zmin)
864 call mt_require_real('mt_zmax',mt_zmax)
865 call mt_require_real('mt_y0',mt_y0)
866 call mt_require_positive_int('mt_nx',mt_nx)
867 call mt_require_positive_int('mt_nz',mt_nz)
868 call mt_require_ordered('mt_xmin','mt_xmax',mt_xmin,mt_xmax)
869 call mt_require_ordered('mt_zmin','mt_zmax',mt_zmin,mt_zmax)
870 if (minimal_output) then
871 write(*,'(a)') 'mt_run_topology_task: writing axis-plane minimal VTI '//trim(output_file)
872 if (mt_b_min>0.d0) then
873 call mt_qsl_plane_vti_xz(mt_xmin,mt_xmax,mt_nx,mt_zmin,mt_zmax, &
874 mt_nz,mt_y0,mt_dl,mt_max_steps,trim(output_file), &
875 mt_compute_length,mt_compute_twist,mt_compute_q, &
876 mt_compute_qperp,b_min=mt_b_min)
877 else
878 call mt_qsl_plane_vti_xz(mt_xmin,mt_xmax,mt_nx,mt_zmin,mt_zmax, &
879 mt_nz,mt_y0,mt_dl,mt_max_steps,trim(output_file), &
880 mt_compute_length,mt_compute_twist,mt_compute_q, &
881 mt_compute_qperp)
882 endif
883 else
884 write(*,'(a)') 'mt_run_topology_task: writing axis-plane full VTU '//trim(output_file)
885 if (mt_b_min>0.d0) then
886 call mt_qsl_plane_vtu_xz(mt_xmin,mt_xmax,mt_nx,mt_zmin,mt_zmax, &
887 mt_nz,mt_y0,mt_dl,mt_max_steps,trim(output_file), &
888 b_min=mt_b_min)
889 else
890 call mt_qsl_plane_vtu_xz(mt_xmin,mt_xmax,mt_nx,mt_zmin,mt_zmax, &
891 mt_nz,mt_y0,mt_dl,mt_max_steps,trim(output_file))
892 endif
893 endif
894 case ('yz')
895 call mt_require_real('mt_ymin',mt_ymin)
896 call mt_require_real('mt_ymax',mt_ymax)
897 call mt_require_real('mt_zmin',mt_zmin)
898 call mt_require_real('mt_zmax',mt_zmax)
899 call mt_require_real('mt_x0',mt_x0)
900 call mt_require_positive_int('mt_ny',mt_ny)
901 call mt_require_positive_int('mt_nz',mt_nz)
902 call mt_require_ordered('mt_ymin','mt_ymax',mt_ymin,mt_ymax)
903 call mt_require_ordered('mt_zmin','mt_zmax',mt_zmin,mt_zmax)
904 if (minimal_output) then
905 write(*,'(a)') 'mt_run_topology_task: writing axis-plane minimal VTI '//trim(output_file)
906 if (mt_b_min>0.d0) then
907 call mt_qsl_plane_vti_yz(mt_ymin,mt_ymax,mt_ny,mt_zmin,mt_zmax, &
908 mt_nz,mt_x0,mt_dl,mt_max_steps,trim(output_file), &
909 mt_compute_length,mt_compute_twist,mt_compute_q, &
910 mt_compute_qperp,b_min=mt_b_min)
911 else
912 call mt_qsl_plane_vti_yz(mt_ymin,mt_ymax,mt_ny,mt_zmin,mt_zmax, &
913 mt_nz,mt_x0,mt_dl,mt_max_steps,trim(output_file), &
914 mt_compute_length,mt_compute_twist,mt_compute_q, &
915 mt_compute_qperp)
916 endif
917 else
918 write(*,'(a)') 'mt_run_topology_task: writing axis-plane full VTU '//trim(output_file)
919 if (mt_b_min>0.d0) then
920 call mt_qsl_plane_vtu_yz(mt_ymin,mt_ymax,mt_ny,mt_zmin,mt_zmax, &
921 mt_nz,mt_x0,mt_dl,mt_max_steps,trim(output_file), &
922 b_min=mt_b_min)
923 else
924 call mt_qsl_plane_vtu_yz(mt_ymin,mt_ymax,mt_ny,mt_zmin,mt_zmax, &
925 mt_nz,mt_x0,mt_dl,mt_max_steps,trim(output_file))
926 endif
927 endif
928 case default
929 call mpistop('mt_run_topology_task: axis_plane_full_vtu requires mt_plane=xy, xz, or yz')
930 end select
931 end subroutine mt_run_axis_plane_full_vtu_task
932
933 subroutine mt_run_axis_plane_csv_task()
934 character(len=mt_task_name_len) :: plane
935 character(len=mt_task_name_len) :: length_csv,twist_csv
936 character(len=mt_task_name_len) :: q_csv
937 character(len=mt_task_name_len) :: qperp_csv
938
939 if (len_trim(mt_output_prefix)==0) then
940 call mpistop('axis_plane_csv requires mt_output_prefix')
941 endif
942 if (len_trim(mt_output_file)>0) then
943 write(*,'(a)') 'mt_run_topology_task: axis_plane_csv ignores mt_output_file'
944 write(*,'(a)') 'mt_run_topology_task: axis_plane_csv uses mt_output_prefix for CSV outputs'
945 endif
946
947 plane=mt_lowercase(trim(mt_plane))
948 call mt_resolve_prefix_file('_'//trim(plane)//'_length.csv', &
949 length_csv,'axis_plane_csv length requires mt_output_prefix')
950 twist_csv=''
951 q_csv=''
952 qperp_csv=''
953 if (mt_compute_twist) then
954 call mt_resolve_prefix_file('_'//trim(plane)//'_twist.csv', &
955 twist_csv,'axis_plane_csv twist requires mt_output_prefix')
956 endif
957 if (mt_compute_q) then
958 call mt_resolve_prefix_file('_'//trim(plane)//'_q.csv', &
959 q_csv,'axis_plane_csv Q requires mt_output_prefix')
960 endif
961 if (mt_compute_qperp) then
962 call mt_resolve_prefix_file('_'//trim(plane)//'_qperp_method2.csv', &
963 qperp_csv,'axis_plane_csv Qperp requires mt_output_prefix')
964 endif
965
966 select case (trim(plane))
967 case ('xy')
968 call mt_require_real('mt_xmin',mt_xmin)
969 call mt_require_real('mt_xmax',mt_xmax)
970 call mt_require_real('mt_ymin',mt_ymin)
971 call mt_require_real('mt_ymax',mt_ymax)
972 call mt_require_real('mt_z0',mt_z0)
973 call mt_require_positive_int('mt_nx',mt_nx)
974 call mt_require_positive_int('mt_ny',mt_ny)
975 call mt_require_ordered('mt_xmin','mt_xmax',mt_xmin,mt_xmax)
976 call mt_require_ordered('mt_ymin','mt_ymax',mt_ymin,mt_ymax)
977 if (mt_b_min>0.d0) then
978 call mt_axis_plane_products_csv_axis(mt_xmin,mt_xmax,mt_nx, &
979 mt_ymin,mt_ymax,mt_ny,mt_z0,1,2,3,mt_dl,mt_max_steps, &
980 trim(length_csv),trim(twist_csv),trim(q_csv), &
981 trim(qperp_csv),'mt_axis_plane_products_csv_xy','ix,iy', &
982 'ix,iy',b_min=mt_b_min)
983 else
984 call mt_axis_plane_products_csv_axis(mt_xmin,mt_xmax,mt_nx, &
985 mt_ymin,mt_ymax,mt_ny,mt_z0,1,2,3,mt_dl,mt_max_steps, &
986 trim(length_csv),trim(twist_csv),trim(q_csv), &
987 trim(qperp_csv),'mt_axis_plane_products_csv_xy','ix,iy', &
988 'ix,iy')
989 endif
990 case ('xz')
991 call mt_require_real('mt_xmin',mt_xmin)
992 call mt_require_real('mt_xmax',mt_xmax)
993 call mt_require_real('mt_zmin',mt_zmin)
994 call mt_require_real('mt_zmax',mt_zmax)
995 call mt_require_real('mt_y0',mt_y0)
996 call mt_require_positive_int('mt_nx',mt_nx)
997 call mt_require_positive_int('mt_nz',mt_nz)
998 call mt_require_ordered('mt_xmin','mt_xmax',mt_xmin,mt_xmax)
999 call mt_require_ordered('mt_zmin','mt_zmax',mt_zmin,mt_zmax)
1000 if (mt_b_min>0.d0) then
1001 call mt_axis_plane_products_csv_axis(mt_xmin,mt_xmax,mt_nx, &
1002 mt_zmin,mt_zmax,mt_nz,mt_y0,1,3,2,mt_dl,mt_max_steps, &
1003 trim(length_csv),trim(twist_csv),trim(q_csv), &
1004 trim(qperp_csv),'mt_axis_plane_products_csv_xz','ix,iz', &
1005 'i,j',b_min=mt_b_min)
1006 else
1007 call mt_axis_plane_products_csv_axis(mt_xmin,mt_xmax,mt_nx, &
1008 mt_zmin,mt_zmax,mt_nz,mt_y0,1,3,2,mt_dl,mt_max_steps, &
1009 trim(length_csv),trim(twist_csv),trim(q_csv), &
1010 trim(qperp_csv),'mt_axis_plane_products_csv_xz','ix,iz', &
1011 'i,j')
1012 endif
1013 case ('yz')
1014 call mt_require_real('mt_ymin',mt_ymin)
1015 call mt_require_real('mt_ymax',mt_ymax)
1016 call mt_require_real('mt_zmin',mt_zmin)
1017 call mt_require_real('mt_zmax',mt_zmax)
1018 call mt_require_real('mt_x0',mt_x0)
1019 call mt_require_positive_int('mt_ny',mt_ny)
1020 call mt_require_positive_int('mt_nz',mt_nz)
1021 call mt_require_ordered('mt_ymin','mt_ymax',mt_ymin,mt_ymax)
1022 call mt_require_ordered('mt_zmin','mt_zmax',mt_zmin,mt_zmax)
1023 if (mt_b_min>0.d0) then
1024 call mt_axis_plane_products_csv_axis(mt_ymin,mt_ymax,mt_ny, &
1025 mt_zmin,mt_zmax,mt_nz,mt_x0,2,3,1,mt_dl,mt_max_steps, &
1026 trim(length_csv),trim(twist_csv),trim(q_csv), &
1027 trim(qperp_csv),'mt_axis_plane_products_csv_yz','iy,iz', &
1028 'i,j',b_min=mt_b_min)
1029 else
1030 call mt_axis_plane_products_csv_axis(mt_ymin,mt_ymax,mt_ny, &
1031 mt_zmin,mt_zmax,mt_nz,mt_x0,2,3,1,mt_dl,mt_max_steps, &
1032 trim(length_csv),trim(twist_csv),trim(q_csv), &
1033 trim(qperp_csv),'mt_axis_plane_products_csv_yz','iy,iz', &
1034 'i,j')
1035 endif
1036 case default
1037 call mpistop('mt_run_topology_task: axis_plane_csv requires mt_plane=xy, xz, or yz')
1038 end select
1039
1040 write(*,'(a)') 'mt_run_topology_task: wrote axis-plane CSV length '// &
1041 trim(length_csv)
1042 if (mt_compute_twist) write(*,'(a)') &
1043 'mt_run_topology_task: wrote axis-plane CSV twist '//trim(twist_csv)
1044 if (mt_compute_q) write(*,'(a)') &
1045 'mt_run_topology_task: wrote axis-plane CSV Q '//trim(q_csv)
1046 if (mt_compute_qperp) write(*,'(a)') &
1047 'mt_run_topology_task: wrote axis-plane CSV Qperp '//trim(qperp_csv)
1048 end subroutine mt_run_axis_plane_csv_task
1049
1050 subroutine mt_run_volume_vti_task()
1051 character(len=mt_task_name_len) :: output_file
1052
1053 call mt_resolve_output_file('volume_vti','.vti','_volume.vti', &
1054 output_file)
1055 call mt_require_real('mt_xmin',mt_xmin)
1056 call mt_require_real('mt_xmax',mt_xmax)
1057 call mt_require_real('mt_ymin',mt_ymin)
1058 call mt_require_real('mt_ymax',mt_ymax)
1059 call mt_require_real('mt_zmin',mt_zmin)
1060 call mt_require_real('mt_zmax',mt_zmax)
1061 call mt_require_positive_int('mt_nx',mt_nx)
1062 call mt_require_positive_int('mt_ny',mt_ny)
1063 call mt_require_positive_int('mt_nz',mt_nz)
1064 call mt_require_ordered('mt_xmin','mt_xmax',mt_xmin,mt_xmax)
1065 call mt_require_ordered('mt_ymin','mt_ymax',mt_ymin,mt_ymax)
1066 call mt_require_ordered('mt_zmin','mt_zmax',mt_zmin,mt_zmax)
1067 write(*,'(a)') 'mt_run_topology_task: writing volume VTI '//trim(output_file)
1068 if (mt_b_min>0.d0) then
1069 if (mt_chunk_nz>0) then
1070 call mt_fieldline_products_volume_vti(mt_xmin,mt_xmax,mt_nx, &
1071 mt_ymin,mt_ymax,mt_ny,mt_zmin,mt_zmax,mt_nz, &
1072 mt_dl,mt_max_steps,trim(output_file),b_min=mt_b_min, &
1073 compute_twist=mt_compute_twist, &
1074 compute_length=mt_compute_length, &
1075 compute_q=mt_compute_q,compute_qperp=mt_compute_qperp, &
1076 chunk_nz=mt_chunk_nz)
1077 else
1078 call mt_fieldline_products_volume_vti(mt_xmin,mt_xmax,mt_nx, &
1079 mt_ymin,mt_ymax,mt_ny,mt_zmin,mt_zmax,mt_nz, &
1080 mt_dl,mt_max_steps,trim(output_file),b_min=mt_b_min, &
1081 compute_twist=mt_compute_twist, &
1082 compute_length=mt_compute_length, &
1083 compute_q=mt_compute_q,compute_qperp=mt_compute_qperp)
1084 endif
1085 else
1086 if (mt_chunk_nz>0) then
1087 call mt_fieldline_products_volume_vti(mt_xmin,mt_xmax,mt_nx, &
1088 mt_ymin,mt_ymax,mt_ny,mt_zmin,mt_zmax,mt_nz, &
1089 mt_dl,mt_max_steps,trim(output_file), &
1090 compute_twist=mt_compute_twist, &
1091 compute_length=mt_compute_length, &
1092 compute_q=mt_compute_q,compute_qperp=mt_compute_qperp, &
1093 chunk_nz=mt_chunk_nz)
1094 else
1095 call mt_fieldline_products_volume_vti(mt_xmin,mt_xmax,mt_nx, &
1096 mt_ymin,mt_ymax,mt_ny,mt_zmin,mt_zmax,mt_nz, &
1097 mt_dl,mt_max_steps,trim(output_file), &
1098 compute_twist=mt_compute_twist, &
1099 compute_length=mt_compute_length, &
1100 compute_q=mt_compute_q,compute_qperp=mt_compute_qperp)
1101 endif
1102 endif
1103 end subroutine mt_run_volume_vti_task
1104
1105 subroutine mt_run_arbitrary_plane_products_task()
1106 character(len=mt_task_name_len) :: vtu_file,csv_file
1107
1108 call mt_resolve_output_file('arbitrary_plane_products','.vtu', &
1109 '_arbitrary_plane_products.vtu',vtu_file)
1110 csv_file=''
1111 if (mt_write_csv) then
1112 call mt_resolve_prefix_file('_arbitrary_plane_products.csv',csv_file, &
1113 'arbitrary_plane_products CSV requires mt_output_prefix')
1114 endif
1115 call mt_require_real('mt_origin(1)',mt_origin(1))
1116 call mt_require_real('mt_origin(2)',mt_origin(2))
1117 call mt_require_real('mt_origin(3)',mt_origin(3))
1118 call mt_require_real('mt_e1(1)',mt_e1(1))
1119 call mt_require_real('mt_e1(2)',mt_e1(2))
1120 call mt_require_real('mt_e1(3)',mt_e1(3))
1121 call mt_require_real('mt_e2(1)',mt_e2(1))
1122 call mt_require_real('mt_e2(2)',mt_e2(2))
1123 call mt_require_real('mt_e2(3)',mt_e2(3))
1124 call mt_require_real('mt_s1min',mt_s1min)
1125 call mt_require_real('mt_s1max',mt_s1max)
1126 call mt_require_real('mt_s2min',mt_s2min)
1127 call mt_require_real('mt_s2max',mt_s2max)
1128 call mt_require_positive_int('mt_n1',mt_n1)
1129 call mt_require_positive_int('mt_n2',mt_n2)
1130 call mt_require_ordered('mt_s1min','mt_s1max',mt_s1min,mt_s1max)
1131 call mt_require_ordered('mt_s2min','mt_s2max',mt_s2min,mt_s2max)
1132
1133 write(*,'(a)') 'mt_run_topology_task: writing arbitrary-plane VTU '// &
1134 trim(vtu_file)
1135 if (mt_write_csv) then
1136 write(*,'(a)') 'mt_run_topology_task: writing arbitrary-plane CSV '// &
1137 trim(csv_file)
1138 endif
1139
1140 if (mt_b_min>0.d0) then
1141 call mt_fieldline_products_plane_arbitrary(mt_origin(1:ndim), &
1142 mt_e1(1:ndim),mt_e2(1:ndim),mt_s1min,mt_s1max,mt_n1, &
1143 mt_s2min,mt_s2max,mt_n2,mt_dl,mt_max_steps,trim(csv_file), &
1144 b_min=mt_b_min,compute_length=mt_compute_length, &
1145 compute_twist=mt_compute_twist, &
1146 compute_q=mt_compute_q,compute_qperp=mt_compute_qperp, &
1147 vtu_file=trim(vtu_file),write_csv=mt_write_csv)
1148 else
1149 call mt_fieldline_products_plane_arbitrary(mt_origin(1:ndim), &
1150 mt_e1(1:ndim),mt_e2(1:ndim),mt_s1min,mt_s1max,mt_n1, &
1151 mt_s2min,mt_s2max,mt_n2,mt_dl,mt_max_steps,trim(csv_file), &
1152 compute_length=mt_compute_length, &
1153 compute_twist=mt_compute_twist, &
1154 compute_q=mt_compute_q,compute_qperp=mt_compute_qperp, &
1155 vtu_file=trim(vtu_file),write_csv=mt_write_csv)
1156 endif
1157 end subroutine mt_run_arbitrary_plane_products_task
1158
1159 subroutine mt_run_seed_products_task()
1160 character(len=mt_task_name_len) :: csv_file,vtu_file,diag_file
1161 character(len=mt_task_name_len) :: rk2_diag_file
1162 double precision, allocatable :: seeds(:,:)
1163 integer :: nseed
1164
1165 if (len_trim(mt_output_prefix)==0) then
1166 call mpistop('seed_products requires mt_output_prefix')
1167 endif
1168 if (len_trim(mt_output_file)>0) then
1169 write(*,'(a)') 'mt_run_topology_task: seed_products ignores mt_output_file'
1170 write(*,'(a)') 'mt_run_topology_task: seed_products uses mt_output_prefix for CSV and VTU'
1171 endif
1172 if (len_trim(mt_seed_file)==0) then
1173 call mpistop('seed_products requires mt_seed_file')
1174 endif
1175
1176 csv_file=''
1177 if (mt_write_csv) then
1178 call mt_resolve_prefix_file('_seed_products.csv',csv_file, &
1179 'seed_products CSV requires mt_output_prefix')
1180 endif
1181 call mt_resolve_prefix_file('_seed_products.vtu',vtu_file, &
1182 'seed_products VTU requires mt_output_prefix')
1183 if (mt_rk45_tangent_diagnostic) then
1184 call mt_resolve_prefix_file('_rk45_tangent_diag.csv',diag_file, &
1185 'seed_products RK45 tangent diagnostic requires mt_output_prefix')
1186 endif
1187 if (mt_rk2_fusion_diagnostic) then
1188 call mt_resolve_prefix_file('_rk2_fusion_diag.csv',rk2_diag_file, &
1189 'seed_products RK2 fusion diagnostic requires mt_output_prefix')
1190 endif
1191 call mt_read_seed_file(trim(mt_seed_file),seeds,nseed)
1192
1193 if (mt_write_csv) write(*,'(a)') &
1194 'mt_run_topology_task: writing seed-products CSV '//trim(csv_file)
1195 write(*,'(a)') 'mt_run_topology_task: writing seed-products VTU '// &
1196 trim(vtu_file)
1197
1198 if (mt_b_min>0.d0) then
1199 call mt_fieldline_products_seeds(seeds,nseed,mt_dl,mt_max_steps, &
1200 trim(csv_file),b_min=mt_b_min,compute_length=mt_compute_length, &
1201 compute_twist=mt_compute_twist, &
1202 compute_q=mt_compute_q,compute_qperp=mt_compute_qperp, &
1203 vtu_file=trim(vtu_file))
1204 if (mt_rk45_tangent_diagnostic) then
1205 write(*,'(a)') 'mt_run_topology_task: writing RK45 tangent '// &
1206 'diagnostic CSV '//trim(diag_file)
1207 call mt_rk45_tangent_diagnostic_seeds(seeds,nseed,mt_dl, &
1208 mt_max_steps,trim(diag_file),b_min=mt_b_min)
1209 endif
1210 if (mt_rk2_fusion_diagnostic) then
1211 write(*,'(a)') 'mt_run_topology_task: writing RK2 fusion '// &
1212 'diagnostic CSV '//trim(rk2_diag_file)
1213 call mt_rk2_fusion_diagnostic_seeds(seeds,nseed,mt_dl, &
1214 mt_max_steps,trim(rk2_diag_file),b_min=mt_b_min)
1215 endif
1216 else
1217 call mt_fieldline_products_seeds(seeds,nseed,mt_dl,mt_max_steps, &
1218 trim(csv_file),compute_length=mt_compute_length, &
1219 compute_twist=mt_compute_twist, &
1220 compute_q=mt_compute_q,compute_qperp=mt_compute_qperp, &
1221 vtu_file=trim(vtu_file))
1222 if (mt_rk45_tangent_diagnostic) then
1223 write(*,'(a)') 'mt_run_topology_task: writing RK45 tangent '// &
1224 'diagnostic CSV '//trim(diag_file)
1225 call mt_rk45_tangent_diagnostic_seeds(seeds,nseed,mt_dl, &
1226 mt_max_steps,trim(diag_file))
1227 endif
1228 if (mt_rk2_fusion_diagnostic) then
1229 write(*,'(a)') 'mt_run_topology_task: writing RK2 fusion '// &
1230 'diagnostic CSV '//trim(rk2_diag_file)
1231 call mt_rk2_fusion_diagnostic_seeds(seeds,nseed,mt_dl, &
1232 mt_max_steps,trim(rk2_diag_file))
1233 endif
1234 endif
1235
1236 deallocate(seeds)
1237 end subroutine mt_run_seed_products_task
1238
1239 subroutine mt_run_spherical_surface_products_task()
1240 character(len=mt_task_name_len) :: surface,csv_file,vtu_file,suffix
1241 double precision :: seed_coord,s1_min,s1_max,s2_min,s2_max
1242 double precision :: seed_theta0,seed_phi0,seed_alpha
1243
1244 surface=mt_lowercase(trim(mt_seed_surface))
1245 if (len_trim(surface)==0) surface='rmin'
1246 select case (trim(surface))
1247 case ('rmin')
1248 seed_coord=xprobmin1
1249 case ('rconst','r_const')
1250 surface='rconst'
1251 call mt_require_real('mt_seed_coord',mt_seed_coord)
1252 seed_coord=mt_seed_coord
1253 if (seed_coord<xprobmin1 .or. seed_coord>xprobmax1) then
1254 call mpistop('spherical_surface_products requires rconst '// &
1255 'mt_seed_coord inside domain')
1256 endif
1257 {^ifthreed
1258 case ('theta_const','thetaconst')
1259 surface='theta_const'
1260 call mt_require_real('mt_seed_coord',mt_seed_coord)
1261 seed_coord=mt_seed_coord
1262 if (seed_coord<xprobmin2 .or. seed_coord>xprobmax2) then
1263 call mpistop('spherical_surface_products requires theta_const '// &
1264 'mt_seed_coord inside domain')
1265 endif
1266 case ('phi_const','phiconst')
1267 surface='phi_const'
1268 call mt_require_real('mt_seed_coord',mt_seed_coord)
1269 seed_coord=mt_seed_coord
1270 if (seed_coord<xprobmin3 .or. seed_coord>xprobmax3) then
1271 call mpistop('spherical_surface_products requires phi_const '// &
1272 'mt_seed_coord inside domain')
1273 endif
1274 case ('radial_plane','radialplane')
1275 surface='radial_plane'
1276 seed_coord=0.d0
1277 call mt_require_real('mt_seed_theta0',mt_seed_theta0)
1278 call mt_require_real('mt_seed_phi0',mt_seed_phi0)
1279 call mt_require_real('mt_seed_alpha',mt_seed_alpha)
1280 if (mt_seed_theta0<xprobmin2 .or. mt_seed_theta0>xprobmax2) then
1281 call mpistop('spherical_surface_products requires radial_plane '// &
1282 'mt_seed_theta0 inside domain')
1283 endif
1284 if (mt_seed_phi0<xprobmin3 .or. mt_seed_phi0>xprobmax3) then
1285 call mpistop('spherical_surface_products requires radial_plane '// &
1286 'mt_seed_phi0 inside domain')
1287 endif
1288 if (abs(dsin(mt_seed_theta0))<=1.d-12) then
1289 call mpistop('spherical_surface_products radial_plane requires '// &
1290 'mt_seed_theta0 away from the polar singularity')
1291 endif
1292 }
1293 case default
1294 call mpistop('spherical_surface_products supports '// &
1295 'mt_seed_surface=rmin, rconst, theta_const, phi_const, or radial_plane')
1296 end select
1297 call mt_require_positive_int('mt_n1',mt_n1)
1298 call mt_require_positive_int('mt_n2',mt_n2)
1299 s1_min=0.d0
1300 s1_max=0.d0
1301 s2_min=0.d0
1302 s2_max=0.d0
1303 {^ifthreed
1304 select case (trim(surface))
1305 case ('rmin','rconst')
1306 s1_min=xprobmin2
1307 s1_max=xprobmax2
1308 s2_min=xprobmin3
1309 s2_max=xprobmax3
1310 case ('theta_const')
1311 s1_min=xprobmin1
1312 s1_max=xprobmax1
1313 s2_min=xprobmin3
1314 s2_max=xprobmax3
1315 case ('phi_const')
1316 s1_min=xprobmin1
1317 s1_max=xprobmax1
1318 s2_min=xprobmin2
1319 s2_max=xprobmax2
1320 case ('radial_plane')
1321 s1_min=xprobmin1
1322 s1_max=xprobmax1
1323 s2_min=-0.5d0*min(xprobmax2-xprobmin2,xprobmax3-xprobmin3)
1324 s2_max= 0.5d0*min(xprobmax2-xprobmin2,xprobmax3-xprobmin3)
1325 end select
1326 }
1327 if (mt_is_set_real(mt_s1min)) s1_min=mt_s1min
1328 if (mt_is_set_real(mt_s1max)) s1_max=mt_s1max
1329 if (mt_is_set_real(mt_s2min)) s2_min=mt_s2min
1330 if (mt_is_set_real(mt_s2max)) s2_max=mt_s2max
1331 call mt_require_ordered('mt_s1min','mt_s1max',s1_min,s1_max)
1332 call mt_require_ordered('mt_s2min','mt_s2max',s2_min,s2_max)
1333
1334 csv_file=''
1335 if (mt_write_csv) then
1336 if (trim(surface)=='rmin') then
1337 suffix='_spherical_rmin_products.csv'
1338 else if (trim(surface)=='radial_plane') then
1339 suffix='_spherical_radial_plane_products.csv'
1340 else
1341 suffix='_spherical_'//trim(surface)//'_products.csv'
1342 endif
1343 call mt_resolve_prefix_file(trim(suffix),csv_file, &
1344 'spherical_surface_products CSV requires mt_output_prefix')
1345 endif
1346 if (trim(surface)=='rmin') then
1347 suffix='_spherical_rmin_products.vtu'
1348 else if (trim(surface)=='radial_plane') then
1349 suffix='_spherical_radial_plane_products.vtu'
1350 else
1351 suffix='_spherical_'//trim(surface)//'_products.vtu'
1352 endif
1353 call mt_resolve_output_file('spherical_surface_products','.vtu', &
1354 trim(suffix),vtu_file)
1355
1356 if (mt_write_csv) then
1357 write(*,'(a)') 'mt_run_topology_task: writing spherical '// &
1358 trim(surface)//' CSV '//trim(csv_file)
1359 endif
1360 write(*,'(a)') 'mt_run_topology_task: writing spherical '// &
1361 trim(surface)//' VTU '//trim(vtu_file)
1362
1363 if (mt_profile_spherical) then
1364 call trace_spherical_profile_reset()
1365 call trace_spherical_profile_set(.true.)
1366 endif
1367
1368 seed_theta0=mt_seed_theta0
1369 seed_phi0=mt_seed_phi0
1370 seed_alpha=mt_seed_alpha
1371 if (mt_b_min>0.d0) then
1372 call mt_fieldline_products_spherical_surface(trim(surface),seed_coord, &
1373 s1_min,s1_max,mt_n1,s2_min,s2_max,mt_n2,mt_dl,mt_max_steps, &
1374 trim(csv_file),trim(vtu_file),trim(mt_seed_layout), &
1375 seed_theta0,seed_phi0,seed_alpha, &
1376 compute_twist=mt_compute_twist,compute_q=mt_compute_q, &
1377 compute_qperp=mt_compute_qperp,b_min=mt_b_min)
1378 else
1379 call mt_fieldline_products_spherical_surface(trim(surface),seed_coord, &
1380 s1_min,s1_max,mt_n1,s2_min,s2_max,mt_n2,mt_dl,mt_max_steps, &
1381 trim(csv_file),trim(vtu_file),trim(mt_seed_layout), &
1382 seed_theta0,seed_phi0,seed_alpha, &
1383 compute_twist=mt_compute_twist,compute_q=mt_compute_q, &
1384 compute_qperp=mt_compute_qperp)
1385 endif
1386 if (mt_profile_spherical) then
1387 call trace_spherical_profile_report('spherical_surface_products '// &
1388 trim(surface))
1389 call trace_spherical_profile_set(.false.)
1390 endif
1391 end subroutine mt_run_spherical_surface_products_task
1392
1393 subroutine mt_run_spherical_cloud_products_task()
1394 character(len=mt_task_name_len) :: vtu_file
1395 double precision :: s1_min,s1_max,s2_min,s2_max,s3_min,s3_max
1396
1397 if (mt_write_csv) then
1398 write(*,'(a)') 'mt_run_topology_task: spherical_cloud_products '// &
1399 'does not write CSV; use seed_products for selected-point diagnostics'
1400 endif
1401 call mt_require_positive_int('mt_n1',mt_n1)
1402 call mt_require_positive_int('mt_n2',mt_n2)
1403 call mt_require_positive_int('mt_n3',mt_n3)
1404 s1_min=xprobmin1
1405 s1_max=xprobmax1
1406 s2_min=0.d0
1407 s2_max=0.d0
1408 s3_min=0.d0
1409 s3_max=0.d0
1410 {^ifthreed
1411 s2_min=xprobmin2
1412 s2_max=xprobmax2
1413 s3_min=xprobmin3
1414 s3_max=xprobmax3
1415 }
1416 if (mt_is_set_real(mt_s1min)) s1_min=mt_s1min
1417 if (mt_is_set_real(mt_s1max)) s1_max=mt_s1max
1418 if (mt_is_set_real(mt_s2min)) s2_min=mt_s2min
1419 if (mt_is_set_real(mt_s2max)) s2_max=mt_s2max
1420 if (mt_is_set_real(mt_s3min)) s3_min=mt_s3min
1421 if (mt_is_set_real(mt_s3max)) s3_max=mt_s3max
1422 call mt_require_ordered('mt_s1min','mt_s1max',s1_min,s1_max)
1423 call mt_require_ordered('mt_s2min','mt_s2max',s2_min,s2_max)
1424 call mt_require_ordered('mt_s3min','mt_s3max',s3_min,s3_max)
1425
1426 call mt_resolve_output_file('spherical_cloud_products','.vtu', &
1427 '_spherical_cloud_products.vtu',vtu_file)
1428
1429 write(*,'(a)') 'mt_run_topology_task: writing spherical cloud VTU '// &
1430 trim(vtu_file)
1431
1432 if (mt_profile_spherical) then
1433 call trace_spherical_profile_reset()
1434 call trace_spherical_profile_set(.true.)
1435 endif
1436
1437 if (mt_b_min>0.d0) then
1438 call mt_fieldline_products_spherical_cloud(s1_min,s1_max,mt_n1, &
1439 s2_min,s2_max,mt_n2,s3_min,s3_max,mt_n3,mt_dl,mt_max_steps, &
1440 trim(vtu_file),trim(mt_seed_layout), &
1441 compute_twist=mt_compute_twist,compute_q=mt_compute_q, &
1442 compute_qperp=mt_compute_qperp,b_min=mt_b_min)
1443 else
1444 call mt_fieldline_products_spherical_cloud(s1_min,s1_max,mt_n1, &
1445 s2_min,s2_max,mt_n2,s3_min,s3_max,mt_n3,mt_dl,mt_max_steps, &
1446 trim(vtu_file),trim(mt_seed_layout), &
1447 compute_twist=mt_compute_twist,compute_q=mt_compute_q, &
1448 compute_qperp=mt_compute_qperp)
1449 endif
1450 if (mt_profile_spherical) then
1451 call trace_spherical_profile_report('spherical_cloud_products')
1452 call trace_spherical_profile_set(.false.)
1453 endif
1454 end subroutine mt_run_spherical_cloud_products_task
1455
1456 subroutine mt_resolve_output_file(mode,extension,suffix,output_file)
1457 character(len=*), intent(in) :: mode,extension,suffix
1458 character(len=*), intent(out) :: output_file
1459 integer :: required_len
1460
1461 output_file=''
1462 if (len_trim(mt_output_file)>0) then
1463 output_file=trim(mt_output_file)
1464 if (len_trim(mt_output_prefix)>0) then
1465 write(*,'(a)') 'mt_run_topology_task: mt_output_file takes precedence over mt_output_prefix'
1466 endif
1467 call mt_warn_extension(output_file,extension,mode)
1468 else
1469 required_len=len_trim(mt_output_prefix)+len_trim(suffix)
1470 if (required_len>len(output_file)) then
1471 call mpistop('mt_run_topology_task output filename exceeds internal length')
1472 endif
1473 output_file=trim(mt_output_prefix)//trim(suffix)
1474 endif
1475 end subroutine mt_resolve_output_file
1476
1477 subroutine mt_resolve_prefix_file(suffix,output_file,missing_message)
1478 character(len=*), intent(in) :: suffix,missing_message
1479 character(len=*), intent(out) :: output_file
1480 integer :: required_len
1481
1482 if (len_trim(mt_output_prefix)==0) then
1483 call mpistop(trim(missing_message))
1484 endif
1485 required_len=len_trim(mt_output_prefix)+len_trim(suffix)
1486 if (required_len>len(output_file)) then
1487 call mpistop('mt_run_topology_task output filename exceeds internal length')
1488 endif
1489 output_file=trim(mt_output_prefix)//trim(suffix)
1490 end subroutine mt_resolve_prefix_file
1491
1492 logical function mt_is_set_real(value) result(is_set)
1493 double precision, intent(in) :: value
1494
1495 is_set=(value/=mt_unset_real)
1496 end function mt_is_set_real
1497
1498 subroutine mt_require_real(name,value)
1499 character(len=*), intent(in) :: name
1500 double precision, intent(in) :: value
1501
1502 if (.not.mt_is_set_real(value)) then
1503 call mpistop('mt_run_topology_task requires '//trim(name))
1504 endif
1505 end subroutine mt_require_real
1506
1507 subroutine mt_require_positive_int(name,value)
1508 character(len=*), intent(in) :: name
1509 integer, intent(in) :: value
1510
1511 if (value<=0) then
1512 call mpistop('mt_run_topology_task requires '//trim(name)//' > 0')
1513 endif
1514 end subroutine mt_require_positive_int
1515
1516 subroutine mt_require_ordered(name_min,name_max,value_min,value_max)
1517 character(len=*), intent(in) :: name_min,name_max
1518 double precision, intent(in) :: value_min,value_max
1519
1520 if (value_max<value_min) then
1521 call mpistop('mt_run_topology_task requires ordered '// &
1522 trim(name_min)//'/'//trim(name_max))
1523 endif
1524 end subroutine mt_require_ordered
1525
1526 subroutine mt_require_requested_science(do_length,do_twist,do_q,do_qperp, &
1527 caller)
1528 logical, intent(in) :: do_length,do_twist,do_q,do_qperp
1529 character(len=*), intent(in) :: caller
1530
1531 if (.not.(do_length .or. do_twist .or. do_q .or. do_qperp)) then
1532 call mpistop(trim(caller)//' requires at least one requested science array')
1533 endif
1534 end subroutine mt_require_requested_science
1535
1536 subroutine mt_read_seed_file(filename,seeds,nseed)
1537 character(len=*), intent(in) :: filename
1538 double precision, allocatable, intent(out) :: seeds(:,:)
1539 integer, intent(out) :: nseed
1540
1541 character(len=1024) :: line
1542 double precision :: xyz(3)
1543 integer :: io,ios,line_no,iseed
1544
1545 nseed=0
1546 open(newunit=io,file=trim(filename),status='old',action='read', &
1547 form='formatted',iostat=ios)
1548 if (ios/=0) then
1549 call mpistop('mt_read_seed_file could not open '//trim(filename))
1550 endif
1551 line_no=0
1552 do
1553 read(io,'(a)',iostat=ios) line
1554 if (ios/=0) exit
1555 line_no=line_no+1
1556 if (.not.mt_seed_line_is_data(line)) cycle
1557 call mt_validate_seed_line(filename,line,line_no)
1558 nseed=nseed+1
1559 enddo
1560 close(io)
1561 if (nseed<=0) then
1562 call mpistop('mt_read_seed_file found no seeds in '//trim(filename))
1563 endif
1564
1565 allocate(seeds(nseed,ndim))
1566 seeds=0.d0
1567 open(newunit=io,file=trim(filename),status='old',action='read', &
1568 form='formatted',iostat=ios)
1569 if (ios/=0) then
1570 call mpistop('mt_read_seed_file could not reopen '//trim(filename))
1571 endif
1572 line_no=0
1573 iseed=0
1574 do
1575 read(io,'(a)',iostat=ios) line
1576 if (ios/=0) exit
1577 line_no=line_no+1
1578 if (.not.mt_seed_line_is_data(line)) cycle
1579 iseed=iseed+1
1580 read(line,*,iostat=ios) xyz
1581 if (ios/=0) then
1582 call mt_fail_seed_line(filename,line_no)
1583 endif
1584 seeds(iseed,1:ndim)=xyz(1:ndim)
1585 enddo
1586 close(io)
1587 end subroutine mt_read_seed_file
1588
1589 logical function mt_seed_line_is_data(line) result(is_data)
1590 character(len=*), intent(in) :: line
1591 character(len=len(line)) :: trimmed
1592
1593 trimmed=adjustl(line)
1594 is_data=len_trim(trimmed)>0
1595 if (is_data) is_data=trimmed(1:1)/='#'
1596 end function mt_seed_line_is_data
1597
1598 subroutine mt_validate_seed_line(filename,line,line_no)
1599 character(len=*), intent(in) :: filename,line
1600 integer, intent(in) :: line_no
1601
1602 double precision :: x,y,z
1603 integer :: ios
1604
1605 if (index(line,',')>0) then
1606 call mt_fail_seed_line(filename,line_no)
1607 endif
1608 if (mt_count_tokens(line)/=3) then
1609 call mt_fail_seed_line(filename,line_no)
1610 endif
1611 read(line,*,iostat=ios) x,y,z
1612 if (ios/=0) then
1613 call mt_fail_seed_line(filename,line_no)
1614 endif
1615 end subroutine mt_validate_seed_line
1616
1617 integer function mt_count_tokens(line) result(ntoken)
1618 character(len=*), intent(in) :: line
1619 integer :: i
1620 logical :: in_token
1621
1622 ntoken=0
1623 in_token=.false.
1624 do i=1,len_trim(line)
1625 if (line(i:i)==' ' .or. line(i:i)==achar(9)) then
1626 in_token=.false.
1627 else
1628 if (.not.in_token) then
1629 ntoken=ntoken+1
1630 in_token=.true.
1631 endif
1632 endif
1633 enddo
1634 end function mt_count_tokens
1635
1636 subroutine mt_fail_seed_line(filename,line_no)
1637 character(len=*), intent(in) :: filename
1638 integer, intent(in) :: line_no
1639
1640 call mpistop('mt_read_seed_file malformed line '// &
1641 trim(mt_int_to_string(line_no))//' in '//trim(filename))
1642 end subroutine mt_fail_seed_line
1643
1644 function mt_int_to_string(value) result(text)
1645 integer, intent(in) :: value
1646 character(len=32) :: text
1647
1648 write(text,'(i0)') value
1649 end function mt_int_to_string
1650
1651 subroutine mt_warn_extension(filename,extension,mode)
1652 character(len=*), intent(in) :: filename,extension,mode
1653
1654 if (.not.mt_has_extension(filename,extension)) then
1655 write(*,'(a)') 'mt_run_topology_task warning: '//trim(mode)// &
1656 ' output file does not end in '//trim(extension)
1657 endif
1658 end subroutine mt_warn_extension
1659
1660 logical function mt_has_extension(filename,extension) result(has_ext)
1661 character(len=*), intent(in) :: filename,extension
1662 character(len=mt_task_name_len) :: fname,ext
1663 integer :: lf,le
1664
1665 fname=mt_lowercase(trim(filename))
1666 ext=mt_lowercase(trim(extension))
1667 lf=len_trim(fname)
1668 le=len_trim(ext)
1669 has_ext=.false.
1670 if (lf>=le) has_ext=(fname(lf-le+1:lf)==ext(1:le))
1671 end function mt_has_extension
1672
1673 function mt_lowercase(input) result(output)
1674 character(len=*), intent(in) :: input
1675 character(len=len(input)) :: output
1676 integer :: i,code
1677
1678 output=input
1679 do i=1,len(input)
1680 code=iachar(output(i:i))
1681 if (code>=iachar('A') .and. code<=iachar('Z')) then
1682 output(i:i)=achar(code+iachar('a')-iachar('A'))
1683 endif
1684 enddo
1685 end function mt_lowercase
1686
1687 logical function mt_vtk_detail_is_full() result(is_full)
1688 is_full=(mt_lowercase(trim(mt_vtk_detail))=='full')
1689 end function mt_vtk_detail_is_full
1690
1691 double precision function mt_visual_float(value) result(out_value)
1692 double precision, intent(in) :: value
1693
1694 if (ieee_is_finite(value)) then
1695 out_value=value
1696 else
1697 out_value=0.d0
1698 endif
1699 end function mt_visual_float
1700
1701 double precision function mt_visual_valid_float(value,is_valid) &
1702 result(out_value)
1703 double precision, intent(in) :: value
1704 logical, intent(in) :: is_valid
1705
1706 if (is_valid .and. ieee_is_finite(value)) then
1707 out_value=value
1708 else
1709 out_value=0.d0
1710 endif
1711 end function mt_visual_valid_float
1712
1713 double precision function mt_vc(vec,icomp) result(value)
1714 ! Return a physical coordinate component without creating fixed
1715 ! out-of-bounds references in 1D/2D source expansions.
1716 double precision, intent(in) :: vec(ndim)
1717 integer, intent(in) :: icomp
1718
1719 if (icomp>=1 .and. icomp<=ndim) then
1720 value=vec(icomp)
1721 else
1722 value=0.d0
1723 endif
1724 end function mt_vc
1725
1726 subroutine mt_length_single(seed,dL,max_steps,csv_file,b_min)
1727 ! Trace one magnetic field line and write its summary to a CSV file.
1728 double precision, intent(in) :: seed(ndim),dl
1729 integer, intent(in) :: max_steps
1730 character(len=*), intent(in) :: csv_file
1731 double precision, intent(in), optional :: b_min
1732
1733 type(trace_length_result) :: result
1734 double precision :: seed_xyz(3)
1735 integer :: csv_unit,io_status
1736
1737 if (npe/=1) then
1738 call mpistop('mt_length_single currently requires npe=1')
1739 endif
1740
1741 if (present(b_min)) then
1742 call trace_field_length_single(seed,dl,max_steps,result,b_min)
1743 else
1744 call trace_field_length_single(seed,dl,max_steps,result)
1745 endif
1746
1747 seed_xyz=0.d0
1748 seed_xyz(1:ndim)=result%seed
1749
1750 open(newunit=csv_unit,file=trim(csv_file),status='replace', &
1751 action='write',form='formatted',iostat=io_status)
1752 if (io_status/=0) then
1753 call mpistop('mt_length_single could not open CSV file')
1754 endif
1755
1756 write(csv_unit,'(a)',iostat=io_status) &
1757 'seed_x,seed_y,seed_z,'// &
1758 'length_total,length_backward,length_forward,'// &
1759 'nstep_backward,nstep_forward,'// &
1760 'status_backward,status_forward'
1761 if (io_status/=0) then
1762 close(csv_unit)
1763 call mpistop('mt_length_single could not write CSV header')
1764 endif
1765
1766 write(csv_unit,'(es24.16,5(",",es24.16),4(",",i0))',iostat=io_status) &
1767 seed_xyz,result%total_length, &
1768 result%backward_length,result%forward_length, &
1769 result%backward_nstep,result%forward_nstep, &
1770 result%backward_status,result%forward_status
1771 if (io_status/=0) then
1772 close(csv_unit)
1773 call mpistop('mt_length_single could not write CSV data')
1774 endif
1775
1776 close(csv_unit)
1777 end subroutine mt_length_single
1778
1779 subroutine mt_length_seeds(seeds,nseed,dL,max_steps,csv_file,b_min)
1780 ! Trace multiple magnetic field lines and write one summary row per seed.
1781 integer, intent(in) :: nseed,max_steps
1782 double precision, intent(in) :: seeds(nseed,ndim),dl
1783 character(len=*), intent(in) :: csv_file
1784 double precision, intent(in), optional :: b_min
1785
1786 type(trace_length_result), allocatable :: results(:)
1787 double precision :: seed_xyz(3)
1788 integer :: csv_unit,io_status,iseed
1789
1790 if (npe/=1) then
1791 call mpistop('mt_length_seeds currently requires npe=1')
1792 endif
1793 if (nseed<0) then
1794 call mpistop('mt_length_seeds requires nseed>=0')
1795 endif
1796
1797 allocate(results(nseed))
1798 if (present(b_min)) then
1799 call trace_field_length_multi(seeds,nseed,dl,max_steps,results,b_min)
1800 else
1801 call trace_field_length_multi(seeds,nseed,dl,max_steps,results)
1802 endif
1803
1804 open(newunit=csv_unit,file=trim(csv_file),status='replace', &
1805 action='write',form='formatted',iostat=io_status)
1806 if (io_status/=0) then
1807 deallocate(results)
1808 call mpistop('mt_length_seeds could not open CSV file')
1809 endif
1810
1811 write(csv_unit,'(a)',iostat=io_status) &
1812 'seed_id,seed_x,seed_y,seed_z,'// &
1813 'length_total,length_backward,length_forward,'// &
1814 'nstep_backward,nstep_forward,'// &
1815 'status_backward,status_forward'
1816 if (io_status/=0) then
1817 close(csv_unit)
1818 deallocate(results)
1819 call mpistop('mt_length_seeds could not write CSV header')
1820 endif
1821
1822 do iseed=1,nseed
1823 seed_xyz=0.d0
1824 seed_xyz(1:ndim)=results(iseed)%seed
1825 write(csv_unit,'(i0,6(",",es24.16),4(",",i0))',iostat=io_status) &
1826 iseed,seed_xyz,results(iseed)%total_length, &
1827 results(iseed)%backward_length,results(iseed)%forward_length, &
1828 results(iseed)%backward_nstep,results(iseed)%forward_nstep, &
1829 results(iseed)%backward_status,results(iseed)%forward_status
1830 if (io_status/=0) then
1831 close(csv_unit)
1832 deallocate(results)
1833 call mpistop('mt_length_seeds could not write CSV data')
1834 endif
1835 enddo
1836
1837 close(csv_unit)
1838 deallocate(results)
1839 end subroutine mt_length_seeds
1840
1841 subroutine mt_fieldline_products_seeds(seeds,nseed,dL,max_steps,csv_file, &
1842 b_min,compute_length,compute_twist,compute_q,compute_qperp,vtu_file)
1843 ! Write selected per-field-line diagnostics for an arbitrary seed set.
1844 integer, intent(in) :: nseed,max_steps
1845 double precision, intent(in) :: seeds(nseed,ndim),dl
1846 character(len=*), intent(in) :: csv_file
1847 double precision, intent(in), optional :: b_min
1848 logical, intent(in), optional :: compute_length,compute_twist
1849 logical, intent(in), optional :: compute_q,compute_qperp
1850 character(len=*), intent(in), optional :: vtu_file
1851
1852 type(trace_length_result), allocatable :: length_results(:)
1853 type(trace_twist_result), allocatable :: twist_results(:)
1854 type(trace_qperp_result), allocatable :: q_results(:)
1855 type(trace_qperp_result), allocatable :: qperp_results(:)
1856 logical :: do_length,do_twist,do_q,do_qperp
1857 character(len=mt_task_name_len) :: integrator
1858
1859 do_length=.true.
1860 do_twist=.false.
1861 do_q=.false.
1862 do_qperp=.false.
1863 if (present(compute_length)) do_length=compute_length
1864 if (present(compute_twist)) do_twist=compute_twist
1865 if (present(compute_q)) do_q=compute_q
1866 if (present(compute_qperp)) do_qperp=compute_qperp
1867 integrator=mt_lowercase(trim(mt_trace_integrator))
1868
1869 if (npe/=1) then
1870 call mpistop('mt_fieldline_products_seeds currently requires npe=1')
1871 endif
1872 if (ndim/=3) then
1873 call mpistop('mt_fieldline_products_seeds requires 3D Cartesian or spherical geometry')
1874 endif
1875 {^ifthreed
1876 select case (geo_coordinate)
1877 case (geo_cartesian,geo_cartesian_stretched)
1878 case (geo_spherical)
1879 if (periodb(3)) then
1880 call mpistop('spherical seed_products does not yet support periodic phi')
1881 endif
1882 case default
1883 call mpistop('mt_fieldline_products_seeds requires Cartesian or spherical geometry')
1884 end select
1885 }
1886 if (do_qperp) then
1887 select case (trim(integrator))
1888 case ('rk2')
1889 ! RK2 Qperp is the mature tangent-transport path.
1890 case ('rk45_cartesian')
1891 {^ifthreed
1892 if (geo_coordinate==geo_spherical) then
1893 call mpistop('seed_products logQperp with spherical geometry '// &
1894 'requires mt_trace_integrator=rk45_spherical')
1895 endif
1896 }
1897 case ('rk45_spherical')
1898 {^ifthreed
1899 if (geo_coordinate/=geo_spherical) then
1900 call mpistop('seed_products logQperp with Cartesian geometry '// &
1901 'requires mt_trace_integrator=rk45_cartesian')
1902 endif
1903 }
1904 case default
1905 call mpistop('seed_products logQperp requires mt_trace_integrator='// &
1906 'rk2, rk45_cartesian, or rk45_spherical')
1907 end select
1908 endif
1909 if (do_q) then
1910 select case (trim(integrator))
1911 case ('rk2')
1912 ! RK2 standard logQ is the mature tangent-transport path.
1913 case ('rk45_cartesian')
1914 {^ifthreed
1915 if (geo_coordinate==geo_spherical) then
1916 call mpistop('seed_products logQ with spherical geometry '// &
1917 'requires mt_trace_integrator=rk45_spherical')
1918 endif
1919 }
1920 case ('rk45_spherical')
1921 {^ifthreed
1922 if (geo_coordinate/=geo_spherical) then
1923 call mpistop('seed_products logQ with Cartesian geometry '// &
1924 'requires mt_trace_integrator=rk45_cartesian')
1925 endif
1926 }
1927 case default
1928 call mpistop('seed_products logQ requires mt_trace_integrator='// &
1929 'rk2, rk45_cartesian, or rk45_spherical')
1930 end select
1931 endif
1932 if (nseed<0) then
1933 call mpistop('mt_fieldline_products_seeds requires nseed>=0')
1934 endif
1935 call mt_require_requested_science(do_length,do_twist,do_q,do_qperp, &
1936 'mt_fieldline_products_seeds')
1937
1938 allocate(length_results(nseed))
1939 if (do_twist) then
1940 allocate(twist_results(nseed))
1941 else
1942 allocate(twist_results(0))
1943 endif
1944 if (do_q) then
1945 allocate(q_results(nseed))
1946 else
1947 allocate(q_results(0))
1948 endif
1949 if (do_qperp) then
1950 allocate(qperp_results(nseed))
1951 else
1952 allocate(qperp_results(0))
1953 endif
1954
1955 if (present(b_min)) then
1956 call mt_trace_fieldline_products_seedset(seeds,nseed,dl,max_steps, &
1957 length_results,twist_results,q_results,qperp_results,do_twist, &
1958 do_q,do_qperp,b_min)
1959 else
1960 call mt_trace_fieldline_products_seedset(seeds,nseed,dl,max_steps, &
1961 length_results,twist_results,q_results,qperp_results,do_twist, &
1962 do_q,do_qperp)
1963 endif
1964
1965 if (len_trim(csv_file)>0) then
1966 call mt_write_fieldline_products_seeds_csv(length_results, &
1967 twist_results,q_results,qperp_results,nseed,csv_file,do_twist, &
1968 do_q,do_qperp)
1969 endif
1970 if (present(vtu_file)) then
1971 if (len_trim(vtu_file)>0) then
1972 call mt_write_fieldline_products_vtu_vertices(vtu_file, &
1973 length_results,twist_results,q_results,qperp_results,nseed, &
1974 do_length,do_twist,do_q,do_qperp,'mt_fieldline_products_seeds')
1975 endif
1976 endif
1977
1978 if (allocated(qperp_results)) deallocate(qperp_results)
1979 if (allocated(q_results)) deallocate(q_results)
1980 if (allocated(twist_results)) deallocate(twist_results)
1981 deallocate(length_results)
1982 end subroutine mt_fieldline_products_seeds
1983
1984 subroutine mt_rk45_tangent_diagnostic_seeds(seeds,nseed,dL,max_steps, &
1985 csv_file,b_min)
1986 integer, intent(in) :: nseed,max_steps
1987 double precision, intent(in) :: seeds(nseed,ndim),dl
1988 character(len=*), intent(in) :: csv_file
1989 double precision, intent(in), optional :: b_min
1990
1991 type(trace_qperp_result), allocatable :: rk2_results(:)
1992 type(trace_qperp_result), allocatable :: rk45_results(:)
1993
1994 if (npe/=1) then
1995 call mpistop('mt_rk45_tangent_diagnostic_seeds currently requires npe=1')
1996 endif
1997 if (nseed<0) then
1998 call mpistop('mt_rk45_tangent_diagnostic_seeds requires nseed>=0')
1999 endif
2000
2001 allocate(rk2_results(nseed),rk45_results(nseed))
2002 if (present(b_min)) then
2003 call trace_field_qperp_multi(seeds,nseed,dl,max_steps,rk2_results, &
2004 b_min)
2005 call trace_debug_cartesian_rk45_tangent_q0_multi(seeds,nseed,dl, &
2006 max_steps,rk45_results,b_min)
2007 else
2008 call trace_field_qperp_multi(seeds,nseed,dl,max_steps,rk2_results)
2009 call trace_debug_cartesian_rk45_tangent_q0_multi(seeds,nseed,dl, &
2010 max_steps,rk45_results)
2011 endif
2012
2013 call mt_write_rk45_tangent_diagnostic_csv(rk2_results,rk45_results, &
2014 nseed,csv_file)
2015 deallocate(rk45_results,rk2_results)
2016 end subroutine mt_rk45_tangent_diagnostic_seeds
2017
2018 subroutine mt_write_rk45_tangent_diagnostic_csv(rk2_results,rk45_results, &
2019 nseed,csv_file)
2020 integer, intent(in) :: nseed
2021 type(trace_qperp_result), intent(in) :: rk2_results(nseed)
2022 type(trace_qperp_result), intent(in) :: rk45_results(nseed)
2023 character(len=*), intent(in) :: csv_file
2024
2025 double precision :: seed_xyz(3),logq_diff,q_diff,length_diff
2026 double precision :: f_endpoint_diff,b_endpoint_diff
2027 double precision :: uf_diff,vf_diff,ub_diff,vb_diff
2028 integer :: csv_unit,io_status,iseed
2029
2030 open(newunit=csv_unit,file=trim(csv_file),status='replace', &
2031 action='write',form='formatted',iostat=io_status)
2032 if (io_status/=0) then
2033 call mpistop('mt_rk45_tangent_diagnostic could not open CSV file')
2034 endif
2035
2036 write(csv_unit,'(a)',iostat=io_status) &
2037 'seed_id,seed_x,seed_y,seed_z,'// &
2038 'rk2_status_q0,rk45_status_q0,'// &
2039 'rk2_forward_status,rk45_forward_status,'// &
2040 'rk2_backward_status,rk45_backward_status,'// &
2041 'rk2_logq0,rk45_logq0,abs_diff_logq0,'// &
2042 'rk2_q0,rk45_q0,abs_diff_q0,'// &
2043 'rk2_length_total,rk45_length_total,abs_diff_length_total,'// &
2044 'endpoint_diff_forward,endpoint_diff_backward,'// &
2045 'u_forward_perp_diff,v_forward_perp_diff,'// &
2046 'u_backward_perp_diff,v_backward_perp_diff'
2047 if (io_status/=0) then
2048 close(csv_unit)
2049 call mpistop('mt_rk45_tangent_diagnostic could not write CSV header')
2050 endif
2051
2052 do iseed=1,nseed
2053 seed_xyz=0.d0
2054 seed_xyz(1:ndim)=rk2_results(iseed)%seed
2055 logq_diff=mt_absdiff_or_nan(rk2_results(iseed)%logq0, &
2056 rk45_results(iseed)%logq0)
2057 q_diff=mt_absdiff_or_nan(rk2_results(iseed)%q0, &
2058 rk45_results(iseed)%q0)
2059 length_diff=abs((rk2_results(iseed)%forward_length+ &
2060 rk2_results(iseed)%backward_length)- &
2061 (rk45_results(iseed)%forward_length+ &
2062 rk45_results(iseed)%backward_length))
2063 f_endpoint_diff=dsqrt(sum((rk2_results(iseed)%forward_endpoint- &
2064 rk45_results(iseed)%forward_endpoint)**2))
2065 b_endpoint_diff=dsqrt(sum((rk2_results(iseed)%backward_endpoint- &
2066 rk45_results(iseed)%backward_endpoint)**2))
2067 uf_diff=dsqrt(sum((rk2_results(iseed)%u_forward_perp- &
2068 rk45_results(iseed)%u_forward_perp)**2))
2069 vf_diff=dsqrt(sum((rk2_results(iseed)%v_forward_perp- &
2070 rk45_results(iseed)%v_forward_perp)**2))
2071 ub_diff=dsqrt(sum((rk2_results(iseed)%u_backward_perp- &
2072 rk45_results(iseed)%u_backward_perp)**2))
2073 vb_diff=dsqrt(sum((rk2_results(iseed)%v_backward_perp- &
2074 rk45_results(iseed)%v_backward_perp)**2))
2075
2076 write(csv_unit,'(i0,3(",",es24.16),6(",",i0),15(",",es24.16))', &
2077 iostat=io_status) &
2078 iseed,seed_xyz, &
2079 rk2_results(iseed)%status_q0, &
2080 rk45_results(iseed)%status_q0, &
2081 rk2_results(iseed)%forward_status, &
2082 rk45_results(iseed)%forward_status, &
2083 rk2_results(iseed)%backward_status, &
2084 rk45_results(iseed)%backward_status, &
2085 rk2_results(iseed)%logq0,rk45_results(iseed)%logq0,logq_diff, &
2086 rk2_results(iseed)%q0,rk45_results(iseed)%q0,q_diff, &
2087 rk2_results(iseed)%forward_length+ &
2088 rk2_results(iseed)%backward_length, &
2089 rk45_results(iseed)%forward_length+ &
2090 rk45_results(iseed)%backward_length, &
2091 length_diff,f_endpoint_diff,b_endpoint_diff, &
2092 uf_diff,vf_diff,ub_diff,vb_diff
2093 if (io_status/=0) then
2094 close(csv_unit)
2095 call mpistop('mt_rk45_tangent_diagnostic could not write CSV data')
2096 endif
2097 enddo
2098
2099 close(csv_unit)
2100 end subroutine mt_write_rk45_tangent_diagnostic_csv
2101
2102 subroutine mt_rk2_fusion_diagnostic_seeds(seeds,nseed,dL,max_steps, &
2103 csv_file,b_min)
2104 integer, intent(in) :: nseed,max_steps
2105 double precision, intent(in) :: seeds(nseed,ndim),dl
2106 character(len=*), intent(in) :: csv_file
2107 double precision, intent(in), optional :: b_min
2108
2109 type(trace_topology_result), allocatable :: summary(:)
2110 type(trace_qperp_result), allocatable :: q_trace(:)
2111 type(trace_qperp_result), allocatable :: q_short(:)
2112 type(trace_twist_result), allocatable :: q_twist(:)
2113 type(trace_twist_result), allocatable :: q_short_twist(:)
2114 integer :: cache_status
2115 logical :: use_spherical_cache
2116
2117 if (npe/=1) then
2118 call mpistop('mt_rk2_fusion_diagnostic currently requires npe=1')
2119 endif
2120 if (nseed<0) then
2121 call mpistop('mt_rk2_fusion_diagnostic requires nseed>=0')
2122 endif
2123 if (mt_lowercase(trim(mt_trace_integrator))/='rk2') then
2124 call mpistop('mt_rk2_fusion_diagnostic requires rk2 tracing')
2125 endif
2126
2127 allocate(summary(nseed),q_trace(nseed),q_short(nseed), &
2128 q_twist(nseed),q_short_twist(nseed))
2129 use_spherical_cache=.false.
2130 {^ifthreed
2131 if (geo_coordinate==geo_spherical) then
2132 call trace_spherical_curl_cache_build(cache_status)
2133 if (cache_status/=trace_status_active) then
2134 call mpistop('mt_rk2_fusion_diagnostic failed to build '// &
2135 'spherical curl cache')
2136 endif
2137 use_spherical_cache=.true.
2138 endif
2139 }
2140
2141 if (present(b_min)) then
2142 call trace_field_topology_multi(seeds,nseed,dl,max_steps,summary, &
2143 need_twist=.true.,need_mapping=.false.,b_min=b_min)
2144 if (geo_coordinate==geo_spherical) then
2145 call trace_field_spherical_rmin_q_multi(seeds,nseed,dl,max_steps, &
2146 q_trace,b_min,twist_results=q_twist)
2147 call trace_field_rk2_short_boundary_q_multi(seeds,nseed,dl, &
2148 max_steps,q_short,b_min,twist_results=q_short_twist)
2149 else
2150 call trace_field_qperp_multi(seeds,nseed,dl,max_steps,q_trace, &
2151 b_min,twist_results=q_twist)
2152 call trace_field_rk2_short_boundary_q_multi(seeds,nseed,dl, &
2153 max_steps,q_short,b_min,twist_results=q_short_twist)
2154 endif
2155 else
2156 call trace_field_topology_multi(seeds,nseed,dl,max_steps,summary, &
2157 need_twist=.true.,need_mapping=.false.)
2158 if (geo_coordinate==geo_spherical) then
2159 call trace_field_spherical_rmin_q_multi(seeds,nseed,dl,max_steps, &
2160 q_trace,twist_results=q_twist)
2161 call trace_field_rk2_short_boundary_q_multi(seeds,nseed,dl, &
2162 max_steps,q_short,twist_results=q_short_twist)
2163 else
2164 call trace_field_qperp_multi(seeds,nseed,dl,max_steps,q_trace, &
2165 twist_results=q_twist)
2166 call trace_field_rk2_short_boundary_q_multi(seeds,nseed,dl, &
2167 max_steps,q_short,twist_results=q_short_twist)
2168 endif
2169 endif
2170
2171 if (use_spherical_cache) call trace_spherical_curl_cache_clear()
2172 call mt_write_rk2_fusion_diagnostic_csv(summary,q_trace,q_twist, &
2173 q_short,q_short_twist,nseed,csv_file)
2174 deallocate(q_short_twist,q_twist,q_short,q_trace,summary)
2175 end subroutine mt_rk2_fusion_diagnostic_seeds
2176
2177 subroutine mt_write_rk2_fusion_diagnostic_csv(summary,q_trace,q_twist, &
2178 q_short,q_short_twist,nseed,csv_file)
2179 integer, intent(in) :: nseed
2180 type(trace_topology_result), intent(in) :: summary(nseed)
2181 type(trace_qperp_result), intent(in) :: q_trace(nseed)
2182 type(trace_twist_result), intent(in) :: q_twist(nseed)
2183 type(trace_qperp_result), intent(in) :: q_short(nseed)
2184 type(trace_twist_result), intent(in) :: q_short_twist(nseed)
2185 character(len=*), intent(in) :: csv_file
2186
2187 double precision :: seed_xyz(3),length_summary,length_q,length_diff
2188 double precision :: length_short,length_diff_short,length_q_short_diff
2189 double precision :: twist_summary,twist_q,twist_diff
2190 double precision :: twist_short,twist_diff_short,twist_q_short_diff
2191 double precision :: max_length_diff,max_twist_diff
2192 double precision :: max_length_short_diff,max_twist_short_diff
2193 integer :: csv_unit,io_status,iseed
2194 integer :: status_mismatch,face_mismatch,twist_status_mismatch
2195 integer :: short_status_mismatch,short_face_mismatch
2196 integer :: short_twist_status_mismatch,short_valid_q_mismatch
2197
2198 max_length_diff=0.d0
2199 max_twist_diff=0.d0
2200 max_length_short_diff=0.d0
2201 max_twist_short_diff=0.d0
2202 status_mismatch=0
2203 face_mismatch=0
2204 twist_status_mismatch=0
2205 short_status_mismatch=0
2206 short_face_mismatch=0
2207 short_twist_status_mismatch=0
2208 short_valid_q_mismatch=0
2209
2210 open(newunit=csv_unit,file=trim(csv_file),status='replace', &
2211 action='write',form='formatted',iostat=io_status)
2212 if (io_status/=0) then
2213 call mpistop('mt_rk2_fusion_diagnostic could not open CSV file')
2214 endif
2215
2216 write(csv_unit,'(a)',iostat=io_status) &
2217 'seed_id,seed_x,seed_y,seed_z,'// &
2218 'length_summary,length_qtrace,dlength_summary_minus_qtrace,'// &
2219 'length_forward_summary,length_forward_qtrace,'// &
2220 'length_backward_summary,length_backward_qtrace,'// &
2221 'twist_summary,twist_qtrace,dtwist_summary_minus_qtrace,'// &
2222 'twist_forward_summary,twist_forward_qtrace,'// &
2223 'twist_backward_summary,twist_backward_qtrace,'// &
2224 'length_short,dlength_summary_minus_short,'// &
2225 'dlength_qtrace_minus_short,'// &
2226 'length_forward_short,length_backward_short,'// &
2227 'twist_short,dtwist_summary_minus_short,'// &
2228 'dtwist_qtrace_minus_short,'// &
2229 'twist_forward_short,twist_backward_short,'// &
2230 'status_forward_summary,status_forward_qtrace,status_forward_short,'// &
2231 'status_backward_summary,status_backward_qtrace,status_backward_short,'// &
2232 'face_forward_summary,face_forward_qtrace,face_forward_short,'// &
2233 'face_backward_summary,face_backward_qtrace,face_backward_short,'// &
2234 'status_twist_summary,status_twist_qtrace,status_twist_short,'// &
2235 'logQ,valid_Q,status_Q,logQ_short,valid_Q_short,status_Q_short'
2236 if (io_status/=0) then
2237 close(csv_unit)
2238 call mpistop('mt_rk2_fusion_diagnostic could not write CSV header')
2239 endif
2240
2241 do iseed=1,nseed
2242 seed_xyz=0.d0
2243 seed_xyz(1:ndim)=summary(iseed)%seed
2244 length_summary=summary(iseed)%length_total
2245 length_q=q_trace(iseed)%forward_length+q_trace(iseed)%backward_length
2246 length_short=q_short(iseed)%forward_length+ &
2247 q_short(iseed)%backward_length
2248 length_diff=length_summary-length_q
2249 length_diff_short=length_summary-length_short
2250 length_q_short_diff=length_q-length_short
2251 twist_summary=summary(iseed)%twist_total
2252 twist_q=q_twist(iseed)%total_twist
2253 twist_short=q_short_twist(iseed)%total_twist
2254 twist_diff=twist_summary-twist_q
2255 twist_diff_short=twist_summary-twist_short
2256 twist_q_short_diff=twist_q-twist_short
2257 max_length_diff=max(max_length_diff,abs(length_diff))
2258 max_twist_diff=max(max_twist_diff,abs(twist_diff))
2259 max_length_short_diff=max(max_length_short_diff, &
2260 abs(length_diff_short))
2261 max_twist_short_diff=max(max_twist_short_diff, &
2262 abs(twist_diff_short))
2263 if (summary(iseed)%forward_status/=q_trace(iseed)%forward_status .or. &
2264 summary(iseed)%backward_status/=q_trace(iseed)%backward_status) &
2265 status_mismatch=status_mismatch+1
2266 if (summary(iseed)%forward_face/=q_trace(iseed)%forward_face .or. &
2267 summary(iseed)%backward_face/=q_trace(iseed)%backward_face) &
2268 face_mismatch=face_mismatch+1
2269 if (summary(iseed)%status_twist/=q_twist(iseed)%status_twist) &
2270 twist_status_mismatch=twist_status_mismatch+1
2271 if (summary(iseed)%forward_status/=q_short(iseed)%forward_status .or. &
2272 summary(iseed)%backward_status/=q_short(iseed)%backward_status) &
2273 short_status_mismatch=short_status_mismatch+1
2274 if (summary(iseed)%forward_face/=q_short(iseed)%forward_face .or. &
2275 summary(iseed)%backward_face/=q_short(iseed)%backward_face) &
2276 short_face_mismatch=short_face_mismatch+1
2277 if (summary(iseed)%status_twist/=q_short_twist(iseed)%status_twist) &
2278 short_twist_status_mismatch=short_twist_status_mismatch+1
2279 if (q_trace(iseed)%valid_q0 .neqv. q_short(iseed)%valid_q0) &
2280 short_valid_q_mismatch=short_valid_q_mismatch+1
2281
2282 write(csv_unit, &
2283 '(i0,3(",",es24.16),24(",",es24.16),15(",",i0),'// &
2284 '",",es24.16,",",l1,",",i0,",",es24.16,",",l1,",",i0)', &
2285 iostat=io_status) &
2286 iseed,seed_xyz, &
2287 length_summary,length_q,length_diff, &
2288 summary(iseed)%length_forward,q_trace(iseed)%forward_length, &
2289 summary(iseed)%length_backward,q_trace(iseed)%backward_length, &
2290 twist_summary,twist_q,twist_diff, &
2291 summary(iseed)%twist_forward,q_twist(iseed)%forward_twist, &
2292 summary(iseed)%twist_backward,q_twist(iseed)%backward_twist, &
2293 length_short,length_diff_short,length_q_short_diff, &
2294 q_short(iseed)%forward_length,q_short(iseed)%backward_length, &
2295 twist_short,twist_diff_short,twist_q_short_diff, &
2296 q_short_twist(iseed)%forward_twist, &
2297 q_short_twist(iseed)%backward_twist, &
2298 summary(iseed)%forward_status,q_trace(iseed)%forward_status, &
2299 q_short(iseed)%forward_status, &
2300 summary(iseed)%backward_status,q_trace(iseed)%backward_status, &
2301 q_short(iseed)%backward_status, &
2302 summary(iseed)%forward_face,q_trace(iseed)%forward_face, &
2303 q_short(iseed)%forward_face, &
2304 summary(iseed)%backward_face,q_trace(iseed)%backward_face, &
2305 q_short(iseed)%backward_face, &
2306 summary(iseed)%status_twist,q_twist(iseed)%status_twist, &
2307 q_short_twist(iseed)%status_twist, &
2308 q_trace(iseed)%logq0,q_trace(iseed)%valid_q0, &
2309 q_trace(iseed)%status_q0, &
2310 q_short(iseed)%logq0,q_short(iseed)%valid_q0, &
2311 q_short(iseed)%status_q0
2312 if (io_status/=0) then
2313 close(csv_unit)
2314 call mpistop('mt_rk2_fusion_diagnostic could not write CSV data')
2315 endif
2316 enddo
2317
2318 close(csv_unit)
2319 write(*,'(a,es12.4)') 'mt_rk2_fusion_diagnostic max_abs_length_diff: ', &
2320 max_length_diff
2321 write(*,'(a,es12.4)') 'mt_rk2_fusion_diagnostic max_abs_twist_diff: ', &
2322 max_twist_diff
2323 write(*,'(a,es12.4)') &
2324 'mt_rk2_fusion_diagnostic max_abs_length_diff_short: ', &
2325 max_length_short_diff
2326 write(*,'(a,es12.4)') &
2327 'mt_rk2_fusion_diagnostic max_abs_twist_diff_short: ', &
2328 max_twist_short_diff
2329 write(*,'(a,i0)') 'mt_rk2_fusion_diagnostic status_mismatch_count: ', &
2330 status_mismatch
2331 write(*,'(a,i0)') 'mt_rk2_fusion_diagnostic face_mismatch_count: ', &
2332 face_mismatch
2333 write(*,'(a,i0)') &
2334 'mt_rk2_fusion_diagnostic twist_status_mismatch_count: ', &
2335 twist_status_mismatch
2336 write(*,'(a,i0)') &
2337 'mt_rk2_fusion_diagnostic short_status_mismatch_count: ', &
2338 short_status_mismatch
2339 write(*,'(a,i0)') &
2340 'mt_rk2_fusion_diagnostic short_face_mismatch_count: ', &
2341 short_face_mismatch
2342 write(*,'(a,i0)') &
2343 'mt_rk2_fusion_diagnostic short_twist_status_mismatch_count: ', &
2344 short_twist_status_mismatch
2345 write(*,'(a,i0)') &
2346 'mt_rk2_fusion_diagnostic short_valid_q_mismatch_count: ', &
2347 short_valid_q_mismatch
2348 end subroutine mt_write_rk2_fusion_diagnostic_csv
2349
2350 double precision function mt_absdiff_or_nan(a,b) result(diff)
2351 double precision, intent(in) :: a,b
2352
2353 if (ieee_is_finite(a) .and. ieee_is_finite(b)) then
2354 diff=abs(a-b)
2355 else
2356 diff=ieee_value(0.d0,ieee_quiet_nan)
2357 endif
2358 end function mt_absdiff_or_nan
2359
2360 subroutine mt_fieldline_products_spherical_surface(surface,seed_coord, &
2361 s1_min,s1_max,n1,s2_min,s2_max,n2,dL,max_steps,csv_file, &
2362 vtu_file,seed_layout,seed_theta0,seed_phi0,seed_alpha, &
2363 compute_twist,compute_q,compute_qperp,b_min)
2364 character(len=*), intent(in) :: surface,csv_file,vtu_file,seed_layout
2365 integer, intent(in) :: n1,n2,max_steps
2366 double precision, intent(in) :: seed_coord,s1_min,s1_max,s2_min,s2_max,dl
2367 double precision, intent(in) :: seed_theta0,seed_phi0,seed_alpha
2368 logical, intent(in), optional :: compute_twist,compute_q,compute_qperp
2369 double precision, intent(in), optional :: b_min
2370
2371 type(trace_topology_result), allocatable :: topology(:)
2372 type(trace_qperp_result), allocatable :: q_results(:)
2373 type(trace_qperp_result), allocatable :: qperp_results(:)
2374 double precision, allocatable :: seeds(:,:)
2375 integer :: nseed
2376 logical :: do_twist,do_q,do_qperp
2377
2378 if (npe/=1) then
2379 call mpistop('mt_fieldline_products_spherical_surface currently '// &
2380 'requires npe=1')
2381 endif
2382 if (ndim/=3 .or. geo_coordinate/=geo_spherical) then
2383 call mpistop('mt_fieldline_products_spherical_surface requires '// &
2384 '3D spherical geometry')
2385 endif
2386 {^ifthreed
2387 if (periodb(3)) then
2388 call mpistop('mt_fieldline_products_spherical_surface does not '// &
2389 'yet support periodic phi')
2390 endif
2391 }
2392 if (n1<1 .or. n2<1) then
2393 call mpistop('mt_fieldline_products_spherical_surface requires '// &
2394 'sample counts >=1')
2395 endif
2396 if (s1_max<s1_min .or. s2_max<s2_min) then
2397 call mpistop('mt_fieldline_products_spherical_surface requires ordered bounds')
2398 endif
2399 do_twist=.false.
2400 do_q=.false.
2401 do_qperp=.false.
2402 if (present(compute_twist)) do_twist=compute_twist
2403 if (present(compute_q)) do_q=compute_q
2404 if (present(compute_qperp)) do_qperp=compute_qperp
2405 call mt_build_spherical_surface_seeds(surface,seed_coord,s1_min,s1_max, &
2406 n1,s2_min,s2_max,n2,seed_layout,seed_theta0,seed_phi0, &
2407 seed_alpha,seeds)
2408 nseed=n1*n2
2409 if (mt_profile_spherical) call trace_spherical_profile_count_seeds(nseed)
2410 allocate(topology(nseed))
2411 if (do_q) then
2412 allocate(q_results(nseed))
2413 else
2414 allocate(q_results(0))
2415 endif
2416 if (do_qperp) then
2417 allocate(qperp_results(nseed))
2418 else
2419 allocate(qperp_results(0))
2420 endif
2421
2422 if (present(b_min)) then
2423 call mt_trace_spherical_surface_products(seeds,nseed,dl,max_steps, &
2424 topology,q_results,qperp_results,do_twist,do_q,do_qperp,b_min)
2425 else
2426 call mt_trace_spherical_surface_products(seeds,nseed,dl,max_steps, &
2427 topology,q_results,qperp_results,do_twist,do_q,do_qperp)
2428 endif
2429
2430 if (len_trim(csv_file)>0) then
2431 call mt_write_spherical_rmin_csv(topology,n1,n2,csv_file, &
2432 'mt_fieldline_products_spherical_surface',do_twist,do_q, &
2433 q_results,do_qperp,qperp_results)
2434 endif
2435 call mt_write_spherical_topology_vtu(vtu_file,topology,n1,n2, &
2436 'mt_fieldline_products_spherical_surface',do_twist,do_q,q_results, &
2437 do_qperp,qperp_results)
2438
2439 deallocate(qperp_results,q_results,topology,seeds)
2440 end subroutine mt_fieldline_products_spherical_surface
2441
2442 subroutine mt_fieldline_products_spherical_cloud(s1_min,s1_max,n1, &
2443 s2_min,s2_max,n2,s3_min,s3_max,n3,dL,max_steps,vtu_file, &
2444 seed_layout,compute_twist,compute_q,compute_qperp,b_min)
2445 character(len=*), intent(in) :: vtu_file,seed_layout
2446 integer, intent(in) :: n1,n2,n3,max_steps
2447 double precision, intent(in) :: s1_min,s1_max,s2_min,s2_max
2448 double precision, intent(in) :: s3_min,s3_max,dl
2449 logical, intent(in), optional :: compute_twist,compute_q,compute_qperp
2450 double precision, intent(in), optional :: b_min
2451
2452 type(trace_topology_result), allocatable :: topology(:)
2453 type(trace_qperp_result), allocatable :: q_results(:)
2454 type(trace_qperp_result), allocatable :: qperp_results(:)
2455 double precision, allocatable :: seeds(:,:)
2456 integer :: nseed
2457 logical :: do_twist,do_q,do_qperp
2458 character(len=mt_task_name_len) :: integrator
2459
2460 if (npe/=1) then
2461 call mpistop('mt_fieldline_products_spherical_cloud currently '// &
2462 'requires npe=1')
2463 endif
2464 if (ndim/=3 .or. geo_coordinate/=geo_spherical) then
2465 call mpistop('mt_fieldline_products_spherical_cloud requires '// &
2466 '3D spherical geometry')
2467 endif
2468 {^ifthreed
2469 if (periodb(3)) then
2470 call mpistop('mt_fieldline_products_spherical_cloud does not '// &
2471 'yet support periodic phi')
2472 endif
2473 }
2474 if (n1<1 .or. n2<1 .or. n3<1) then
2475 call mpistop('mt_fieldline_products_spherical_cloud requires '// &
2476 'sample counts >=1')
2477 endif
2478 if (s1_max<s1_min .or. s2_max<s2_min .or. s3_max<s3_min) then
2479 call mpistop('mt_fieldline_products_spherical_cloud requires ordered bounds')
2480 endif
2481
2482 do_twist=.false.
2483 do_q=.false.
2484 do_qperp=.false.
2485 if (present(compute_twist)) do_twist=compute_twist
2486 if (present(compute_q)) do_q=compute_q
2487 if (present(compute_qperp)) do_qperp=compute_qperp
2488 integrator=mt_lowercase(trim(mt_trace_integrator))
2489
2490 call mt_build_spherical_cloud_seeds(s1_min,s1_max,n1,s2_min,s2_max, &
2491 n2,s3_min,s3_max,n3,seed_layout,seeds)
2492 nseed=n1*n2*n3
2493 if (mt_profile_spherical) call trace_spherical_profile_count_seeds(nseed)
2494 allocate(topology(nseed))
2495 if (do_q) then
2496 allocate(q_results(nseed))
2497 else
2498 allocate(q_results(0))
2499 endif
2500 if (do_qperp) then
2501 allocate(qperp_results(nseed))
2502 else
2503 allocate(qperp_results(0))
2504 endif
2505
2506 if (present(b_min)) then
2507 call mt_trace_spherical_cloud_products(seeds,nseed,dl,max_steps, &
2508 topology,q_results,qperp_results,do_twist,do_q,do_qperp,b_min)
2509 else
2510 call mt_trace_spherical_cloud_products(seeds,nseed,dl,max_steps, &
2511 topology,q_results,qperp_results,do_twist,do_q,do_qperp)
2512 endif
2513
2514 call mt_write_spherical_cloud_vtu(vtu_file,topology,nseed, &
2515 'mt_fieldline_products_spherical_cloud',do_twist,do_q,q_results, &
2516 do_qperp,qperp_results)
2517
2518 deallocate(qperp_results,q_results,topology,seeds)
2519 end subroutine mt_fieldline_products_spherical_cloud
2520
2521 subroutine mt_trace_spherical_surface_products(seeds,nseed,dL,max_steps, &
2522 topology,q_results,qperp_results,do_twist,do_q,do_qperp,b_min)
2523 integer, intent(in) :: nseed,max_steps
2524 double precision, intent(in) :: seeds(nseed,ndim),dl
2525 type(trace_topology_result), intent(out) :: topology(nseed)
2526 type(trace_qperp_result), intent(out) :: q_results(:)
2527 type(trace_qperp_result), intent(out) :: qperp_results(:)
2528 logical, intent(in) :: do_twist,do_q,do_qperp
2529 double precision, intent(in), optional :: b_min
2530
2531 type(trace_qperp_result) :: q_local,qperp_local
2532 double precision :: seed_local(ndim)
2533 integer :: iseed,cache_status
2534
2535 if (nseed<=0) return
2536
2537 if (do_twist) then
2538 call trace_spherical_curl_cache_build(cache_status)
2539 if (cache_status/=trace_status_active) then
2540 call mpistop('mt_trace_spherical_surface_products failed to '// &
2541 'build spherical curl cache')
2542 endif
2543 endif
2544
2545 if (present(b_min)) then
2546 !$OMP PARALLEL DO DEFAULT(SHARED) PRIVATE(iseed,seed_local,q_local,qperp_local) SCHEDULE(DYNAMIC,16)
2547 do iseed=1,nseed
2548 seed_local=seeds(iseed,:)
2549 call mt_trace_spherical_surface_seed(seed_local,dl,max_steps, &
2550 topology(iseed),q_local,qperp_local,do_twist,do_q, &
2551 do_qperp,b_min)
2552 if (do_q) q_results(iseed)=q_local
2553 if (do_qperp) qperp_results(iseed)=qperp_local
2554 enddo
2555 !$OMP END PARALLEL DO
2556 else
2557 !$OMP PARALLEL DO DEFAULT(SHARED) PRIVATE(iseed,seed_local,q_local,qperp_local) SCHEDULE(DYNAMIC,16)
2558 do iseed=1,nseed
2559 seed_local=seeds(iseed,:)
2560 call mt_trace_spherical_surface_seed(seed_local,dl,max_steps, &
2561 topology(iseed),q_local,qperp_local,do_twist,do_q, &
2562 do_qperp)
2563 if (do_q) q_results(iseed)=q_local
2564 if (do_qperp) qperp_results(iseed)=qperp_local
2565 enddo
2566 !$OMP END PARALLEL DO
2567 endif
2568
2569 if (do_twist) call trace_spherical_curl_cache_clear()
2570 end subroutine mt_trace_spherical_surface_products
2571
2572 subroutine mt_trace_spherical_surface_seed(seed,dL,max_steps,topology, &
2573 q_result,qperp_result,do_twist,do_q,do_qperp,b_min)
2574 integer, intent(in) :: max_steps
2575 double precision, intent(in) :: seed(ndim),dl
2576 type(trace_topology_result), intent(out) :: topology
2577 type(trace_qperp_result), intent(out) :: q_result,qperp_result
2578 logical, intent(in) :: do_twist,do_q,do_qperp
2579 double precision, intent(in), optional :: b_min
2580
2581 type(trace_topology_result) :: topology_one(1)
2582 type(trace_qperp_result) :: q_one(1),qperp_one(1)
2583 type(trace_twist_result) :: twist_one(1)
2584 double precision :: seed_one(1,ndim),source_normal(3)
2585
2586 seed_one(1,:)=seed
2587 source_normal=0.d0
2588 source_normal(1)=-1.d0
2589
2590 if (do_q .and. do_qperp) then
2591 if (present(b_min)) then
2592 if (do_twist) then
2593 call trace_field_spherical_rmin_q_qperp_multi(seed_one,1,dl, &
2594 max_steps,q_one,qperp_one,b_min,twist_results=twist_one)
2595 else
2596 call trace_field_spherical_rmin_q_qperp_multi(seed_one,1,dl, &
2597 max_steps,q_one,qperp_one,b_min)
2598 endif
2599 else
2600 if (do_twist) then
2601 call trace_field_spherical_rmin_q_qperp_multi(seed_one,1,dl, &
2602 max_steps,q_one,qperp_one,twist_results=twist_one)
2603 else
2604 call trace_field_spherical_rmin_q_qperp_multi(seed_one,1,dl, &
2605 max_steps,q_one,qperp_one)
2606 endif
2607 endif
2608 call mt_q0_trace_to_topology(q_one,twist_one,1,topology_one,do_twist)
2609 topology=topology_one(1)
2610 q_result=q_one(1)
2611 qperp_result=qperp_one(1)
2612 return
2613 endif
2614
2615 if (do_q) then
2616 if (present(b_min)) then
2617 if (do_twist) then
2618 call trace_field_spherical_rmin_q_multi(seed_one,1,dl,max_steps, &
2619 q_one,b_min,twist_results=twist_one)
2620 else
2621 call trace_field_spherical_rmin_q_multi(seed_one,1,dl,max_steps, &
2622 q_one,b_min)
2623 endif
2624 else
2625 if (do_twist) then
2626 call trace_field_spherical_rmin_q_multi(seed_one,1,dl,max_steps, &
2627 q_one,twist_results=twist_one)
2628 else
2629 call trace_field_spherical_rmin_q_multi(seed_one,1,dl,max_steps, &
2630 q_one)
2631 endif
2632 endif
2633 call mt_q0_trace_to_topology(q_one,twist_one,1,topology_one,do_twist)
2634 topology=topology_one(1)
2635 q_result=q_one(1)
2636 return
2637 endif
2638
2639 if (present(b_min)) then
2640 call trace_field_topology_multi(seed_one,1,dl,max_steps,topology_one, &
2641 need_twist=do_twist,need_mapping=.false.,b_min=b_min, &
2642 source_normal=source_normal)
2643 else
2644 call trace_field_topology_multi(seed_one,1,dl,max_steps,topology_one, &
2645 need_twist=do_twist,need_mapping=.false., &
2646 source_normal=source_normal)
2647 endif
2648 topology=topology_one(1)
2649
2650 if (do_qperp) then
2651 if (present(b_min)) then
2652 call trace_field_spherical_qperp_multi(seed_one,1,dl,max_steps, &
2653 qperp_one,b_min)
2654 else
2655 call trace_field_spherical_qperp_multi(seed_one,1,dl,max_steps, &
2656 qperp_one)
2657 endif
2658 qperp_result=qperp_one(1)
2659 endif
2660 end subroutine mt_trace_spherical_surface_seed
2661
2662 subroutine mt_trace_spherical_cloud_products(seeds,nseed,dL,max_steps, &
2663 topology,q_results,qperp_results,do_twist,do_q,do_qperp,b_min)
2664 integer, intent(in) :: nseed,max_steps
2665 double precision, intent(in) :: seeds(nseed,ndim),dl
2666 type(trace_topology_result), intent(out) :: topology(nseed)
2667 type(trace_qperp_result), intent(out) :: q_results(:)
2668 type(trace_qperp_result), intent(out) :: qperp_results(:)
2669 logical, intent(in) :: do_twist,do_q,do_qperp
2670 double precision, intent(in), optional :: b_min
2671
2672 type(trace_topology_result) :: topology_one(1)
2673 type(trace_twist_result), allocatable :: twist_results(:)
2674 double precision :: seed_local(ndim),seed_one(1,ndim)
2675 integer :: iseed,cache_status
2676 character(len=mt_task_name_len) :: integrator
2677
2678 if (nseed<=0) return
2679
2680 integrator=mt_lowercase(trim(mt_trace_integrator))
2681 if (do_q .and. do_qperp .and. &
2682 (integrator=='rk2' .or. integrator=='rk45_spherical')) then
2683 ! The spherical grouped RK45 driver scans all active states by grid.
2684 ! For volume clouds this is much slower and much more memory-hungry than
2685 ! the surface product's seed-wise OpenMP schedule.
2686 if (present(b_min)) then
2687 call mt_trace_spherical_surface_products(seeds,nseed,dl,max_steps, &
2688 topology,q_results,qperp_results,do_twist,do_q,do_qperp,b_min)
2689 else
2690 call mt_trace_spherical_surface_products(seeds,nseed,dl,max_steps, &
2691 topology,q_results,qperp_results,do_twist,do_q,do_qperp)
2692 endif
2693 return
2694 endif
2695
2696 if (do_q .and. .not.do_qperp) then
2697 if (do_twist) then
2698 allocate(twist_results(nseed))
2699 if (present(b_min)) then
2700 call trace_field_spherical_rmin_q_multi(seeds,nseed,dl,max_steps, &
2701 q_results,b_min,twist_results=twist_results)
2702 else
2703 call trace_field_spherical_rmin_q_multi(seeds,nseed,dl,max_steps, &
2704 q_results,twist_results=twist_results)
2705 endif
2706 call mt_q0_trace_to_topology(q_results,twist_results,nseed,topology, &
2707 do_twist)
2708 deallocate(twist_results)
2709 else
2710 allocate(twist_results(0))
2711 if (present(b_min)) then
2712 call trace_field_spherical_rmin_q_multi(seeds,nseed,dl,max_steps, &
2713 q_results,b_min)
2714 else
2715 call trace_field_spherical_rmin_q_multi(seeds,nseed,dl,max_steps, &
2716 q_results)
2717 endif
2718 call mt_q0_trace_to_topology(q_results,twist_results,nseed,topology, &
2719 do_twist)
2720 deallocate(twist_results)
2721 endif
2722 return
2723 endif
2724
2725 if (do_qperp) then
2726 if (do_twist) then
2727 allocate(twist_results(nseed))
2728 if (present(b_min)) then
2729 call trace_field_spherical_qperp_multi(seeds,nseed,dl,max_steps, &
2730 qperp_results,b_min,twist_results=twist_results)
2731 else
2732 call trace_field_spherical_qperp_multi(seeds,nseed,dl,max_steps, &
2733 qperp_results,twist_results=twist_results)
2734 endif
2735 call mt_qperp_trace_to_topology(qperp_results,twist_results,nseed, &
2736 topology,do_twist)
2737 deallocate(twist_results)
2738 else
2739 allocate(twist_results(0))
2740 if (present(b_min)) then
2741 call trace_field_spherical_qperp_multi(seeds,nseed,dl,max_steps, &
2742 qperp_results,b_min)
2743 else
2744 call trace_field_spherical_qperp_multi(seeds,nseed,dl,max_steps, &
2745 qperp_results)
2746 endif
2747 call mt_qperp_trace_to_topology(qperp_results,twist_results,nseed, &
2748 topology,do_twist)
2749 deallocate(twist_results)
2750 endif
2751 return
2752 endif
2753
2754 if (do_twist) then
2755 call trace_spherical_curl_cache_build(cache_status)
2756 if (cache_status/=trace_status_active) then
2757 call mpistop('mt_trace_spherical_cloud_products failed to '// &
2758 'build spherical curl cache')
2759 endif
2760 endif
2761
2762 if (present(b_min)) then
2763 !$OMP PARALLEL DO DEFAULT(SHARED) PRIVATE(iseed,seed_local,seed_one,topology_one) SCHEDULE(DYNAMIC,16)
2764 do iseed=1,nseed
2765 seed_local=seeds(iseed,:)
2766 seed_one(1,:)=seed_local
2767 call trace_field_topology_multi(seed_one,1,dl,max_steps, &
2768 topology_one,need_twist=do_twist,need_mapping=.false., &
2769 b_min=b_min)
2770 topology(iseed)=topology_one(1)
2771 enddo
2772 !$OMP END PARALLEL DO
2773 else
2774 !$OMP PARALLEL DO DEFAULT(SHARED) PRIVATE(iseed,seed_local,seed_one,topology_one) SCHEDULE(DYNAMIC,16)
2775 do iseed=1,nseed
2776 seed_local=seeds(iseed,:)
2777 seed_one(1,:)=seed_local
2778 call trace_field_topology_multi(seed_one,1,dl,max_steps, &
2779 topology_one,need_twist=do_twist,need_mapping=.false.)
2780 topology(iseed)=topology_one(1)
2781 enddo
2782 !$OMP END PARALLEL DO
2783 endif
2784
2785 if (do_twist) call trace_spherical_curl_cache_clear()
2786 end subroutine mt_trace_spherical_cloud_products
2787
2788 subroutine mt_length_plane_xy(xmin,xmax,nx,ymin,ymax,ny,z0,dL, &
2789 max_steps,csv_file,b_min)
2790 ! Trace a uniform seed grid on a constant-z Cartesian plane.
2791 integer, intent(in) :: nx,ny,max_steps
2792 double precision, intent(in) :: xmin,xmax,ymin,ymax,z0,dl
2793 character(len=*), intent(in) :: csv_file
2794 double precision, intent(in), optional :: b_min
2795
2796 if (present(b_min)) then
2797 call mt_length_plane_axis(xmin,xmax,nx,ymin,ymax,ny,z0,1,2,3, &
2798 dl,max_steps,csv_file,'mt_length_plane_xy','ix,iy',b_min)
2799 else
2800 call mt_length_plane_axis(xmin,xmax,nx,ymin,ymax,ny,z0,1,2,3, &
2801 dl,max_steps,csv_file,'mt_length_plane_xy','ix,iy')
2802 endif
2803 end subroutine mt_length_plane_xy
2804
2805 subroutine mt_mapping_plane_xy(xmin,xmax,nx,ymin,ymax,ny,z0,dL, &
2806 max_steps,csv_file,b_min)
2807 ! Trace a constant-z seed grid and write endpoint metadata for Q mapping.
2808 integer, intent(in) :: nx,ny,max_steps
2809 double precision, intent(in) :: xmin,xmax,ymin,ymax,z0,dl
2810 character(len=*), intent(in) :: csv_file
2811 double precision, intent(in), optional :: b_min
2812
2813 type(trace_mapping_result), allocatable :: results(:)
2814 double precision, allocatable :: seeds(:,:)
2815 double precision :: source_normal(3)
2816 integer :: nseed
2817
2818 call mt_validate_axis_plane(xmin,xmax,nx,ymin,ymax,ny, &
2819 'mt_mapping_plane_xy')
2820 call mt_build_axis_plane_seeds(xmin,xmax,nx,ymin,ymax,ny,z0, &
2821 1,2,3,seeds)
2822
2823 source_normal=0.d0
2824 source_normal(3)=1.d0
2825 nseed=nx*ny
2826 allocate(results(nseed))
2827 if (present(b_min)) then
2828 call trace_field_mapping_multi(seeds,nseed,dl,max_steps,results, &
2829 b_min=b_min,source_normal=source_normal)
2830 else
2831 call trace_field_mapping_multi(seeds,nseed,dl,max_steps,results, &
2832 source_normal=source_normal)
2833 endif
2834 call mt_write_mapping_plane_xy_csv(results,nx,ny,csv_file)
2835
2836 deallocate(seeds,results)
2837 end subroutine mt_mapping_plane_xy
2838
2839 subroutine mt_q_plane_xy(xmin,xmax,nx,ymin,ymax,ny,z0,dL, &
2840 max_steps,csv_file,b_min)
2841 ! Compute standard Cartesian logQ diagnostics on a constant-z seed plane.
2842 integer, intent(in) :: nx,ny,max_steps
2843 double precision, intent(in) :: xmin,xmax,ymin,ymax,z0,dl
2844 character(len=*), intent(in) :: csv_file
2845 double precision, intent(in), optional :: b_min
2846
2847 if (present(b_min)) then
2848 call mt_q_plane_axis(xmin,xmax,nx,ymin,ymax,ny,z0,1,2,3, &
2849 dl,max_steps,csv_file,'mt_q_plane_xy','ix,iy',b_min)
2850 else
2851 call mt_q_plane_axis(xmin,xmax,nx,ymin,ymax,ny,z0,1,2,3, &
2852 dl,max_steps,csv_file,'mt_q_plane_xy','ix,iy')
2853 endif
2854 end subroutine mt_q_plane_xy
2855
2856 subroutine mt_q_plane_xz(xmin,xmax,nx,zmin,zmax,nz,y0,dL, &
2857 max_steps,csv_file,b_min)
2858 ! Compute standard Cartesian logQ diagnostics on a constant-y seed plane.
2859 integer, intent(in) :: nx,nz,max_steps
2860 double precision, intent(in) :: xmin,xmax,zmin,zmax,y0,dl
2861 character(len=*), intent(in) :: csv_file
2862 double precision, intent(in), optional :: b_min
2863
2864 if (present(b_min)) then
2865 call mt_q_plane_axis(xmin,xmax,nx,zmin,zmax,nz,y0,1,3,2, &
2866 dl,max_steps,csv_file,'mt_q_plane_xz','ix,iz',b_min)
2867 else
2868 call mt_q_plane_axis(xmin,xmax,nx,zmin,zmax,nz,y0,1,3,2, &
2869 dl,max_steps,csv_file,'mt_q_plane_xz','ix,iz')
2870 endif
2871 end subroutine mt_q_plane_xz
2872
2873 subroutine mt_q_plane_yz(ymin,ymax,ny,zmin,zmax,nz,x0,dL, &
2874 max_steps,csv_file,b_min)
2875 ! Compute standard Cartesian logQ diagnostics on a constant-x seed plane.
2876 integer, intent(in) :: ny,nz,max_steps
2877 double precision, intent(in) :: ymin,ymax,zmin,zmax,x0,dl
2878 character(len=*), intent(in) :: csv_file
2879 double precision, intent(in), optional :: b_min
2880
2881 if (present(b_min)) then
2882 call mt_q_plane_axis(ymin,ymax,ny,zmin,zmax,nz,x0,2,3,1, &
2883 dl,max_steps,csv_file,'mt_q_plane_yz','iy,iz',b_min)
2884 else
2885 call mt_q_plane_axis(ymin,ymax,ny,zmin,zmax,nz,x0,2,3,1, &
2886 dl,max_steps,csv_file,'mt_q_plane_yz','iy,iz')
2887 endif
2888 end subroutine mt_q_plane_yz
2889
2890 subroutine mt_qperp_plane_xy(xmin,xmax,nx,ymin,ymax,ny,z0,dL, &
2891 max_steps,csv_file,b_min)
2892 ! Compute Method-II Qperp diagnostics on a constant-z source plane.
2893 integer, intent(in) :: nx,ny,max_steps
2894 double precision, intent(in) :: xmin,xmax,ymin,ymax,z0,dl
2895 character(len=*), intent(in) :: csv_file
2896 double precision, intent(in), optional :: b_min
2897
2898 if (present(b_min)) then
2899 call mt_qperp_plane_axis(xmin,xmax,nx,ymin,ymax,ny,z0,1,2,3, &
2900 dl,max_steps,csv_file,'mt_qperp_plane_xy','ix,iy',b_min)
2901 else
2902 call mt_qperp_plane_axis(xmin,xmax,nx,ymin,ymax,ny,z0,1,2,3, &
2903 dl,max_steps,csv_file,'mt_qperp_plane_xy','ix,iy')
2904 endif
2905 end subroutine mt_qperp_plane_xy
2906
2907 subroutine mt_qperp_plane_xz(xmin,xmax,nx,zmin,zmax,nz,y0,dL, &
2908 max_steps,csv_file,b_min)
2909 ! Compute Method-II Qperp diagnostics on a constant-y source plane.
2910 integer, intent(in) :: nx,nz,max_steps
2911 double precision, intent(in) :: xmin,xmax,zmin,zmax,y0,dl
2912 character(len=*), intent(in) :: csv_file
2913 double precision, intent(in), optional :: b_min
2914
2915 if (present(b_min)) then
2916 call mt_qperp_plane_axis(xmin,xmax,nx,zmin,zmax,nz,y0,1,3,2, &
2917 dl,max_steps,csv_file,'mt_qperp_plane_xz','ix,iz',b_min)
2918 else
2919 call mt_qperp_plane_axis(xmin,xmax,nx,zmin,zmax,nz,y0,1,3,2, &
2920 dl,max_steps,csv_file,'mt_qperp_plane_xz','ix,iz')
2921 endif
2922 end subroutine mt_qperp_plane_xz
2923
2924 subroutine mt_qperp_plane_yz(ymin,ymax,ny,zmin,zmax,nz,x0,dL, &
2925 max_steps,csv_file,b_min)
2926 ! Compute Method-II Qperp diagnostics on a constant-x source plane.
2927 integer, intent(in) :: ny,nz,max_steps
2928 double precision, intent(in) :: ymin,ymax,zmin,zmax,x0,dl
2929 character(len=*), intent(in) :: csv_file
2930 double precision, intent(in), optional :: b_min
2931
2932 if (present(b_min)) then
2933 call mt_qperp_plane_axis(ymin,ymax,ny,zmin,zmax,nz,x0,2,3,1, &
2934 dl,max_steps,csv_file,'mt_qperp_plane_yz','iy,iz',b_min)
2935 else
2936 call mt_qperp_plane_axis(ymin,ymax,ny,zmin,zmax,nz,x0,2,3,1, &
2937 dl,max_steps,csv_file,'mt_qperp_plane_yz','iy,iz')
2938 endif
2939 end subroutine mt_qperp_plane_yz
2940
2941 subroutine mt_qperp_plane_arbitrary(origin,e1,e2,s1min,s1max,n1, &
2942 s2min,s2max,n2,dL,max_steps,csv_file,b_min)
2943 ! Compute Method-II Qperp diagnostics on an orthonormal arbitrary plane.
2944 integer, intent(in) :: n1,n2,max_steps
2945 double precision, intent(in) :: origin(ndim),e1(ndim),e2(ndim)
2946 double precision, intent(in) :: s1min,s1max,s2min,s2max,dl
2947 character(len=*), intent(in) :: csv_file
2948 double precision, intent(in), optional :: b_min
2949
2950 type(trace_qperp_result), allocatable :: results(:)
2951 double precision, allocatable :: seeds(:,:),s1(:),s2(:)
2952 integer :: nseed
2953
2954 if (.not.mt_validate_arbitrary_plane_basis(e1,e2,s1min,s1max,n1, &
2955 s2min,s2max,n2,'mt_qperp_plane_arbitrary')) then
2956 call mt_write_qperp_arbitrary_header(csv_file, &
2957 'mt_qperp_plane_arbitrary')
2958 return
2959 endif
2960
2961 call mt_build_arbitrary_plane_seeds(origin,e1,e2,s1min,s1max,n1, &
2962 s2min,s2max,n2,seeds,s1,s2)
2963
2964 nseed=n1*n2
2965 allocate(results(nseed))
2966 if (present(b_min)) then
2967 call trace_field_qperp_multi(seeds,nseed,dl,max_steps,results,b_min)
2968 else
2969 call trace_field_qperp_multi(seeds,nseed,dl,max_steps,results)
2970 endif
2971 call mt_write_qperp_arbitrary_csv(results,s1,s2,n1,n2,csv_file, &
2972 'mt_qperp_plane_arbitrary')
2973
2974 deallocate(seeds,s1,s2,results)
2975 end subroutine mt_qperp_plane_arbitrary
2976
2977 subroutine mt_fieldline_products_plane_arbitrary(origin,e1,e2,s1min, &
2978 s1max,n1,s2min,s2max,n2,dL,max_steps,csv_file,b_min, &
2979 compute_length,compute_twist,compute_q,compute_qperp,vtu_file, &
2980 write_csv)
2981 ! Write selected per-field-line diagnostics on an arbitrary seed plane.
2982 integer, intent(in) :: n1,n2,max_steps
2983 double precision, intent(in) :: origin(ndim),e1(ndim),e2(ndim)
2984 double precision, intent(in) :: s1min,s1max,s2min,s2max,dl
2985 character(len=*), intent(in) :: csv_file
2986 double precision, intent(in), optional :: b_min
2987 logical, intent(in), optional :: compute_length,compute_twist
2988 logical, intent(in), optional :: compute_q,compute_qperp
2989 character(len=*), intent(in), optional :: vtu_file
2990 logical, intent(in), optional :: write_csv
2991
2992 type(trace_length_result), allocatable :: length_results(:)
2993 type(trace_twist_result), allocatable :: twist_results(:)
2994 type(trace_qperp_result), allocatable :: q_results(:)
2995 type(trace_qperp_result), allocatable :: qperp_results(:)
2996 double precision, allocatable :: seeds(:,:),s1(:),s2(:)
2997 integer :: nseed
2998 logical :: do_length,do_twist,do_q,do_qperp,do_csv
2999
3000 do_length=.true.
3001 do_twist=.false.
3002 do_q=.false.
3003 do_qperp=.false.
3004 do_csv=.true.
3005 if (present(compute_length)) do_length=compute_length
3006 if (present(compute_twist)) do_twist=compute_twist
3007 if (present(compute_q)) do_q=compute_q
3008 if (present(compute_qperp)) do_qperp=compute_qperp
3009 if (present(write_csv)) do_csv=write_csv
3010
3011 if (.not.mt_validate_arbitrary_plane_basis(e1,e2,s1min,s1max,n1, &
3012 s2min,s2max,n2,'mt_fieldline_products_plane_arbitrary')) then
3013 if (do_csv) then
3014 call mt_write_fieldline_products_plane_arbitrary_header(csv_file, &
3015 'mt_fieldline_products_plane_arbitrary',do_twist,do_q,do_qperp)
3016 endif
3017 if (present(vtu_file)) then
3018 if (len_trim(vtu_file)>0) then
3019 call mt_write_fieldline_products_vtu_empty(vtu_file,do_twist, &
3020 do_q,do_qperp,'mt_fieldline_products_plane_arbitrary', &
3021 do_length=do_length)
3022 endif
3023 endif
3024 return
3025 endif
3026 call mt_require_requested_science(do_length,do_twist,do_q,do_qperp, &
3027 'mt_fieldline_products_plane_arbitrary')
3028
3029 call mt_build_arbitrary_plane_seeds(origin,e1,e2,s1min,s1max,n1, &
3030 s2min,s2max,n2,seeds,s1,s2)
3031
3032 nseed=n1*n2
3033 allocate(length_results(nseed))
3034 if (do_twist) then
3035 allocate(twist_results(nseed))
3036 else
3037 allocate(twist_results(0))
3038 endif
3039 if (do_q) then
3040 allocate(q_results(nseed))
3041 else
3042 allocate(q_results(0))
3043 endif
3044 if (do_qperp) then
3045 allocate(qperp_results(nseed))
3046 else
3047 allocate(qperp_results(0))
3048 endif
3049
3050 if (present(b_min)) then
3051 call mt_trace_fieldline_products_seedset(seeds,nseed,dl,max_steps, &
3052 length_results,twist_results,q_results,qperp_results,do_twist, &
3053 do_q,do_qperp,b_min)
3054 else
3055 call mt_trace_fieldline_products_seedset(seeds,nseed,dl,max_steps, &
3056 length_results,twist_results,q_results,qperp_results,do_twist, &
3057 do_q,do_qperp)
3058 endif
3059
3060 if (do_csv) then
3061 call mt_write_fieldline_products_plane_arbitrary_csv(length_results, &
3062 twist_results,q_results,qperp_results,s1,s2,n1,n2,csv_file, &
3063 do_twist,do_q,do_qperp,'mt_fieldline_products_plane_arbitrary')
3064 endif
3065 if (present(vtu_file)) then
3066 if (len_trim(vtu_file)>0) then
3067 call mt_write_fieldline_products_vtu_plane(vtu_file, &
3068 length_results,twist_results,q_results,qperp_results,n1,n2, &
3069 do_twist,do_q,do_qperp,'mt_fieldline_products_plane_arbitrary', &
3070 do_length=do_length)
3071 endif
3072 endif
3073
3074 deallocate(qperp_results,q_results,twist_results,length_results,seeds,s1,s2)
3076
3077 subroutine mt_topology_plane_xy(xmin,xmax,nx,ymin,ymax,ny,z0,dL, &
3078 max_steps,length_csv,twist_csv,mapping_csv,b_min)
3079 ! Trace a constant-z seed plane once and write selected topology products.
3080 integer, intent(in) :: nx,ny,max_steps
3081 double precision, intent(in) :: xmin,xmax,ymin,ymax,z0,dl
3082 character(len=*), intent(in) :: length_csv,twist_csv,mapping_csv
3083 double precision, intent(in), optional :: b_min
3084
3085 if (present(b_min)) then
3086 call mt_topology_plane_axis(xmin,xmax,nx,ymin,ymax,ny,z0,1,2,3, &
3087 dl,max_steps,length_csv,twist_csv,mapping_csv, &
3088 'mt_topology_plane_xy','ix,iy','ix,iy',b_min)
3089 else
3090 call mt_topology_plane_axis(xmin,xmax,nx,ymin,ymax,ny,z0,1,2,3, &
3091 dl,max_steps,length_csv,twist_csv,mapping_csv, &
3092 'mt_topology_plane_xy','ix,iy','ix,iy')
3093 endif
3094 end subroutine mt_topology_plane_xy
3095
3096 subroutine mt_topology_plane_xz(xmin,xmax,nx,zmin,zmax,nz,y0,dL, &
3097 max_steps,length_csv,twist_csv,mapping_csv,b_min)
3098 ! Trace a constant-y seed plane once and write selected topology products.
3099 integer, intent(in) :: nx,nz,max_steps
3100 double precision, intent(in) :: xmin,xmax,zmin,zmax,y0,dl
3101 character(len=*), intent(in) :: length_csv,twist_csv,mapping_csv
3102 double precision, intent(in), optional :: b_min
3103
3104 if (present(b_min)) then
3105 call mt_topology_plane_axis(xmin,xmax,nx,zmin,zmax,nz,y0,1,3,2, &
3106 dl,max_steps,length_csv,twist_csv,mapping_csv, &
3107 'mt_topology_plane_xz','ix,iz','i,j',b_min)
3108 else
3109 call mt_topology_plane_axis(xmin,xmax,nx,zmin,zmax,nz,y0,1,3,2, &
3110 dl,max_steps,length_csv,twist_csv,mapping_csv, &
3111 'mt_topology_plane_xz','ix,iz','i,j')
3112 endif
3113 end subroutine mt_topology_plane_xz
3114
3115 subroutine mt_topology_plane_yz(ymin,ymax,ny,zmin,zmax,nz,x0,dL, &
3116 max_steps,length_csv,twist_csv,mapping_csv,b_min)
3117 ! Trace a constant-x seed plane once and write selected topology products.
3118 integer, intent(in) :: ny,nz,max_steps
3119 double precision, intent(in) :: ymin,ymax,zmin,zmax,x0,dl
3120 character(len=*), intent(in) :: length_csv,twist_csv,mapping_csv
3121 double precision, intent(in), optional :: b_min
3122
3123 if (present(b_min)) then
3124 call mt_topology_plane_axis(ymin,ymax,ny,zmin,zmax,nz,x0,2,3,1, &
3125 dl,max_steps,length_csv,twist_csv,mapping_csv, &
3126 'mt_topology_plane_yz','iy,iz','i,j',b_min)
3127 else
3128 call mt_topology_plane_axis(ymin,ymax,ny,zmin,zmax,nz,x0,2,3,1, &
3129 dl,max_steps,length_csv,twist_csv,mapping_csv, &
3130 'mt_topology_plane_yz','iy,iz','i,j')
3131 endif
3132 end subroutine mt_topology_plane_yz
3133
3134 subroutine mt_qsl_plane_vtu_xy(xmin,xmax,nx,ymin,ymax,ny,z0,dL, &
3135 max_steps,vtu_file,b_min)
3136 ! Write a full topology/QSL visualization file for a constant-z plane.
3137 integer, intent(in) :: nx,ny,max_steps
3138 double precision, intent(in) :: xmin,xmax,ymin,ymax,z0,dl
3139 character(len=*), intent(in) :: vtu_file
3140 double precision, intent(in), optional :: b_min
3141
3142 if (present(b_min)) then
3143 call mt_qsl_plane_vtu_axis(xmin,xmax,nx,ymin,ymax,ny,z0,1,2,3, &
3144 dl,max_steps,vtu_file,'mt_qsl_plane_vtu_xy',b_min)
3145 else
3146 call mt_qsl_plane_vtu_axis(xmin,xmax,nx,ymin,ymax,ny,z0,1,2,3, &
3147 dl,max_steps,vtu_file,'mt_qsl_plane_vtu_xy')
3148 endif
3149 end subroutine mt_qsl_plane_vtu_xy
3150
3151 subroutine mt_qsl_plane_vtu_xz(xmin,xmax,nx,zmin,zmax,nz,y0,dL, &
3152 max_steps,vtu_file,b_min)
3153 ! Write a full topology/QSL visualization file for a constant-y plane.
3154 integer, intent(in) :: nx,nz,max_steps
3155 double precision, intent(in) :: xmin,xmax,zmin,zmax,y0,dl
3156 character(len=*), intent(in) :: vtu_file
3157 double precision, intent(in), optional :: b_min
3158
3159 if (present(b_min)) then
3160 call mt_qsl_plane_vtu_axis(xmin,xmax,nx,zmin,zmax,nz,y0,1,3,2, &
3161 dl,max_steps,vtu_file,'mt_qsl_plane_vtu_xz',b_min)
3162 else
3163 call mt_qsl_plane_vtu_axis(xmin,xmax,nx,zmin,zmax,nz,y0,1,3,2, &
3164 dl,max_steps,vtu_file,'mt_qsl_plane_vtu_xz')
3165 endif
3166 end subroutine mt_qsl_plane_vtu_xz
3167
3168 subroutine mt_qsl_plane_vtu_yz(ymin,ymax,ny,zmin,zmax,nz,x0,dL, &
3169 max_steps,vtu_file,b_min)
3170 ! Write a full topology/QSL visualization file for a constant-x plane.
3171 integer, intent(in) :: ny,nz,max_steps
3172 double precision, intent(in) :: ymin,ymax,zmin,zmax,x0,dl
3173 character(len=*), intent(in) :: vtu_file
3174 double precision, intent(in), optional :: b_min
3175
3176 if (present(b_min)) then
3177 call mt_qsl_plane_vtu_axis(ymin,ymax,ny,zmin,zmax,nz,x0,2,3,1, &
3178 dl,max_steps,vtu_file,'mt_qsl_plane_vtu_yz',b_min)
3179 else
3180 call mt_qsl_plane_vtu_axis(ymin,ymax,ny,zmin,zmax,nz,x0,2,3,1, &
3181 dl,max_steps,vtu_file,'mt_qsl_plane_vtu_yz')
3182 endif
3183 end subroutine mt_qsl_plane_vtu_yz
3184
3185 subroutine mt_qsl_plane_vti_xy(xmin,xmax,nx,ymin,ymax,ny,z0,dL, &
3186 max_steps,vti_file,do_length,do_twist,do_q,do_qperp,b_min)
3187 ! Write requested minimal science arrays for a constant-z plane as VTI.
3188 integer, intent(in) :: nx,ny,max_steps
3189 double precision, intent(in) :: xmin,xmax,ymin,ymax,z0,dl
3190 character(len=*), intent(in) :: vti_file
3191 logical, intent(in) :: do_length,do_twist,do_q,do_qperp
3192 double precision, intent(in), optional :: b_min
3193
3194 if (present(b_min)) then
3195 call mt_qsl_plane_vti_axis(xmin,xmax,nx,ymin,ymax,ny,z0, &
3196 1,2,3,dl,max_steps,vti_file,do_twist,do_q,do_qperp, &
3197 'mt_qsl_plane_vti_xy',b_min,do_length=do_length)
3198 else
3199 call mt_qsl_plane_vti_axis(xmin,xmax,nx,ymin,ymax,ny,z0, &
3200 1,2,3,dl,max_steps,vti_file,do_twist,do_q,do_qperp, &
3201 'mt_qsl_plane_vti_xy',do_length=do_length)
3202 endif
3203 end subroutine mt_qsl_plane_vti_xy
3204
3205 subroutine mt_qsl_plane_vti_xz(xmin,xmax,nx,zmin,zmax,nz,y0,dL, &
3206 max_steps,vti_file,do_length,do_twist,do_q,do_qperp,b_min)
3207 ! Write requested minimal science arrays for a constant-y plane as VTI.
3208 integer, intent(in) :: nx,nz,max_steps
3209 double precision, intent(in) :: xmin,xmax,zmin,zmax,y0,dl
3210 character(len=*), intent(in) :: vti_file
3211 logical, intent(in) :: do_length,do_twist,do_q,do_qperp
3212 double precision, intent(in), optional :: b_min
3213
3214 if (present(b_min)) then
3215 call mt_qsl_plane_vti_axis(xmin,xmax,nx,zmin,zmax,nz,y0, &
3216 1,3,2,dl,max_steps,vti_file,do_twist,do_q,do_qperp, &
3217 'mt_qsl_plane_vti_xz',b_min,do_length=do_length)
3218 else
3219 call mt_qsl_plane_vti_axis(xmin,xmax,nx,zmin,zmax,nz,y0, &
3220 1,3,2,dl,max_steps,vti_file,do_twist,do_q,do_qperp, &
3221 'mt_qsl_plane_vti_xz',do_length=do_length)
3222 endif
3223 end subroutine mt_qsl_plane_vti_xz
3224
3225 subroutine mt_qsl_plane_vti_yz(ymin,ymax,ny,zmin,zmax,nz,x0,dL, &
3226 max_steps,vti_file,do_length,do_twist,do_q,do_qperp,b_min)
3227 ! Write requested minimal science arrays for a constant-x plane as VTI.
3228 integer, intent(in) :: ny,nz,max_steps
3229 double precision, intent(in) :: ymin,ymax,zmin,zmax,x0,dl
3230 character(len=*), intent(in) :: vti_file
3231 logical, intent(in) :: do_length,do_twist,do_q,do_qperp
3232 double precision, intent(in), optional :: b_min
3233
3234 if (present(b_min)) then
3235 call mt_qsl_plane_vti_axis(ymin,ymax,ny,zmin,zmax,nz,x0, &
3236 2,3,1,dl,max_steps,vti_file,do_twist,do_q,do_qperp, &
3237 'mt_qsl_plane_vti_yz',b_min,do_length=do_length)
3238 else
3239 call mt_qsl_plane_vti_axis(ymin,ymax,ny,zmin,zmax,nz,x0, &
3240 2,3,1,dl,max_steps,vti_file,do_twist,do_q,do_qperp, &
3241 'mt_qsl_plane_vti_yz',do_length=do_length)
3242 endif
3243 end subroutine mt_qsl_plane_vti_yz
3244
3245 subroutine mt_write_cartesian_vti_pointdata(vti_file,xmin,xmax,nx, &
3246 ymin,ymax,ny,zmin,zmax,nz,length_total,qperp,status)
3247 ! Low-level appended-binary VTI writer for future uniform seed-volume
3248 ! products. PointData values use i-fastest ordering:
3249 ! ipoint = (k-1)*nx*ny + (j-1)*nx + i.
3250 character(len=*), intent(in) :: vti_file
3251 integer, intent(in) :: nx,ny,nz
3252 double precision, intent(in) :: xmin,xmax,ymin,ymax,zmin,zmax
3253 double precision, intent(in) :: length_total(:),qperp(:)
3254 integer, intent(in) :: status(:)
3255
3256 integer :: npoint
3257 double precision :: origin(3),spacing(3)
3258
3259 if (len_trim(vti_file)==0) then
3260 call mpistop('mt_write_cartesian_vti_pointdata requires a VTI file')
3261 endif
3262 if (nx<=0 .or. ny<=0 .or. nz<=0) then
3263 call mpistop('mt_write_cartesian_vti_pointdata requires positive dimensions')
3264 endif
3265
3266 npoint=nx*ny*nz
3267 if (size(length_total)/=npoint .or. size(qperp)/=npoint .or. &
3268 size(status)/=npoint) then
3269 call mpistop('mt_write_cartesian_vti_pointdata array size mismatch')
3270 endif
3271
3272 origin=(/ xmin,ymin,zmin /)
3273 spacing(1)=mt_vti_axis_spacing(xmin,xmax,nx)
3274 spacing(2)=mt_vti_axis_spacing(ymin,ymax,ny)
3275 spacing(3)=mt_vti_axis_spacing(zmin,zmax,nz)
3276 call mt_write_vti_pointdata_fixed(vti_file,origin,spacing,nx,ny,nz, &
3277 length_total,qperp,status,'mt_write_cartesian_vti_pointdata')
3279
3280 subroutine mt_fieldline_products_volume_vti(xmin,xmax,nx, &
3281 ymin,ymax,ny,zmin,zmax,nz,dL,max_steps,vti_file,b_min, &
3282 compute_length,compute_twist,compute_q,compute_qperp,chunk_nz)
3283 ! Compute per-seed field-line products on a user-defined uniform
3284 ! Cartesian sampling volume and write PointData to appended-binary VTI.
3285 integer, intent(in) :: nx,ny,nz,max_steps
3286 double precision, intent(in) :: xmin,xmax,ymin,ymax,zmin,zmax,dl
3287 character(len=*), intent(in) :: vti_file
3288 double precision, intent(in), optional :: b_min
3289 logical, intent(in), optional :: compute_length,compute_twist
3290 logical, intent(in), optional :: compute_q,compute_qperp
3291 integer, intent(in), optional :: chunk_nz
3292
3293 type(trace_length_result), allocatable :: length_slab(:)
3294 type(trace_twist_result), allocatable :: twist_slab(:)
3295 type(trace_qperp_result), allocatable :: q_slab(:)
3296 type(trace_qperp_result), allocatable :: qperp_slab(:)
3297 type(mt_volume_products) :: products
3298 double precision, allocatable :: seeds_slab(:,:)
3299 double precision :: origin(3),spacing(3)
3300 integer :: k_start,k_end,slab_nz,slab_nseed,nseed
3301 integer :: chunk_nz_eff
3302 integer(kind=8) :: nseed64
3303 logical :: do_length,do_twist,do_q,do_qperp
3304
3305 if (len_trim(vti_file)==0) then
3306 call mpistop('mt_fieldline_products_volume_vti requires a VTI file')
3307 endif
3308 if (npe/=1) then
3309 call mpistop('mt_fieldline_products_volume_vti currently requires npe=1')
3310 endif
3311 if (ndim/=3) then
3312 call mpistop('mt_fieldline_products_volume_vti requires 3D Cartesian geometry')
3313 endif
3314 {^ifthreed
3315 select case (geo_coordinate)
3316 case (geo_cartesian)
3317 ! The output VTI is a user-defined sampling lattice; RK2 tracing can
3318 ! interpolate through either slab-uniform or AMR Cartesian grids.
3319 case (geo_cartesian_stretched)
3320 case default
3321 call mpistop('volume_vti requires Cartesian geometry')
3322 end select
3323 }
3324 if (nx<=0 .or. ny<=0 .or. nz<=0) then
3325 call mpistop('mt_fieldline_products_volume_vti requires positive dimensions')
3326 endif
3327 if (xmax<xmin .or. ymax<ymin .or. zmax<zmin) then
3328 call mpistop('mt_fieldline_products_volume_vti requires ordered bounds')
3329 endif
3330
3331 nseed64=int(nx,kind=8)*int(ny,kind=8)*int(nz,kind=8)
3332 if (nseed64>int(huge(nseed),kind=8)) then
3333 call mpistop('mt_fieldline_products_volume_vti seed count overflows integer')
3334 endif
3335 if (nseed64>1000000_8) then
3336 write(*,'(a,i0,a)') &
3337 'mt_fieldline_products_volume_vti warning: volume has ', &
3338 nseed64,' seeds; final VTI arrays still scale with nseed'
3339 endif
3340 nseed=int(nseed64)
3341
3342 do_length=.true.
3343 do_twist=.false.
3344 do_q=.false.
3345 do_qperp=.false.
3346 if (present(compute_length)) do_length=compute_length
3347 if (present(compute_twist)) do_twist=compute_twist
3348 if (present(compute_q)) do_q=compute_q
3349 if (present(compute_qperp)) do_qperp=compute_qperp
3350 call mt_require_requested_science(do_length,do_twist,do_q,do_qperp, &
3351 'mt_fieldline_products_volume_vti')
3352
3353 chunk_nz_eff=nz
3354 if (present(chunk_nz)) chunk_nz_eff=max(1,min(nz,chunk_nz))
3355
3356 origin=(/ xmin,ymin,zmin /)
3357 spacing(1)=mt_vti_axis_spacing(xmin,xmax,nx)
3358 spacing(2)=mt_vti_axis_spacing(ymin,ymax,ny)
3359 spacing(3)=mt_vti_axis_spacing(zmin,zmax,nz)
3360
3361 call mt_allocate_volume_products(products,nseed,do_twist,do_q,do_qperp)
3362
3363 do k_start=1,nz,chunk_nz_eff
3364 k_end=min(nz,k_start+chunk_nz_eff-1)
3365 slab_nz=k_end-k_start+1
3366 slab_nseed=nx*ny*slab_nz
3367
3368 allocate(seeds_slab(slab_nseed,ndim))
3369 call mt_build_volume_slab_seeds(seeds_slab,xmin,ymin,zmin, &
3370 spacing,nx,ny,k_start,slab_nz)
3371
3372 allocate(length_slab(slab_nseed))
3373 if (do_twist) then
3374 allocate(twist_slab(slab_nseed))
3375 else
3376 allocate(twist_slab(0))
3377 endif
3378 if (do_q) then
3379 allocate(q_slab(slab_nseed))
3380 else
3381 allocate(q_slab(0))
3382 endif
3383
3384 if (do_qperp) then
3385 allocate(qperp_slab(slab_nseed))
3386 else
3387 allocate(qperp_slab(0))
3388 endif
3389
3390 if (present(b_min)) then
3391 call mt_trace_fieldline_products_seedset(seeds_slab,slab_nseed, &
3392 dl,max_steps,length_slab,twist_slab,q_slab,qperp_slab, &
3393 do_twist,do_q,do_qperp,b_min)
3394 else
3395 call mt_trace_fieldline_products_seedset(seeds_slab,slab_nseed, &
3396 dl,max_steps,length_slab,twist_slab,q_slab,qperp_slab, &
3397 do_twist,do_q,do_qperp)
3398 endif
3399
3400 call mt_copy_volume_length_slab(products,length_slab,nx,ny, &
3401 k_start,slab_nz)
3402 deallocate(length_slab)
3403
3404 if (do_twist) then
3405 call mt_copy_volume_twist_slab(products,twist_slab,nx,ny, &
3406 k_start,slab_nz)
3407 endif
3408 deallocate(twist_slab)
3409
3410 if (do_q) then
3411 call mt_copy_volume_q_slab(products,q_slab,nx,ny,k_start,slab_nz)
3412 endif
3413 deallocate(q_slab)
3414
3415 if (do_qperp) then
3416 call mt_copy_volume_qperp_slab(products,qperp_slab,nx,ny, &
3417 k_start,slab_nz)
3418 endif
3419 deallocate(qperp_slab)
3420
3421 deallocate(seeds_slab)
3422 enddo
3423
3424 call mt_write_fieldline_products_volume_vti(vti_file,origin,spacing, &
3425 nx,ny,nz,products, &
3426 do_length,do_twist,do_q,do_qperp,'mt_fieldline_products_volume_vti')
3427 call mt_deallocate_volume_products(products)
3429
3430 subroutine mt_trace_fieldline_products_seedset(seeds,nseed,dL,max_steps, &
3431 length_results,twist_results,q_results,qperp_results,do_twist, &
3432 do_q,do_qperp,b_min)
3433 integer, intent(in) :: nseed,max_steps
3434 double precision, intent(in) :: seeds(nseed,ndim),dl
3435 type(trace_length_result), intent(out) :: length_results(nseed)
3436 type(trace_twist_result), intent(out) :: twist_results(:)
3437 type(trace_qperp_result), intent(out) :: q_results(:)
3438 type(trace_qperp_result), intent(out) :: qperp_results(:)
3439 logical, intent(in) :: do_twist,do_q,do_qperp
3440 double precision, intent(in), optional :: b_min
3441
3442 type(trace_topology_result) :: topology_one(1)
3443 double precision :: seed_local(ndim),seed_one(1,ndim)
3444 integer :: iseed
3445 character(len=mt_task_name_len) :: integrator
3446
3447 integrator=mt_lowercase(trim(mt_trace_integrator))
3448 if (do_q .and. do_qperp .and. geo_coordinate==geo_spherical .and. &
3449 (integrator=='rk2' .or. integrator=='rk45_spherical')) then
3450 if (do_twist) then
3451 if (present(b_min)) then
3452 call trace_field_spherical_rmin_q_qperp_multi(seeds,nseed,dl, &
3453 max_steps,q_results,qperp_results,b_min, &
3454 twist_results=twist_results)
3455 else
3456 call trace_field_spherical_rmin_q_qperp_multi(seeds,nseed,dl, &
3457 max_steps,q_results,qperp_results, &
3458 twist_results=twist_results)
3459 endif
3460 else
3461 if (present(b_min)) then
3462 call trace_field_spherical_rmin_q_qperp_multi(seeds,nseed,dl, &
3463 max_steps,q_results,qperp_results,b_min)
3464 else
3465 call trace_field_spherical_rmin_q_qperp_multi(seeds,nseed,dl, &
3466 max_steps,q_results,qperp_results)
3467 endif
3468 endif
3469 call mt_q0_trace_to_length(q_results,nseed,length_results)
3470 return
3471 endif
3472
3473 if (do_q .and. do_qperp .and. geo_coordinate/=geo_spherical .and. &
3474 (integrator=='rk2' .or. integrator=='rk45_cartesian')) then
3475 if (do_twist) then
3476 if (present(b_min)) then
3477 call trace_field_qperp_multi(seeds,nseed,dl,max_steps, &
3478 qperp_results,b_min,twist_results=twist_results)
3479 else
3480 call trace_field_qperp_multi(seeds,nseed,dl,max_steps, &
3481 qperp_results,twist_results=twist_results)
3482 endif
3483 else
3484 if (present(b_min)) then
3485 call trace_field_qperp_multi(seeds,nseed,dl,max_steps, &
3486 qperp_results,b_min)
3487 else
3488 call trace_field_qperp_multi(seeds,nseed,dl,max_steps, &
3489 qperp_results)
3490 endif
3491 endif
3492 q_results=qperp_results
3493 call mt_qperp_trace_to_length(qperp_results,nseed,length_results)
3494 return
3495 endif
3496
3497 if (do_qperp .and. .not.do_q .and. &
3498 (integrator=='rk2' .or. &
3499 (integrator=='rk45_cartesian' .and. geo_coordinate/=geo_spherical) &
3500 .or. (integrator=='rk45_spherical' .and. &
3501 geo_coordinate==geo_spherical))) then
3502 select case (geo_coordinate)
3503 case (geo_spherical)
3504 if (do_twist) then
3505 if (present(b_min)) then
3506 call trace_field_spherical_qperp_multi(seeds,nseed,dl,max_steps, &
3507 qperp_results,b_min,twist_results=twist_results)
3508 else
3509 call trace_field_spherical_qperp_multi(seeds,nseed,dl,max_steps, &
3510 qperp_results,twist_results=twist_results)
3511 endif
3512 else
3513 if (present(b_min)) then
3514 call trace_field_spherical_qperp_multi(seeds,nseed,dl,max_steps, &
3515 qperp_results,b_min)
3516 else
3517 call trace_field_spherical_qperp_multi(seeds,nseed,dl,max_steps, &
3518 qperp_results)
3519 endif
3520 endif
3521 case default
3522 if (do_twist) then
3523 if (present(b_min)) then
3524 call trace_field_qperp_multi(seeds,nseed,dl,max_steps, &
3525 qperp_results,b_min,twist_results=twist_results)
3526 else
3527 call trace_field_qperp_multi(seeds,nseed,dl,max_steps, &
3528 qperp_results,twist_results=twist_results)
3529 endif
3530 else
3531 if (present(b_min)) then
3532 call trace_field_qperp_multi(seeds,nseed,dl,max_steps, &
3533 qperp_results,b_min)
3534 else
3535 call trace_field_qperp_multi(seeds,nseed,dl,max_steps, &
3536 qperp_results)
3537 endif
3538 endif
3539 end select
3540 call mt_qperp_trace_to_length(qperp_results,nseed,length_results)
3541 return
3542 endif
3543
3544 if (do_q .and. .not.do_qperp .and. geo_coordinate==geo_spherical .and. &
3545 (integrator=='rk2' .or. integrator=='rk45_spherical')) then
3546 if (do_twist) then
3547 if (present(b_min)) then
3548 call trace_field_spherical_rmin_q_multi(seeds,nseed,dl,max_steps, &
3549 q_results,b_min,twist_results=twist_results)
3550 else
3551 call trace_field_spherical_rmin_q_multi(seeds,nseed,dl,max_steps, &
3552 q_results,twist_results=twist_results)
3553 endif
3554 else
3555 if (present(b_min)) then
3556 call trace_field_spherical_rmin_q_multi(seeds,nseed,dl,max_steps, &
3557 q_results,b_min)
3558 else
3559 call trace_field_spherical_rmin_q_multi(seeds,nseed,dl,max_steps, &
3560 q_results)
3561 endif
3562 endif
3563 call mt_q0_trace_to_length(q_results,nseed,length_results)
3564 return
3565 endif
3566
3567 if (do_q .and. .not.do_qperp .and. &
3568 (integrator=='rk2' .or. &
3569 (integrator=='rk45_cartesian' .and. geo_coordinate/=geo_spherical) &
3570 .or. (integrator=='rk45_spherical' .and. &
3571 geo_coordinate==geo_spherical))) then
3572 if (integrator=='rk2') then
3573 if (geo_coordinate==geo_cartesian_stretched .or. &
3574 (geo_coordinate==geo_cartesian .and. .not.slab_uniform)) then
3575 if (do_twist) then
3576 if (present(b_min)) then
3577 call trace_field_qperp_multi(seeds,nseed,dl,max_steps, &
3578 q_results,b_min,twist_results=twist_results)
3579 else
3580 call trace_field_qperp_multi(seeds,nseed,dl,max_steps, &
3581 q_results,twist_results=twist_results)
3582 endif
3583 else
3584 if (present(b_min)) then
3585 call trace_field_qperp_multi(seeds,nseed,dl,max_steps, &
3586 q_results,b_min)
3587 else
3588 call trace_field_qperp_multi(seeds,nseed,dl,max_steps, &
3589 q_results)
3590 endif
3591 endif
3592 else
3593 if (do_twist) then
3594 if (present(b_min)) then
3595 call trace_field_rk2_short_boundary_q_multi(seeds,nseed,dl, &
3596 max_steps,q_results,b_min,twist_results=twist_results)
3597 else
3598 call trace_field_rk2_short_boundary_q_multi(seeds,nseed,dl, &
3599 max_steps,q_results,twist_results=twist_results)
3600 endif
3601 else
3602 if (present(b_min)) then
3603 call trace_field_rk2_short_boundary_q_multi(seeds,nseed,dl, &
3604 max_steps,q_results,b_min)
3605 else
3606 call trace_field_rk2_short_boundary_q_multi(seeds,nseed,dl, &
3607 max_steps,q_results)
3608 endif
3609 endif
3610 endif
3611 else if (integrator=='rk45_cartesian') then
3612 if (do_twist) then
3613 if (present(b_min)) then
3614 call trace_field_qperp_multi(seeds,nseed,dl,max_steps, &
3615 q_results,b_min,twist_results=twist_results)
3616 else
3617 call trace_field_qperp_multi(seeds,nseed,dl,max_steps, &
3618 q_results,twist_results=twist_results)
3619 endif
3620 else
3621 if (present(b_min)) then
3622 call trace_field_qperp_multi(seeds,nseed,dl,max_steps, &
3623 q_results,b_min)
3624 else
3625 call trace_field_qperp_multi(seeds,nseed,dl,max_steps,q_results)
3626 endif
3627 endif
3628 else
3629 if (do_twist) then
3630 if (present(b_min)) then
3631 call trace_field_spherical_rmin_q_multi(seeds,nseed,dl, &
3632 max_steps,q_results,b_min,twist_results=twist_results)
3633 else
3634 call trace_field_spherical_rmin_q_multi(seeds,nseed,dl, &
3635 max_steps,q_results,twist_results=twist_results)
3636 endif
3637 else
3638 if (present(b_min)) then
3639 call trace_field_spherical_rmin_q_multi(seeds,nseed,dl, &
3640 max_steps,q_results,b_min)
3641 else
3642 call trace_field_spherical_rmin_q_multi(seeds,nseed,dl, &
3643 max_steps,q_results)
3644 endif
3645 endif
3646 endif
3647 call mt_q0_trace_to_length(q_results,nseed,length_results)
3648 return
3649 endif
3650
3651 if (present(b_min)) then
3652 !$OMP PARALLEL DO DEFAULT(SHARED) PRIVATE(iseed,seed_local,seed_one,topology_one) SCHEDULE(DYNAMIC,16)
3653 do iseed=1,nseed
3654 seed_local=seeds(iseed,:)
3655 if (do_twist) then
3656 seed_one(1,:)=seed_local
3657 call trace_field_topology_multi(seed_one,1,dl,max_steps, &
3658 topology_one,need_twist=.true.,need_mapping=.false., &
3659 b_min=b_min)
3660 call mt_topology_to_length(topology_one,1, &
3661 length_results(iseed:iseed))
3662 call mt_topology_to_twist(topology_one,1, &
3663 twist_results(iseed:iseed))
3664 else
3665 call trace_field_length_single(seed_local,dl,max_steps, &
3666 length_results(iseed),b_min)
3667 endif
3668 if (do_qperp) then
3669 call trace_field_qperp_single(seed_local,dl,max_steps, &
3670 qperp_results(iseed),b_min)
3671 endif
3672 enddo
3673 !$OMP END PARALLEL DO
3674 else
3675 !$OMP PARALLEL DO DEFAULT(SHARED) PRIVATE(iseed,seed_local,seed_one,topology_one) SCHEDULE(DYNAMIC,16)
3676 do iseed=1,nseed
3677 seed_local=seeds(iseed,:)
3678 if (do_twist) then
3679 seed_one(1,:)=seed_local
3680 call trace_field_topology_multi(seed_one,1,dl,max_steps, &
3681 topology_one,need_twist=.true.,need_mapping=.false.)
3682 call mt_topology_to_length(topology_one,1, &
3683 length_results(iseed:iseed))
3684 call mt_topology_to_twist(topology_one,1, &
3685 twist_results(iseed:iseed))
3686 else
3687 call trace_field_length_single(seed_local,dl,max_steps, &
3688 length_results(iseed))
3689 endif
3690 if (do_qperp) then
3691 call trace_field_qperp_single(seed_local,dl,max_steps, &
3692 qperp_results(iseed))
3693 endif
3694 enddo
3695 !$OMP END PARALLEL DO
3696 endif
3697
3698 if (do_q) then
3699 if (mt_lowercase(trim(mt_trace_integrator))=='rk45_cartesian') then
3700 if (present(b_min)) then
3701 call trace_field_qperp_multi(seeds,nseed,dl,max_steps,q_results, &
3702 b_min)
3703 else
3704 call trace_field_qperp_multi(seeds,nseed,dl,max_steps,q_results)
3705 endif
3706 else if (geo_coordinate==geo_spherical) then
3707 if (present(b_min)) then
3708 call trace_field_spherical_rmin_q_multi(seeds,nseed,dl, &
3709 max_steps,q_results,b_min)
3710 else
3711 call trace_field_spherical_rmin_q_multi(seeds,nseed,dl, &
3712 max_steps,q_results)
3713 endif
3714 else if (do_qperp) then
3715 q_results=qperp_results
3716 else
3717 if (present(b_min)) then
3718 call trace_field_qperp_multi(seeds,nseed,dl,max_steps,q_results, &
3719 b_min)
3720 else
3721 call trace_field_qperp_multi(seeds,nseed,dl,max_steps,q_results)
3722 endif
3723 endif
3724 endif
3725 end subroutine mt_trace_fieldline_products_seedset
3726
3727 subroutine mt_twist_single(seed,dL,max_steps,csv_file,b_min)
3728 ! Trace one magnetic field line and write its length and twist summary.
3729 double precision, intent(in) :: seed(ndim),dl
3730 integer, intent(in) :: max_steps
3731 character(len=*), intent(in) :: csv_file
3732 double precision, intent(in), optional :: b_min
3733
3734 type(trace_twist_result) :: result
3735 double precision :: seed_xyz(3)
3736 integer :: csv_unit,io_status
3737
3738 if (npe/=1) then
3739 call mpistop('mt_twist_single currently requires npe=1')
3740 endif
3741 if (ndim/=3 .or. .not.slab_uniform) then
3742 call mpistop('mt_twist_single requires 3D uniform Cartesian geometry')
3743 endif
3744
3745 if (present(b_min)) then
3746 call trace_field_twist_single(seed,dl,max_steps,result,b_min)
3747 else
3748 call trace_field_twist_single(seed,dl,max_steps,result)
3749 endif
3750
3751 seed_xyz=0.d0
3752 seed_xyz(1:ndim)=result%line%seed
3753
3754 open(newunit=csv_unit,file=trim(csv_file),status='replace', &
3755 action='write',form='formatted',iostat=io_status)
3756 if (io_status/=0) then
3757 call mpistop('mt_twist_single could not open CSV file')
3758 endif
3759
3760 write(csv_unit,'(a)',iostat=io_status) &
3761 'seed_id,seed_x,seed_y,seed_z,'// &
3762 'length_total,length_backward,length_forward,'// &
3763 'twist_total,twist_backward,twist_forward,'// &
3764 'nstep_backward,nstep_forward,'// &
3765 'status_backward,status_forward'
3766 if (io_status/=0) then
3767 close(csv_unit)
3768 call mpistop('mt_twist_single could not write CSV header')
3769 endif
3770
3771 write(csv_unit,'(i0,9(",",es24.16),4(",",i0))',iostat=io_status) &
3772 1,seed_xyz,result%line%total_length, &
3773 result%line%backward_length,result%line%forward_length, &
3774 result%total_twist,result%backward_twist,result%forward_twist, &
3775 result%line%backward_nstep,result%line%forward_nstep, &
3776 result%line%backward_status,result%line%forward_status
3777 if (io_status/=0) then
3778 close(csv_unit)
3779 call mpistop('mt_twist_single could not write CSV data')
3780 endif
3781
3782 close(csv_unit)
3783 end subroutine mt_twist_single
3784
3785 subroutine mt_twist_seeds(seeds,nseed,dL,max_steps,csv_file,b_min)
3786 ! Trace multiple magnetic field lines and write length and twist summaries.
3787 integer, intent(in) :: nseed,max_steps
3788 double precision, intent(in) :: seeds(nseed,ndim),dl
3789 character(len=*), intent(in) :: csv_file
3790 double precision, intent(in), optional :: b_min
3791
3792 type(trace_twist_result), allocatable :: results(:)
3793 double precision :: seed_xyz(3)
3794 integer :: csv_unit,io_status,iseed
3795
3796 if (npe/=1) then
3797 call mpistop('mt_twist_seeds currently requires npe=1')
3798 endif
3799 if (ndim/=3 .or. .not.slab_uniform) then
3800 call mpistop('mt_twist_seeds requires 3D uniform Cartesian geometry')
3801 endif
3802 if (nseed<0) then
3803 call mpistop('mt_twist_seeds requires nseed>=0')
3804 endif
3805
3806 allocate(results(nseed))
3807 if (present(b_min)) then
3808 call trace_field_twist_multi(seeds,nseed,dl,max_steps,results,b_min)
3809 else
3810 call trace_field_twist_multi(seeds,nseed,dl,max_steps,results)
3811 endif
3812
3813 open(newunit=csv_unit,file=trim(csv_file),status='replace', &
3814 action='write',form='formatted',iostat=io_status)
3815 if (io_status/=0) then
3816 deallocate(results)
3817 call mpistop('mt_twist_seeds could not open CSV file')
3818 endif
3819
3820 write(csv_unit,'(a)',iostat=io_status) &
3821 'seed_id,seed_x,seed_y,seed_z,'// &
3822 'length_total,length_backward,length_forward,'// &
3823 'twist_total,twist_backward,twist_forward,'// &
3824 'nstep_backward,nstep_forward,'// &
3825 'status_backward,status_forward'
3826 if (io_status/=0) then
3827 close(csv_unit)
3828 deallocate(results)
3829 call mpistop('mt_twist_seeds could not write CSV header')
3830 endif
3831
3832 do iseed=1,nseed
3833 seed_xyz=0.d0
3834 seed_xyz(1:ndim)=results(iseed)%line%seed
3835 write(csv_unit,'(i0,9(",",es24.16),4(",",i0))',iostat=io_status) &
3836 iseed,seed_xyz,results(iseed)%line%total_length, &
3837 results(iseed)%line%backward_length, &
3838 results(iseed)%line%forward_length, &
3839 results(iseed)%total_twist,results(iseed)%backward_twist, &
3840 results(iseed)%forward_twist, &
3841 results(iseed)%line%backward_nstep, &
3842 results(iseed)%line%forward_nstep, &
3843 results(iseed)%line%backward_status, &
3844 results(iseed)%line%forward_status
3845 if (io_status/=0) then
3846 close(csv_unit)
3847 deallocate(results)
3848 call mpistop('mt_twist_seeds could not write CSV data')
3849 endif
3850 enddo
3851
3852 close(csv_unit)
3853 deallocate(results)
3854 end subroutine mt_twist_seeds
3855
3856 subroutine mt_twist_plane_xy(xmin,xmax,nx,ymin,ymax,ny,z0,dL, &
3857 max_steps,csv_file,b_min)
3858 ! Trace a uniform seed grid on a constant-z plane and write twist summaries.
3859 integer, intent(in) :: nx,ny,max_steps
3860 double precision, intent(in) :: xmin,xmax,ymin,ymax,z0,dl
3861 character(len=*), intent(in) :: csv_file
3862 double precision, intent(in), optional :: b_min
3863
3864 if (present(b_min)) then
3865 call mt_twist_plane_axis(xmin,xmax,nx,ymin,ymax,ny,z0,1,2,3, &
3866 dl,max_steps,csv_file,'mt_twist_plane_xy','ix,iy',b_min)
3867 else
3868 call mt_twist_plane_axis(xmin,xmax,nx,ymin,ymax,ny,z0,1,2,3, &
3869 dl,max_steps,csv_file,'mt_twist_plane_xy','ix,iy')
3870 endif
3871 end subroutine mt_twist_plane_xy
3872
3873 subroutine mt_length_plane_xz(xmin,xmax,nx,zmin,zmax,nz,y0,dL, &
3874 max_steps,csv_file,b_min)
3875 integer, intent(in) :: nx,nz,max_steps
3876 double precision, intent(in) :: xmin,xmax,zmin,zmax,y0,dl
3877 character(len=*), intent(in) :: csv_file
3878 double precision, intent(in), optional :: b_min
3879
3880 if (present(b_min)) then
3881 call mt_length_plane_axis(xmin,xmax,nx,zmin,zmax,nz,y0,1,3,2, &
3882 dl,max_steps,csv_file,'mt_length_plane_xz','i,j',b_min)
3883 else
3884 call mt_length_plane_axis(xmin,xmax,nx,zmin,zmax,nz,y0,1,3,2, &
3885 dl,max_steps,csv_file,'mt_length_plane_xz','i,j')
3886 endif
3887 end subroutine mt_length_plane_xz
3888
3889 subroutine mt_length_plane_yz(ymin,ymax,ny,zmin,zmax,nz,x0,dL, &
3890 max_steps,csv_file,b_min)
3891 integer, intent(in) :: ny,nz,max_steps
3892 double precision, intent(in) :: ymin,ymax,zmin,zmax,x0,dl
3893 character(len=*), intent(in) :: csv_file
3894 double precision, intent(in), optional :: b_min
3895
3896 if (present(b_min)) then
3897 call mt_length_plane_axis(ymin,ymax,ny,zmin,zmax,nz,x0,2,3,1, &
3898 dl,max_steps,csv_file,'mt_length_plane_yz','i,j',b_min)
3899 else
3900 call mt_length_plane_axis(ymin,ymax,ny,zmin,zmax,nz,x0,2,3,1, &
3901 dl,max_steps,csv_file,'mt_length_plane_yz','i,j')
3902 endif
3903 end subroutine mt_length_plane_yz
3904
3905 subroutine mt_twist_plane_xz(xmin,xmax,nx,zmin,zmax,nz,y0,dL, &
3906 max_steps,csv_file,b_min)
3907 integer, intent(in) :: nx,nz,max_steps
3908 double precision, intent(in) :: xmin,xmax,zmin,zmax,y0,dl
3909 character(len=*), intent(in) :: csv_file
3910 double precision, intent(in), optional :: b_min
3911
3912 if (present(b_min)) then
3913 call mt_twist_plane_axis(xmin,xmax,nx,zmin,zmax,nz,y0,1,3,2, &
3914 dl,max_steps,csv_file,'mt_twist_plane_xz','i,j',b_min)
3915 else
3916 call mt_twist_plane_axis(xmin,xmax,nx,zmin,zmax,nz,y0,1,3,2, &
3917 dl,max_steps,csv_file,'mt_twist_plane_xz','i,j')
3918 endif
3919 end subroutine mt_twist_plane_xz
3920
3921 subroutine mt_twist_plane_yz(ymin,ymax,ny,zmin,zmax,nz,x0,dL, &
3922 max_steps,csv_file,b_min)
3923 integer, intent(in) :: ny,nz,max_steps
3924 double precision, intent(in) :: ymin,ymax,zmin,zmax,x0,dl
3925 character(len=*), intent(in) :: csv_file
3926 double precision, intent(in), optional :: b_min
3927
3928 if (present(b_min)) then
3929 call mt_twist_plane_axis(ymin,ymax,ny,zmin,zmax,nz,x0,2,3,1, &
3930 dl,max_steps,csv_file,'mt_twist_plane_yz','i,j',b_min)
3931 else
3932 call mt_twist_plane_axis(ymin,ymax,ny,zmin,zmax,nz,x0,2,3,1, &
3933 dl,max_steps,csv_file,'mt_twist_plane_yz','i,j')
3934 endif
3935 end subroutine mt_twist_plane_yz
3936
3937 subroutine mt_length_plane_axis(c1min,c1max,n1,c2min,c2max,n2, &
3938 fixed_value,axis1,axis2,fixed_axis,dL,max_steps,csv_file, &
3939 caller,index_header,b_min)
3940 integer, intent(in) :: n1,n2,axis1,axis2,fixed_axis,max_steps
3941 double precision, intent(in) :: c1min,c1max,c2min,c2max
3942 double precision, intent(in) :: fixed_value,dl
3943 character(len=*), intent(in) :: csv_file,caller,index_header
3944 double precision, intent(in), optional :: b_min
3945
3946 type(trace_length_result), allocatable :: results(:)
3947 double precision, allocatable :: seeds(:,:)
3948 integer :: nseed
3949
3950 call mt_validate_axis_plane(c1min,c1max,n1,c2min,c2max,n2,caller)
3951 call mt_build_axis_plane_seeds(c1min,c1max,n1,c2min,c2max,n2, &
3952 fixed_value,axis1,axis2,fixed_axis,seeds)
3953
3954 nseed=n1*n2
3955 allocate(results(nseed))
3956 if (present(b_min)) then
3957 call trace_field_length_multi(seeds,nseed,dl,max_steps,results,b_min)
3958 else
3959 call trace_field_length_multi(seeds,nseed,dl,max_steps,results)
3960 endif
3961 call mt_write_length_plane_csv(results,n1,n2,csv_file,caller, &
3962 index_header)
3963
3964 deallocate(seeds,results)
3965 end subroutine mt_length_plane_axis
3966
3967 subroutine mt_twist_plane_axis(c1min,c1max,n1,c2min,c2max,n2, &
3968 fixed_value,axis1,axis2,fixed_axis,dL,max_steps,csv_file, &
3969 caller,index_header,b_min)
3970 integer, intent(in) :: n1,n2,axis1,axis2,fixed_axis,max_steps
3971 double precision, intent(in) :: c1min,c1max,c2min,c2max
3972 double precision, intent(in) :: fixed_value,dl
3973 character(len=*), intent(in) :: csv_file,caller,index_header
3974 double precision, intent(in), optional :: b_min
3975
3976 type(trace_twist_result), allocatable :: results(:)
3977 double precision, allocatable :: seeds(:,:)
3978 integer :: nseed
3979
3980 call mt_validate_axis_plane(c1min,c1max,n1,c2min,c2max,n2,caller)
3981 call mt_build_axis_plane_seeds(c1min,c1max,n1,c2min,c2max,n2, &
3982 fixed_value,axis1,axis2,fixed_axis,seeds)
3983
3984 nseed=n1*n2
3985 allocate(results(nseed))
3986 if (present(b_min)) then
3987 call trace_field_twist_multi(seeds,nseed,dl,max_steps,results,b_min)
3988 else
3989 call trace_field_twist_multi(seeds,nseed,dl,max_steps,results)
3990 endif
3991 call mt_write_twist_plane_csv(results,n1,n2,csv_file,caller, &
3992 index_header)
3993
3994 deallocate(seeds,results)
3995 end subroutine mt_twist_plane_axis
3996
3997 subroutine mt_q_plane_axis(c1min,c1max,n1,c2min,c2max,n2, &
3998 fixed_value,axis1,axis2,fixed_axis,dL,max_steps,csv_file,caller, &
3999 index_header,b_min)
4000 integer, intent(in) :: n1,n2,axis1,axis2,fixed_axis,max_steps
4001 double precision, intent(in) :: c1min,c1max,c2min,c2max
4002 double precision, intent(in) :: fixed_value,dl
4003 character(len=*), intent(in) :: csv_file,caller,index_header
4004 double precision, intent(in), optional :: b_min
4005
4006 type(trace_qperp_result), allocatable :: results(:)
4007 double precision, allocatable :: seeds(:,:)
4008 integer :: nseed
4009
4010 call mt_validate_axis_plane(c1min,c1max,n1,c2min,c2max,n2,caller)
4011 call mt_build_axis_plane_seeds(c1min,c1max,n1,c2min,c2max,n2, &
4012 fixed_value,axis1,axis2,fixed_axis,seeds)
4013
4014 nseed=n1*n2
4015 allocate(results(nseed))
4016 if (present(b_min)) then
4017 call trace_field_qperp_multi(seeds,nseed,dl,max_steps,results,b_min)
4018 else
4019 call trace_field_qperp_multi(seeds,nseed,dl,max_steps,results)
4020 endif
4021 call mt_write_q_plane_csv(results,n1,n2,csv_file,caller,index_header)
4022
4023 deallocate(seeds,results)
4024 end subroutine mt_q_plane_axis
4025
4026 subroutine mt_qperp_plane_axis(c1min,c1max,n1,c2min,c2max,n2, &
4027 fixed_value,axis1,axis2,fixed_axis,dL,max_steps,csv_file, &
4028 caller,index_header,b_min)
4029 integer, intent(in) :: n1,n2,axis1,axis2,fixed_axis,max_steps
4030 double precision, intent(in) :: c1min,c1max,c2min,c2max
4031 double precision, intent(in) :: fixed_value,dl
4032 character(len=*), intent(in) :: csv_file,caller,index_header
4033 double precision, intent(in), optional :: b_min
4034
4035 type(trace_qperp_result), allocatable :: results(:)
4036 double precision, allocatable :: seeds(:,:)
4037 integer :: nseed
4038
4039 call mt_validate_axis_plane(c1min,c1max,n1,c2min,c2max,n2,caller)
4040 call mt_build_axis_plane_seeds(c1min,c1max,n1,c2min,c2max,n2, &
4041 fixed_value,axis1,axis2,fixed_axis,seeds)
4042
4043 nseed=n1*n2
4044 allocate(results(nseed))
4045 if (present(b_min)) then
4046 call trace_field_qperp_multi(seeds,nseed,dl,max_steps,results,b_min)
4047 else
4048 call trace_field_qperp_multi(seeds,nseed,dl,max_steps,results)
4049 endif
4050 call mt_write_qperp_plane_csv(results,n1,n2,csv_file,caller, &
4051 index_header)
4052
4053 deallocate(seeds,results)
4054 end subroutine mt_qperp_plane_axis
4055
4056 subroutine mt_axis_plane_products_csv_axis(c1min,c1max,n1,c2min,c2max, &
4057 n2,fixed_value,axis1,axis2,fixed_axis,dL,max_steps,length_csv, &
4058 twist_csv,q_csv,qperp_csv,caller,index_header,length_index_header, &
4059 b_min)
4060 integer, intent(in) :: n1,n2,axis1,axis2,fixed_axis,max_steps
4061 double precision, intent(in) :: c1min,c1max,c2min,c2max
4062 double precision, intent(in) :: fixed_value,dl
4063 character(len=*), intent(in) :: length_csv,twist_csv,q_csv,qperp_csv
4064 character(len=*), intent(in) :: caller,index_header,length_index_header
4065 double precision, intent(in), optional :: b_min
4066
4067 type(trace_length_result), allocatable :: length_results(:)
4068 type(trace_twist_result), allocatable :: twist_results(:)
4069 type(trace_qperp_result), allocatable :: q_results(:)
4070 type(trace_qperp_result), allocatable :: qperp_results(:)
4071 double precision, allocatable :: seeds(:,:)
4072 integer :: nseed
4073 logical :: do_twist,do_q,do_qperp
4074
4075 call mt_validate_axis_plane(c1min,c1max,n1,c2min,c2max,n2,caller)
4076 if (len_trim(length_csv)==0) then
4077 call mpistop(trim(caller)//' requires a length CSV file')
4078 endif
4079
4080 do_twist=len_trim(twist_csv)>0
4081 do_q=len_trim(q_csv)>0
4082 do_qperp=len_trim(qperp_csv)>0
4083
4084 call mt_build_axis_plane_seeds(c1min,c1max,n1,c2min,c2max,n2, &
4085 fixed_value,axis1,axis2,fixed_axis,seeds)
4086 nseed=n1*n2
4087 allocate(length_results(nseed))
4088 if (do_twist) then
4089 allocate(twist_results(nseed))
4090 else
4091 allocate(twist_results(0))
4092 endif
4093 if (do_q) then
4094 allocate(q_results(nseed))
4095 else
4096 allocate(q_results(0))
4097 endif
4098 if (do_qperp) then
4099 allocate(qperp_results(nseed))
4100 else
4101 allocate(qperp_results(0))
4102 endif
4103
4104 if (present(b_min)) then
4105 call mt_trace_fieldline_products_seedset(seeds,nseed,dl,max_steps, &
4106 length_results,twist_results,q_results,qperp_results, &
4107 do_twist,do_q,do_qperp,b_min)
4108 else
4109 call mt_trace_fieldline_products_seedset(seeds,nseed,dl,max_steps, &
4110 length_results,twist_results,q_results,qperp_results, &
4111 do_twist,do_q,do_qperp)
4112 endif
4113
4114 call mt_write_length_plane_csv(length_results,n1,n2,length_csv, &
4115 caller,length_index_header)
4116 if (do_twist) then
4117 call mt_write_twist_plane_csv(twist_results,n1,n2,twist_csv, &
4118 caller,length_index_header)
4119 endif
4120 if (do_q) then
4121 call mt_write_q_plane_csv(q_results,n1,n2,q_csv,caller, &
4122 index_header)
4123 endif
4124 if (do_qperp) then
4125 call mt_write_qperp_plane_csv(qperp_results,n1,n2,qperp_csv, &
4126 caller,index_header)
4127 endif
4128
4129 deallocate(qperp_results,q_results,twist_results,length_results,seeds)
4130 end subroutine mt_axis_plane_products_csv_axis
4131
4132 subroutine mt_topology_plane_axis(c1min,c1max,n1,c2min,c2max,n2, &
4133 fixed_value,axis1,axis2,fixed_axis,dL,max_steps,length_csv, &
4134 twist_csv,mapping_csv,caller,index_header,length_index_header, &
4135 b_min)
4136 integer, intent(in) :: n1,n2,axis1,axis2,fixed_axis,max_steps
4137 double precision, intent(in) :: c1min,c1max,c2min,c2max
4138 double precision, intent(in) :: fixed_value,dl
4139 character(len=*), intent(in) :: length_csv,twist_csv,mapping_csv
4140 character(len=*), intent(in) :: caller,index_header,length_index_header
4141 double precision, intent(in), optional :: b_min
4142
4143 type(trace_topology_result), allocatable :: topology(:)
4144 type(trace_length_result), allocatable :: length_results(:)
4145 type(trace_twist_result), allocatable :: twist_results(:)
4146 type(trace_mapping_result), allocatable :: mapping_results(:)
4147 double precision, allocatable :: seeds(:,:)
4148 double precision :: source_normal(3)
4149 integer :: nseed
4150 logical :: write_twist,write_mapping,need_mapping
4151
4152 call mt_validate_axis_plane(c1min,c1max,n1,c2min,c2max,n2,caller)
4153 if (len_trim(length_csv)==0) then
4154 call mpistop(trim(caller)//' requires a length CSV file')
4155 endif
4156
4157 write_twist=len_trim(twist_csv)>0
4158 write_mapping=len_trim(mapping_csv)>0
4159 need_mapping=write_mapping
4160
4161 call mt_build_axis_plane_seeds(c1min,c1max,n1,c2min,c2max,n2, &
4162 fixed_value,axis1,axis2,fixed_axis,seeds)
4163 nseed=n1*n2
4164 allocate(topology(nseed),length_results(nseed))
4165 source_normal=0.d0
4166 source_normal(fixed_axis)=1.d0
4167 if (present(b_min)) then
4168 call trace_field_topology_multi(seeds,nseed,dl,max_steps,topology, &
4169 need_twist=write_twist,need_mapping=need_mapping,b_min=b_min, &
4170 source_normal=source_normal)
4171 else
4172 call trace_field_topology_multi(seeds,nseed,dl,max_steps,topology, &
4173 need_twist=write_twist,need_mapping=need_mapping, &
4174 source_normal=source_normal)
4175 endif
4176
4177 call mt_topology_to_length(topology,nseed,length_results)
4178 call mt_write_length_plane_csv(length_results,n1,n2,length_csv, &
4179 caller,length_index_header)
4180
4181 if (write_twist) then
4182 allocate(twist_results(nseed))
4183 call mt_topology_to_twist(topology,nseed,twist_results)
4184 call mt_write_twist_plane_csv(twist_results,n1,n2,twist_csv, &
4185 caller,length_index_header)
4186 deallocate(twist_results)
4187 endif
4188
4189 if (need_mapping) then
4190 allocate(mapping_results(nseed))
4191 call mt_topology_to_mapping(topology,nseed,mapping_results)
4192 if (write_mapping) then
4193 call mt_write_mapping_plane_csv(mapping_results,n1,n2,mapping_csv, &
4194 caller,index_header)
4195 endif
4196 deallocate(mapping_results)
4197 endif
4198
4199 deallocate(length_results,topology,seeds)
4200 end subroutine mt_topology_plane_axis
4201
4202 subroutine mt_qsl_plane_vtu_axis(c1min,c1max,n1,c2min,c2max,n2, &
4203 fixed_value,axis1,axis2,fixed_axis,dL,max_steps,vtu_file,caller, &
4204 b_min)
4205 integer, intent(in) :: n1,n2,axis1,axis2,fixed_axis,max_steps
4206 double precision, intent(in) :: c1min,c1max,c2min,c2max
4207 double precision, intent(in) :: fixed_value,dl
4208 character(len=*), intent(in) :: vtu_file,caller
4209 double precision, intent(in), optional :: b_min
4210
4211 type(trace_length_result), allocatable :: length_results(:)
4212 type(trace_twist_result), allocatable :: twist_results(:)
4213 type(trace_mapping_result), allocatable :: mapping_results(:)
4214 type(trace_qperp_result), allocatable :: qperp_results(:)
4215 double precision, allocatable :: seeds(:,:)
4216 double precision :: source_normal(3)
4217 integer :: nseed
4218 logical :: need_mapping
4219
4220 call mt_validate_axis_plane(c1min,c1max,n1,c2min,c2max,n2,caller)
4221 if (len_trim(vtu_file)==0) then
4222 call mpistop(trim(caller)//' requires a VTU file')
4223 endif
4224
4225 call mt_build_axis_plane_seeds(c1min,c1max,n1,c2min,c2max,n2, &
4226 fixed_value,axis1,axis2,fixed_axis,seeds)
4227 nseed=n1*n2
4228 allocate(length_results(nseed),twist_results(nseed), &
4229 mapping_results(nseed),qperp_results(nseed))
4230
4231 source_normal=0.d0
4232 source_normal(fixed_axis)=1.d0
4233 need_mapping=mt_vtk_detail_is_full()
4234 if (need_mapping) then
4235 if (present(b_min)) then
4236 call mt_trace_qsl_plane_full(seeds,nseed,dl,max_steps,source_normal, &
4237 qperp_results,twist_results,mapping_results,b_min)
4238 else
4239 call mt_trace_qsl_plane_full(seeds,nseed,dl,max_steps,source_normal, &
4240 qperp_results,twist_results,mapping_results)
4241 endif
4242 call mt_qperp_trace_to_length(qperp_results,nseed,length_results)
4243 else
4244 if (present(b_min)) then
4245 call mt_trace_qsl_plane_minimal(seeds,nseed,dl,max_steps, &
4246 qperp_results,twist_results,b_min)
4247 else
4248 call mt_trace_qsl_plane_minimal(seeds,nseed,dl,max_steps, &
4249 qperp_results,twist_results)
4250 endif
4251 call mt_qperp_trace_to_length(qperp_results,nseed,length_results)
4252 endif
4253
4254 call mt_write_qsl_plane_vtu(vtu_file,length_results,twist_results, &
4255 mapping_results,qperp_results,n1,n2,caller)
4256
4257 deallocate(qperp_results,mapping_results,twist_results, &
4258 length_results,seeds)
4259 end subroutine mt_qsl_plane_vtu_axis
4260
4261 subroutine mt_qsl_plane_vti_axis(c1min,c1max,n1,c2min,c2max,n2, &
4262 fixed_value,axis1,axis2,fixed_axis,dL,max_steps,vti_file, &
4263 do_twist,do_q,do_qperp,caller,b_min,do_length)
4264 integer, intent(in) :: n1,n2,axis1,axis2,fixed_axis,max_steps
4265 double precision, intent(in) :: c1min,c1max,c2min,c2max
4266 double precision, intent(in) :: fixed_value,dl
4267 character(len=*), intent(in) :: vti_file,caller
4268 logical, intent(in) :: do_twist,do_q,do_qperp
4269 double precision, intent(in), optional :: b_min
4270 logical, intent(in), optional :: do_length
4271
4272 type(trace_length_result), allocatable :: length_results(:)
4273 type(trace_twist_result), allocatable :: twist_results(:)
4274 type(trace_qperp_result), allocatable :: q_results(:)
4275 type(trace_qperp_result), allocatable :: qperp_results(:)
4276 type(mt_volume_products) :: products
4277 double precision, allocatable :: seeds(:,:)
4278 double precision :: origin(3),spacing(3)
4279 integer :: nseed,nx_vti,ny_vti,nz_vti
4280 logical :: do_length_eff
4281
4282 call mt_validate_axis_plane(c1min,c1max,n1,c2min,c2max,n2,caller)
4283 if (len_trim(vti_file)==0) then
4284 call mpistop(trim(caller)//' requires a VTI file')
4285 endif
4286 do_length_eff=.true.
4287 if (present(do_length)) do_length_eff=do_length
4288 call mt_require_requested_science(do_length_eff,do_twist,do_q,do_qperp, &
4289 caller)
4290
4291 call mt_build_axis_plane_seeds(c1min,c1max,n1,c2min,c2max,n2, &
4292 fixed_value,axis1,axis2,fixed_axis,seeds)
4293 nseed=n1*n2
4294
4295 allocate(length_results(nseed))
4296 if (do_twist) then
4297 allocate(twist_results(nseed))
4298 else
4299 allocate(twist_results(0))
4300 endif
4301 if (do_q) then
4302 allocate(q_results(nseed))
4303 else
4304 allocate(q_results(0))
4305 endif
4306 if (do_qperp) then
4307 allocate(qperp_results(nseed))
4308 else
4309 allocate(qperp_results(0))
4310 endif
4311
4312 if (present(b_min)) then
4313 call mt_trace_fieldline_products_seedset(seeds,nseed,dl,max_steps, &
4314 length_results,twist_results,q_results,qperp_results,do_twist, &
4315 do_q,do_qperp,b_min)
4316 else
4317 call mt_trace_fieldline_products_seedset(seeds,nseed,dl,max_steps, &
4318 length_results,twist_results,q_results,qperp_results,do_twist, &
4319 do_q,do_qperp)
4320 endif
4321
4322 call mt_allocate_volume_products(products,nseed,do_twist,do_q,do_qperp)
4323 call mt_copy_volume_length_slab(products,length_results,nseed,1,1,1)
4324 if (do_twist) call mt_copy_volume_twist_slab(products,twist_results, &
4325 nseed,1,1,1)
4326 if (do_q) call mt_copy_volume_q_slab(products,q_results,nseed,1,1,1)
4327 if (do_qperp) call mt_copy_volume_qperp_slab(products,qperp_results, &
4328 nseed,1,1,1)
4329
4330 origin=0.d0
4331 spacing=0.d0
4332 nx_vti=1
4333 ny_vti=1
4334 nz_vti=1
4335 origin(axis1)=c1min
4336 origin(axis2)=c2min
4337 origin(fixed_axis)=fixed_value
4338 spacing(axis1)=mt_vti_axis_spacing(c1min,c1max,n1)
4339 spacing(axis2)=mt_vti_axis_spacing(c2min,c2max,n2)
4340 select case (axis1)
4341 case (1)
4342 nx_vti=n1
4343 case (2)
4344 ny_vti=n1
4345 case (3)
4346 nz_vti=n1
4347 end select
4348 select case (axis2)
4349 case (1)
4350 nx_vti=n2
4351 case (2)
4352 ny_vti=n2
4353 case (3)
4354 nz_vti=n2
4355 end select
4356
4357 call mt_write_fieldline_products_volume_vti(vti_file,origin,spacing, &
4358 nx_vti,ny_vti,nz_vti,products,do_length_eff,do_twist,do_q, &
4359 do_qperp,caller)
4360
4361 call mt_deallocate_volume_products(products)
4362 deallocate(qperp_results,q_results,twist_results,length_results,seeds)
4363 end subroutine mt_qsl_plane_vti_axis
4364
4365 subroutine mt_trace_qsl_plane_full(seeds,nseed,dL,max_steps,source_normal, &
4366 qperp_results,twist_results,mapping_results,b_min)
4367 integer, intent(in) :: nseed,max_steps
4368 double precision, intent(in) :: seeds(nseed,ndim),dl,source_normal(3)
4369 type(trace_qperp_result), intent(out) :: qperp_results(nseed)
4370 type(trace_twist_result), intent(out) :: twist_results(nseed)
4371 type(trace_mapping_result), intent(out) :: mapping_results(nseed)
4372 double precision, intent(in), optional :: b_min
4373
4374 double precision :: seed_local(ndim)
4375 integer :: iseed
4376
4377 if (present(b_min)) then
4378 !$OMP PARALLEL DO DEFAULT(SHARED) PRIVATE(iseed,seed_local) SCHEDULE(DYNAMIC,16)
4379 do iseed=1,nseed
4380 seed_local=seeds(iseed,:)
4381 call trace_field_mapping_single(seed_local,dl,max_steps, &
4382 mapping_results(iseed),b_min,source_normal)
4383 enddo
4384 !$OMP END PARALLEL DO
4385 call trace_field_qperp_multi(seeds,nseed,dl,max_steps, &
4386 qperp_results,b_min,twist_results=twist_results)
4387 else
4388 !$OMP PARALLEL DO DEFAULT(SHARED) PRIVATE(iseed,seed_local) SCHEDULE(DYNAMIC,16)
4389 do iseed=1,nseed
4390 seed_local=seeds(iseed,:)
4391 call trace_field_mapping_single(seed_local,dl,max_steps, &
4392 mapping_results(iseed),source_normal=source_normal)
4393 enddo
4394 !$OMP END PARALLEL DO
4395 call trace_field_qperp_multi(seeds,nseed,dl,max_steps, &
4396 qperp_results,twist_results=twist_results)
4397 endif
4398 end subroutine mt_trace_qsl_plane_full
4399
4400 subroutine mt_trace_qsl_plane_minimal(seeds,nseed,dL,max_steps, &
4401 qperp_results,twist_results,b_min)
4402 integer, intent(in) :: nseed,max_steps
4403 double precision, intent(in) :: seeds(nseed,ndim),dl
4404 type(trace_qperp_result), intent(out) :: qperp_results(nseed)
4405 type(trace_twist_result), intent(out) :: twist_results(nseed)
4406 double precision, intent(in), optional :: b_min
4407
4408 if (present(b_min)) then
4409 call trace_field_qperp_multi(seeds,nseed,dl,max_steps, &
4410 qperp_results,b_min,twist_results=twist_results)
4411 else
4412 call trace_field_qperp_multi(seeds,nseed,dl,max_steps, &
4413 qperp_results,twist_results=twist_results)
4414 endif
4415 end subroutine mt_trace_qsl_plane_minimal
4416
4417 subroutine mt_qperp_to_length(qperp_results,nseed,results)
4418 integer, intent(in) :: nseed
4419 type(trace_qperp_result), intent(in) :: qperp_results(nseed)
4420 type(trace_length_result), intent(out) :: results(nseed)
4421
4422 integer :: iseed
4423
4424 do iseed=1,nseed
4425 results(iseed)%seed=qperp_results(iseed)%seed
4426 results(iseed)%forward_footpoint=qperp_results(iseed)%forward_endpoint
4427 results(iseed)%backward_footpoint=qperp_results(iseed)%backward_endpoint
4428 results(iseed)%forward_status=qperp_results(iseed)%forward_status
4429 results(iseed)%backward_status=qperp_results(iseed)%backward_status
4430 results(iseed)%forward_nstep=0
4431 results(iseed)%backward_nstep=0
4432 if (qperp_results(iseed)%valid_q0) then
4433 results(iseed)%forward_length=qperp_results(iseed)%forward_length
4434 results(iseed)%backward_length=qperp_results(iseed)%backward_length
4435 results(iseed)%total_length=results(iseed)%forward_length &
4436 +results(iseed)%backward_length
4437 else
4438 results(iseed)%forward_length=0.d0
4439 results(iseed)%backward_length=0.d0
4440 results(iseed)%total_length=0.d0
4441 endif
4442 enddo
4443 end subroutine mt_qperp_to_length
4444
4445 subroutine mt_qperp_trace_to_length(qperp_results,nseed,results)
4446 integer, intent(in) :: nseed
4447 type(trace_qperp_result), intent(in) :: qperp_results(nseed)
4448 type(trace_length_result), intent(out) :: results(nseed)
4449
4450 integer :: iseed
4451
4452 do iseed=1,nseed
4453 results(iseed)%seed=qperp_results(iseed)%seed
4454 results(iseed)%forward_footpoint=qperp_results(iseed)%forward_endpoint
4455 results(iseed)%backward_footpoint=qperp_results(iseed)%backward_endpoint
4456 results(iseed)%forward_length=qperp_results(iseed)%forward_length
4457 results(iseed)%backward_length=qperp_results(iseed)%backward_length
4458 results(iseed)%total_length=results(iseed)%forward_length+ &
4459 results(iseed)%backward_length
4460 results(iseed)%forward_nstep=qperp_results(iseed)%forward_nstep
4461 results(iseed)%backward_nstep=qperp_results(iseed)%backward_nstep
4462 results(iseed)%forward_status=qperp_results(iseed)%forward_status
4463 results(iseed)%backward_status=qperp_results(iseed)%backward_status
4464 enddo
4465 end subroutine mt_qperp_trace_to_length
4466
4467 subroutine mt_qperp_trace_to_topology(qperp_results,twist_results,nseed, &
4468 topology,do_twist)
4469 integer, intent(in) :: nseed
4470 type(trace_qperp_result), intent(in) :: qperp_results(nseed)
4471 type(trace_twist_result), intent(in) :: twist_results(:)
4472 type(trace_topology_result), intent(out) :: topology(nseed)
4473 logical, intent(in) :: do_twist
4474
4475 integer :: iseed
4476
4477 do iseed=1,nseed
4478 topology(iseed)%seed=qperp_results(iseed)%seed
4479 topology(iseed)%length_forward=qperp_results(iseed)%forward_length
4480 topology(iseed)%length_backward=qperp_results(iseed)%backward_length
4481 topology(iseed)%length_total=topology(iseed)%length_forward &
4482 +topology(iseed)%length_backward
4483 topology(iseed)%twist_forward=0.d0
4484 topology(iseed)%twist_backward=0.d0
4485 topology(iseed)%twist_total=0.d0
4486 if (do_twist) then
4487 topology(iseed)%twist_forward=twist_results(iseed)%forward_twist
4488 topology(iseed)%twist_backward=twist_results(iseed)%backward_twist
4489 topology(iseed)%twist_total=twist_results(iseed)%total_twist
4490 endif
4491 topology(iseed)%forward_endpoint=qperp_results(iseed)%forward_endpoint
4492 topology(iseed)%backward_endpoint=qperp_results(iseed)%backward_endpoint
4493 topology(iseed)%forward_nstep=qperp_results(iseed)%forward_nstep
4494 topology(iseed)%backward_nstep=qperp_results(iseed)%backward_nstep
4495 topology(iseed)%forward_face=qperp_results(iseed)%forward_face
4496 topology(iseed)%backward_face=qperp_results(iseed)%backward_face
4497 topology(iseed)%forward_status=qperp_results(iseed)%forward_status
4498 topology(iseed)%backward_status=qperp_results(iseed)%backward_status
4499 topology(iseed)%map_forward_endpoint=qperp_results(iseed)%forward_endpoint
4500 topology(iseed)%map_backward_endpoint=qperp_results(iseed)%backward_endpoint
4501 topology(iseed)%map_forward_length=qperp_results(iseed)%forward_length
4502 topology(iseed)%map_backward_length=qperp_results(iseed)%backward_length
4503 topology(iseed)%map_forward_face=qperp_results(iseed)%forward_face
4504 topology(iseed)%map_backward_face=qperp_results(iseed)%backward_face
4505 topology(iseed)%map_forward_status=qperp_results(iseed)%forward_status
4506 topology(iseed)%map_backward_status=qperp_results(iseed)%backward_status
4507 topology(iseed)%source_B=0.d0
4508 topology(iseed)%forward_B=0.d0
4509 topology(iseed)%backward_B=0.d0
4510 topology(iseed)%source_B(1:ndim)=qperp_results(iseed)%B_seed
4511 topology(iseed)%forward_B(1:ndim)=qperp_results(iseed)%forward_B
4512 topology(iseed)%backward_B(1:ndim)=qperp_results(iseed)%backward_B
4513 topology(iseed)%source_Bn=0.d0
4514 topology(iseed)%forward_Bn=0.d0
4515 topology(iseed)%backward_Bn=0.d0
4516 topology(iseed)%has_twist=do_twist
4517 topology(iseed)%has_mapping=.false.
4518 topology(iseed)%valid_twist=.false.
4519 topology(iseed)%status_twist=qperp_results(iseed)%status
4520 if (do_twist) then
4521 topology(iseed)%valid_twist=twist_results(iseed)%valid_twist
4522 topology(iseed)%status_twist=twist_results(iseed)%status_twist
4523 endif
4524 topology(iseed)%valid=qperp_results(iseed)%status==trace_status_boundary
4525 topology(iseed)%status=qperp_results(iseed)%status
4526 enddo
4527 end subroutine mt_qperp_trace_to_topology
4528
4529 subroutine mt_q0_trace_to_length(q_results,nseed,results)
4530 integer, intent(in) :: nseed
4531 type(trace_qperp_result), intent(in) :: q_results(nseed)
4532 type(trace_length_result), intent(out) :: results(nseed)
4533
4534 integer :: iseed
4535
4536 do iseed=1,nseed
4537 results(iseed)%seed=q_results(iseed)%seed
4538 results(iseed)%forward_footpoint=q_results(iseed)%forward_endpoint
4539 results(iseed)%backward_footpoint=q_results(iseed)%backward_endpoint
4540 results(iseed)%forward_length=q_results(iseed)%forward_length
4541 results(iseed)%backward_length=q_results(iseed)%backward_length
4542 results(iseed)%total_length=results(iseed)%forward_length &
4543 +results(iseed)%backward_length
4544 results(iseed)%forward_nstep=q_results(iseed)%forward_nstep
4545 results(iseed)%backward_nstep=q_results(iseed)%backward_nstep
4546 results(iseed)%forward_status=q_results(iseed)%forward_status
4547 results(iseed)%backward_status=q_results(iseed)%backward_status
4548 enddo
4549 end subroutine mt_q0_trace_to_length
4550
4551 subroutine mt_q0_trace_to_topology(q_results,twist_results,nseed, &
4552 topology,do_twist)
4553 integer, intent(in) :: nseed
4554 type(trace_qperp_result), intent(in) :: q_results(nseed)
4555 type(trace_twist_result), intent(in) :: twist_results(:)
4556 type(trace_topology_result), intent(out) :: topology(nseed)
4557 logical, intent(in) :: do_twist
4558
4559 integer :: iseed
4560
4561 do iseed=1,nseed
4562 topology(iseed)%seed=q_results(iseed)%seed
4563 topology(iseed)%length_forward=q_results(iseed)%forward_length
4564 topology(iseed)%length_backward=q_results(iseed)%backward_length
4565 topology(iseed)%length_total=topology(iseed)%length_forward &
4566 +topology(iseed)%length_backward
4567 topology(iseed)%twist_forward=0.d0
4568 topology(iseed)%twist_backward=0.d0
4569 topology(iseed)%twist_total=0.d0
4570 if (do_twist) then
4571 topology(iseed)%twist_forward=twist_results(iseed)%forward_twist
4572 topology(iseed)%twist_backward=twist_results(iseed)%backward_twist
4573 topology(iseed)%twist_total=twist_results(iseed)%total_twist
4574 endif
4575 topology(iseed)%forward_endpoint=q_results(iseed)%forward_endpoint
4576 topology(iseed)%backward_endpoint=q_results(iseed)%backward_endpoint
4577 topology(iseed)%forward_nstep=q_results(iseed)%forward_nstep
4578 topology(iseed)%backward_nstep=q_results(iseed)%backward_nstep
4579 topology(iseed)%forward_face=q_results(iseed)%forward_face
4580 topology(iseed)%backward_face=q_results(iseed)%backward_face
4581 topology(iseed)%forward_status=q_results(iseed)%forward_status
4582 topology(iseed)%backward_status=q_results(iseed)%backward_status
4583 topology(iseed)%map_forward_endpoint=q_results(iseed)%forward_endpoint
4584 topology(iseed)%map_backward_endpoint=q_results(iseed)%backward_endpoint
4585 topology(iseed)%map_forward_length=q_results(iseed)%forward_length
4586 topology(iseed)%map_backward_length=q_results(iseed)%backward_length
4587 topology(iseed)%map_forward_face=q_results(iseed)%forward_face
4588 topology(iseed)%map_backward_face=q_results(iseed)%backward_face
4589 topology(iseed)%map_forward_status=q_results(iseed)%forward_status
4590 topology(iseed)%map_backward_status=q_results(iseed)%backward_status
4591 topology(iseed)%source_B=0.d0
4592 topology(iseed)%forward_B=0.d0
4593 topology(iseed)%backward_B=0.d0
4594 topology(iseed)%source_B(1:ndim)=q_results(iseed)%B_seed
4595 topology(iseed)%forward_B(1:ndim)=q_results(iseed)%forward_B
4596 topology(iseed)%backward_B(1:ndim)=q_results(iseed)%backward_B
4597 topology(iseed)%source_Bn=0.d0
4598 topology(iseed)%forward_Bn=q_results(iseed)%forward_Bn_q0
4599 topology(iseed)%backward_Bn=q_results(iseed)%backward_Bn_q0
4600 topology(iseed)%has_twist=do_twist
4601 topology(iseed)%has_mapping=.false.
4602 topology(iseed)%valid_twist=.false.
4603 topology(iseed)%status_twist=q_results(iseed)%status
4604 if (do_twist) then
4605 topology(iseed)%valid_twist=twist_results(iseed)%valid_twist
4606 topology(iseed)%status_twist=twist_results(iseed)%status_twist
4607 endif
4608 topology(iseed)%valid=q_results(iseed)%status==trace_status_boundary
4609 topology(iseed)%status=q_results(iseed)%status
4610 enddo
4611 end subroutine mt_q0_trace_to_topology
4612
4613 subroutine mt_topology_to_length(topology,nseed,results)
4614 integer, intent(in) :: nseed
4615 type(trace_topology_result), intent(in) :: topology(nseed)
4616 type(trace_length_result), intent(out) :: results(nseed)
4617
4618 integer :: iseed
4619
4620 do iseed=1,nseed
4621 results(iseed)%seed=topology(iseed)%seed
4622 results(iseed)%forward_footpoint=topology(iseed)%forward_endpoint
4623 results(iseed)%backward_footpoint=topology(iseed)%backward_endpoint
4624 results(iseed)%forward_length=topology(iseed)%length_forward
4625 results(iseed)%backward_length=topology(iseed)%length_backward
4626 results(iseed)%total_length=topology(iseed)%length_total
4627 results(iseed)%forward_nstep=topology(iseed)%forward_nstep
4628 results(iseed)%backward_nstep=topology(iseed)%backward_nstep
4629 results(iseed)%forward_status=topology(iseed)%forward_status
4630 results(iseed)%backward_status=topology(iseed)%backward_status
4631 enddo
4632 end subroutine mt_topology_to_length
4633
4634 subroutine mt_topology_to_twist(topology,nseed,results)
4635 integer, intent(in) :: nseed
4636 type(trace_topology_result), intent(in) :: topology(nseed)
4637 type(trace_twist_result), intent(out) :: results(nseed)
4638
4639 integer :: iseed
4640
4641 do iseed=1,nseed
4642 results(iseed)%line%seed=topology(iseed)%seed
4643 results(iseed)%line%forward_footpoint=topology(iseed)%forward_endpoint
4644 results(iseed)%line%backward_footpoint=topology(iseed)%backward_endpoint
4645 results(iseed)%line%forward_length=topology(iseed)%length_forward
4646 results(iseed)%line%backward_length=topology(iseed)%length_backward
4647 results(iseed)%line%total_length=topology(iseed)%length_total
4648 results(iseed)%line%forward_nstep=topology(iseed)%forward_nstep
4649 results(iseed)%line%backward_nstep=topology(iseed)%backward_nstep
4650 results(iseed)%line%forward_status=topology(iseed)%forward_status
4651 results(iseed)%line%backward_status=topology(iseed)%backward_status
4652 results(iseed)%forward_twist=topology(iseed)%twist_forward
4653 results(iseed)%backward_twist=topology(iseed)%twist_backward
4654 results(iseed)%total_twist=topology(iseed)%twist_total
4655 results(iseed)%valid_twist=topology(iseed)%valid_twist
4656 results(iseed)%status_twist=topology(iseed)%status_twist
4657 enddo
4658 end subroutine mt_topology_to_twist
4659
4660 subroutine mt_topology_to_mapping(topology,nseed,results)
4661 integer, intent(in) :: nseed
4662 type(trace_topology_result), intent(in) :: topology(nseed)
4663 type(trace_mapping_result), intent(out) :: results(nseed)
4664
4665 integer :: iseed
4666
4667 do iseed=1,nseed
4668 results(iseed)%seed=topology(iseed)%seed
4669 results(iseed)%source_B=topology(iseed)%source_B
4670 results(iseed)%forward_footpoint=topology(iseed)%map_forward_endpoint
4671 results(iseed)%backward_footpoint=topology(iseed)%map_backward_endpoint
4672 results(iseed)%forward_B=topology(iseed)%forward_B
4673 results(iseed)%backward_B=topology(iseed)%backward_B
4674 results(iseed)%forward_length=topology(iseed)%map_forward_length
4675 results(iseed)%backward_length=topology(iseed)%map_backward_length
4676 results(iseed)%source_Bn=topology(iseed)%source_Bn
4677 results(iseed)%forward_Bn=topology(iseed)%forward_Bn
4678 results(iseed)%backward_Bn=topology(iseed)%backward_Bn
4679 results(iseed)%forward_face=topology(iseed)%map_forward_face
4680 results(iseed)%backward_face=topology(iseed)%map_backward_face
4681 results(iseed)%forward_status=topology(iseed)%map_forward_status
4682 results(iseed)%backward_status=topology(iseed)%map_backward_status
4683 results(iseed)%valid=topology(iseed)%has_mapping .and. &
4684 topology(iseed)%valid
4685 enddo
4686 end subroutine mt_topology_to_mapping
4687
4688 subroutine mt_validate_axis_plane(c1min,c1max,n1,c2min,c2max,n2,caller)
4689 integer, intent(in) :: n1,n2
4690 double precision, intent(in) :: c1min,c1max,c2min,c2max
4691 character(len=*), intent(in) :: caller
4692
4693 if (npe/=1) then
4694 call mpistop(trim(caller)//' currently requires npe=1')
4695 endif
4696 if (ndim/=3) then
4697 call mpistop(trim(caller)//' requires ndim=3')
4698 return
4699 endif
4700 {^ifthreed
4701 select case (geo_coordinate)
4702 case (geo_cartesian)
4703 ! Coordinate-plane products are sampled seed surfaces. RK2 tracing can
4704 ! use either slab-uniform or AMR Cartesian simulation grids.
4705 case (geo_cartesian_stretched)
4706 case default
4707 call mpistop(trim(caller)//' requires Cartesian geometry')
4708 end select
4709 }
4710 if (n1<1 .or. n2<1) then
4711 call mpistop(trim(caller)//' requires both sample counts >=1')
4712 endif
4713 if (c1max<c1min .or. c2max<c2min) then
4714 call mpistop(trim(caller)//' requires ordered plane bounds')
4715 endif
4716 end subroutine mt_validate_axis_plane
4717
4718 subroutine mt_build_axis_plane_seeds(c1min,c1max,n1,c2min,c2max,n2, &
4719 fixed_value,axis1,axis2,fixed_axis,seeds)
4720 integer, intent(in) :: n1,n2,axis1,axis2,fixed_axis
4721 double precision, intent(in) :: c1min,c1max,c2min,c2max,fixed_value
4722 double precision, allocatable, intent(out) :: seeds(:,:)
4723
4724 double precision :: dc1,dc2
4725 integer :: i,j,iseed
4726
4727 dc1=0.d0
4728 dc2=0.d0
4729 if (n1>1) dc1=(c1max-c1min)/dble(n1-1)
4730 if (n2>1) dc2=(c2max-c2min)/dble(n2-1)
4731
4732 allocate(seeds(n1*n2,ndim))
4733 seeds=0.d0
4734 do j=1,n2
4735 do i=1,n1
4736 iseed=(j-1)*n1+i
4737 seeds(iseed,axis1)=c1min+dble(i-1)*dc1
4738 seeds(iseed,axis2)=c2min+dble(j-1)*dc2
4739 seeds(iseed,fixed_axis)=fixed_value
4740 enddo
4741 enddo
4742 end subroutine mt_build_axis_plane_seeds
4743
4744 subroutine mt_build_spherical_surface_seeds(surface,seed_coord,s1_min, &
4745 s1_max,n1,s2_min,s2_max,n2,seed_layout,seed_theta0,seed_phi0, &
4746 seed_alpha,seeds)
4747 character(len=*), intent(in) :: surface,seed_layout
4748 integer, intent(in) :: n1,n2
4749 double precision, intent(in) :: seed_coord,s1_min,s1_max,s2_min,s2_max
4750 double precision, intent(in) :: seed_theta0,seed_phi0,seed_alpha
4751 double precision, allocatable, intent(out) :: seeds(:,:)
4752
4753 character(len=mt_task_name_len) :: layout
4754 double precision :: s1,s2
4755 integer :: i,j,iseed,status
4756
4757 layout=mt_lowercase(trim(seed_layout))
4758 if (len_trim(layout)==0) layout='endpoint'
4759 select case (trim(layout))
4760 case ('endpoint','endpoints','boundary')
4761 case ('cell_centered','cell-centered','centered','center')
4762 case default
4763 call mpistop('spherical_surface_products requires '// &
4764 'mt_seed_layout=endpoint or cell_centered')
4765 end select
4766
4767 allocate(seeds(n1*n2,ndim))
4768 seeds=0.d0
4769 do j=1,n2
4770 s2=mt_seed_axis_coord(s2_min,s2_max,n2,j,layout)
4771 do i=1,n1
4772 s1=mt_seed_axis_coord(s1_min,s1_max,n1,i,layout)
4773 iseed=(j-1)*n1+i
4774 select case (trim(surface))
4775 case ('rmin','rconst')
4776 seeds(iseed,1)=seed_coord
4777 seeds(iseed,2)=s1
4778 seeds(iseed,3)=s2
4779 case ('theta_const')
4780 seeds(iseed,1)=s1
4781 seeds(iseed,2)=seed_coord
4782 seeds(iseed,3)=s2
4783 case ('phi_const')
4784 seeds(iseed,1)=s1
4785 seeds(iseed,2)=s2
4786 seeds(iseed,3)=seed_coord
4787 case ('radial_plane')
4788 call mt_spherical_radial_plane_seed(s1,s2,seed_theta0,seed_phi0, &
4789 seed_alpha,seeds(iseed,:),status)
4790 if (status/=0) then
4791 call mpistop('mt_build_spherical_surface_seeds radial_plane '// &
4792 'seed lies outside the spherical domain; adjust '// &
4793 'mt_seed_theta0/mt_seed_phi0/mt_seed_alpha or mt_s2 bounds')
4794 endif
4795 case default
4796 call mpistop('mt_build_spherical_surface_seeds got '// &
4797 'unsupported surface')
4798 end select
4799 enddo
4800 enddo
4801 end subroutine mt_build_spherical_surface_seeds
4802
4803 subroutine mt_spherical_radial_plane_seed(radius,u,theta0,phi0,alpha,seed, &
4804 status)
4805 double precision, intent(in) :: radius,u,theta0,phi0,alpha
4806 double precision, intent(out) :: seed(ndim)
4807 integer, intent(out) :: status
4808
4809 double precision :: sin_theta0,cos_theta0,sin_phi0,cos_phi0
4810 double precision :: n0(3),etheta(3),ephi(3),tangent(3),nhat(3)
4811 double precision :: norm_n,theta,phi,cos_u,sin_u
4812
4813 seed=0.d0
4814 status=1
4815 {^ifthreed
4816 if (radius<xprobmin1 .or. radius>xprobmax1) return
4817 if (theta0<xprobmin2 .or. theta0>xprobmax2) return
4818 if (phi0<xprobmin3 .or. phi0>xprobmax3) return
4819
4820 sin_theta0=dsin(theta0)
4821 cos_theta0=dcos(theta0)
4822 if (abs(sin_theta0)<=1.d-12) return
4823 sin_phi0=dsin(phi0)
4824 cos_phi0=dcos(phi0)
4825
4826 n0=(/sin_theta0*cos_phi0,sin_theta0*sin_phi0,cos_theta0/)
4827 etheta=(/cos_theta0*cos_phi0,cos_theta0*sin_phi0,-sin_theta0/)
4828 ephi=(/-sin_phi0,cos_phi0,0.d0/)
4829 tangent=dcos(alpha)*etheta+dsin(alpha)*ephi
4830
4831 cos_u=dcos(u)
4832 sin_u=dsin(u)
4833 nhat=cos_u*n0+sin_u*tangent
4834 norm_n=dsqrt(sum(nhat**2))
4835 if (norm_n<=0.d0) return
4836 nhat=nhat/norm_n
4837
4838 theta=dacos(max(-1.d0,min(1.d0,nhat(3))))
4839 phi=datan2(nhat(2),nhat(1))
4840 if (theta<xprobmin2 .or. theta>xprobmax2) return
4841 if (phi<xprobmin3 .or. phi>xprobmax3) return
4842
4843 seed(1)=radius
4844 seed(2)=theta
4845 seed(3)=phi
4846 status=0
4847 }
4848 end subroutine mt_spherical_radial_plane_seed
4849
4850 subroutine mt_build_spherical_cloud_seeds(s1_min,s1_max,n1,s2_min, &
4851 s2_max,n2,s3_min,s3_max,n3,seed_layout,seeds)
4852 character(len=*), intent(in) :: seed_layout
4853 integer, intent(in) :: n1,n2,n3
4854 double precision, intent(in) :: s1_min,s1_max,s2_min,s2_max
4855 double precision, intent(in) :: s3_min,s3_max
4856 double precision, allocatable, intent(out) :: seeds(:,:)
4857
4858 character(len=mt_task_name_len) :: layout
4859 double precision :: s1,s2,s3
4860 integer :: i,j,k,iseed
4861
4862 layout=mt_lowercase(trim(seed_layout))
4863 if (len_trim(layout)==0) layout='endpoint'
4864 select case (trim(layout))
4865 case ('endpoint','endpoints','boundary')
4866 case ('cell_centered','cell-centered','centered','center')
4867 case default
4868 call mpistop('spherical_cloud_products requires '// &
4869 'mt_seed_layout=endpoint or cell_centered')
4870 end select
4871
4872 allocate(seeds(n1*n2*n3,ndim))
4873 seeds=0.d0
4874 do k=1,n3
4875 s3=mt_seed_axis_coord(s3_min,s3_max,n3,k,layout)
4876 do j=1,n2
4877 s2=mt_seed_axis_coord(s2_min,s2_max,n2,j,layout)
4878 do i=1,n1
4879 s1=mt_seed_axis_coord(s1_min,s1_max,n1,i,layout)
4880 iseed=(k-1)*n1*n2+(j-1)*n1+i
4881 seeds(iseed,1)=s1
4882 seeds(iseed,2)=s2
4883 seeds(iseed,3)=s3
4884 enddo
4885 enddo
4886 enddo
4887 end subroutine mt_build_spherical_cloud_seeds
4888
4889 double precision function mt_seed_axis_coord(cmin,cmax,n,i,layout) &
4890 result(coord)
4891 double precision, intent(in) :: cmin,cmax
4892 integer, intent(in) :: n,i
4893 character(len=*), intent(in) :: layout
4894
4895 select case (trim(layout))
4896 case ('cell_centered','cell-centered','centered','center')
4897 coord=cmin+(dble(i)-0.5d0)*(cmax-cmin)/dble(n)
4898 case default
4899 if (n>1) then
4900 coord=cmin+dble(i-1)*(cmax-cmin)/dble(n-1)
4901 else
4902 coord=cmin
4903 endif
4904 end select
4905 end function mt_seed_axis_coord
4906
4907 integer function mt_spherical_connection_type(face_b,face_f,is_valid) &
4908 result(connection_type)
4909 integer, intent(in) :: face_b,face_f
4910 logical, intent(in) :: is_valid
4911
4912 logical :: b_rmin,f_rmin,b_rmax,f_rmax,b_side,f_side
4913
4914 connection_type=0
4915 if (.not.is_valid) return
4916 if (.not.mt_q_face_valid(face_b)) return
4917 if (.not.mt_q_face_valid(face_f)) return
4918
4919 b_rmin=face_b==trace_face_xmin
4920 f_rmin=face_f==trace_face_xmin
4921 b_rmax=face_b==trace_face_xmax
4922 f_rmax=face_f==trace_face_xmax
4923 b_side=.not.(b_rmin .or. b_rmax)
4924 f_side=.not.(f_rmin .or. f_rmax)
4925
4926 if (b_rmin .and. f_rmin) then
4927 connection_type=1
4928 else if ((b_rmin .and. f_rmax) .or. (b_rmax .and. f_rmin)) then
4929 connection_type=2
4930 else if ((b_rmin .and. f_side) .or. (f_rmin .and. b_side)) then
4931 connection_type=3
4932 else if (b_rmax .and. f_rmax) then
4933 connection_type=4
4934 else if (b_side .and. f_side .and. face_b==face_f) then
4935 connection_type=5
4936 else
4937 connection_type=6
4938 endif
4939 end function mt_spherical_connection_type
4940
4941 logical function mt_validate_arbitrary_plane_basis(e1,e2,s1min,s1max, &
4942 n1,s2min,s2max,n2,caller) result(valid)
4943 integer, intent(in) :: n1,n2
4944 double precision, intent(in) :: e1(ndim),e2(ndim)
4945 double precision, intent(in) :: s1min,s1max,s2min,s2max
4946 character(len=*), intent(in) :: caller
4947
4948 double precision, parameter :: basis_tol=1.d-10
4949 double precision :: e1_norm,e2_norm,e12_dot
4950
4951 valid=.false.
4952 if (npe/=1) then
4953 write(*,'(a)') trim(caller)//' currently requires npe=1'
4954 return
4955 endif
4956 if (ndim/=3) then
4957 write(*,'(a)') trim(caller)//' requires ndim=3'
4958 return
4959 endif
4960 {^ifthreed
4961 select case (geo_coordinate)
4962 case (geo_cartesian,geo_cartesian_stretched)
4963 case default
4964 write(*,'(a)') trim(caller)//' requires Cartesian geometry'
4965 return
4966 end select
4967 }
4968 if (n1<1 .or. n2<1) then
4969 write(*,'(a)') trim(caller)//' requires both sample counts >=1'
4970 return
4971 endif
4972 if (s1max<s1min .or. s2max<s2min) then
4973 write(*,'(a)') trim(caller)//' requires ordered plane bounds'
4974 return
4975 endif
4976 e1_norm=dsqrt(sum(e1**2))
4977 e2_norm=dsqrt(sum(e2**2))
4978 e12_dot=sum(e1*e2)
4979 if (abs(e1_norm-1.d0)>basis_tol .or. &
4980 abs(e2_norm-1.d0)>basis_tol .or. &
4981 abs(e12_dot)>basis_tol) then
4982 write(*,'(a)') trim(caller)//' requires orthonormal e1/e2'
4983 return
4984 endif
4985
4986 valid=.true.
4987 end function mt_validate_arbitrary_plane_basis
4988
4989 subroutine mt_build_arbitrary_plane_seeds(origin,e1,e2,s1min,s1max,n1, &
4990 s2min,s2max,n2,seeds,s1,s2)
4991 integer, intent(in) :: n1,n2
4992 double precision, intent(in) :: origin(ndim),e1(ndim),e2(ndim)
4993 double precision, intent(in) :: s1min,s1max,s2min,s2max
4994 double precision, allocatable, intent(out) :: seeds(:,:),s1(:),s2(:)
4995
4996 double precision :: ds1,ds2
4997 integer :: i,j,iseed
4998
4999 ds1=0.d0
5000 ds2=0.d0
5001 if (n1>1) ds1=(s1max-s1min)/dble(n1-1)
5002 if (n2>1) ds2=(s2max-s2min)/dble(n2-1)
5003
5004 allocate(seeds(n1*n2,ndim),s1(n1*n2),s2(n1*n2))
5005 do j=1,n2
5006 do i=1,n1
5007 iseed=(j-1)*n1+i
5008 s1(iseed)=s1min+dble(i-1)*ds1
5009 s2(iseed)=s2min+dble(j-1)*ds2
5010 seeds(iseed,:)=origin+s1(iseed)*e1+s2(iseed)*e2
5011 enddo
5012 enddo
5013 end subroutine mt_build_arbitrary_plane_seeds
5014
5015 subroutine mt_write_length_plane_csv(results,n1,n2,csv_file,caller, &
5016 index_header)
5017 integer, intent(in) :: n1,n2
5018 type(trace_length_result), intent(in) :: results(n1*n2)
5019 character(len=*), intent(in) :: csv_file,caller,index_header
5020
5021 double precision :: seed_xyz(3)
5022 integer :: csv_unit,io_status,i,j,iseed
5023
5024 open(newunit=csv_unit,file=trim(csv_file),status='replace', &
5025 action='write',form='formatted',iostat=io_status)
5026 if (io_status/=0) then
5027 call mpistop(trim(caller)//' could not open CSV file')
5028 endif
5029
5030 write(csv_unit,'(a)',iostat=io_status) &
5031 trim(index_header)//',seed_x,seed_y,seed_z,'// &
5032 'length_total,length_backward,length_forward,'// &
5033 'nstep_backward,nstep_forward,'// &
5034 'status_backward,status_forward'
5035 if (io_status/=0) then
5036 close(csv_unit)
5037 call mpistop(trim(caller)//' could not write CSV header')
5038 endif
5039
5040 do j=1,n2
5041 do i=1,n1
5042 iseed=(j-1)*n1+i
5043 seed_xyz=0.d0
5044 seed_xyz(1:ndim)=results(iseed)%seed
5045 write(csv_unit,'(i0,",",i0,6(",",es24.16),4(",",i0))', &
5046 iostat=io_status) i,j,seed_xyz,results(iseed)%total_length, &
5047 results(iseed)%backward_length, &
5048 results(iseed)%forward_length, &
5049 results(iseed)%backward_nstep, &
5050 results(iseed)%forward_nstep, &
5051 results(iseed)%backward_status, &
5052 results(iseed)%forward_status
5053 if (io_status/=0) then
5054 close(csv_unit)
5055 call mpistop(trim(caller)//' could not write CSV data')
5056 endif
5057 enddo
5058 enddo
5059
5060 close(csv_unit)
5061 end subroutine mt_write_length_plane_csv
5062
5063 subroutine mt_write_spherical_rmin_csv(topology,n1,n2,csv_file,caller, &
5064 do_twist,do_q,q_results,do_qperp,qperp_results)
5065 integer, intent(in) :: n1,n2
5066 type(trace_topology_result), intent(in) :: topology(n1*n2)
5067 character(len=*), intent(in) :: csv_file,caller
5068 logical, intent(in) :: do_twist,do_q,do_qperp
5069 type(trace_qperp_result), intent(in) :: q_results(:)
5070 type(trace_qperp_result), intent(in) :: qperp_results(:)
5071
5072 integer :: csv_unit,io_status,i,j,iseed,connection_type
5073 logical :: valid
5074 character(len=2048) :: header
5075
5076 open(newunit=csv_unit,file=trim(csv_file),status='replace', &
5077 action='write',form='formatted',iostat=io_status)
5078 if (io_status/=0) then
5079 call mpistop(trim(caller)//' could not open CSV file')
5080 endif
5081
5082 header='i,j,seed_r,seed_theta,seed_phi,'// &
5083 'length_total,length_backward,length_forward'
5084 if (do_twist) then
5085 header=trim(header)//','// &
5086 'twist_total,twist_backward,twist_forward'
5087 endif
5088 if (do_q) then
5089 header=trim(header)//','// &
5090 'logQ,valid_Q,status_Q'
5091 endif
5092 if (do_qperp) then
5093 header=trim(header)//','// &
5094 'logQperp,valid_Qperp,status_Qperp'
5095 endif
5096 header=trim(header)//','// &
5097 'r_b,theta_b,phi_b,r_f,theta_f,phi_f,'// &
5098 'face_backward,face_forward,connection_type_spherical,'// &
5099 'nstep_backward,nstep_forward,status_backward,status_forward'
5100 if (do_twist) then
5101 header=trim(header)//','// &
5102 'status_twist,valid_twist'
5103 endif
5104 header=trim(header)//',valid'
5105 write(csv_unit,'(a)',iostat=io_status) trim(header)
5106 if (io_status/=0) then
5107 close(csv_unit)
5108 call mpistop(trim(caller)//' could not write CSV header')
5109 endif
5110
5111 do j=1,n2
5112 do i=1,n1
5113 iseed=(j-1)*n1+i
5114 valid=topology(iseed)%valid
5115 connection_type=mt_spherical_connection_type( &
5116 topology(iseed)%backward_face,topology(iseed)%forward_face, &
5117 valid)
5118 write(csv_unit,'(i0,",",i0,6(",",es24.16))',advance='no', &
5119 iostat=io_status) i,j,topology(iseed)%seed, &
5120 topology(iseed)%length_total, &
5121 topology(iseed)%length_backward, &
5122 topology(iseed)%length_forward
5123 if (io_status/=0) exit
5124 if (do_twist) then
5125 write(csv_unit,'(3(",",es24.16))',advance='no', &
5126 iostat=io_status) topology(iseed)%twist_total, &
5127 topology(iseed)%twist_backward, &
5128 topology(iseed)%twist_forward
5129 if (io_status/=0) exit
5130 endif
5131 if (do_q) then
5132 write(csv_unit,'(",",es24.16,",",l1,",",i0)',advance='no', &
5133 iostat=io_status) q_results(iseed)%logq0, &
5134 q_results(iseed)%valid_q0,q_results(iseed)%status_q0
5135 if (io_status/=0) exit
5136 endif
5137 if (do_qperp) then
5138 write(csv_unit,'(",",es24.16,",",l1,",",i0)',advance='no', &
5139 iostat=io_status) qperp_results(iseed)%logqperp, &
5140 qperp_results(iseed)%valid,qperp_results(iseed)%status
5141 if (io_status/=0) exit
5142 endif
5143 write(csv_unit,'(6(",",es24.16),7(",",i0))',advance='no', &
5144 iostat=io_status) topology(iseed)%backward_endpoint, &
5145 topology(iseed)%forward_endpoint, &
5146 topology(iseed)%backward_face,topology(iseed)%forward_face, &
5147 connection_type,topology(iseed)%backward_nstep, &
5148 topology(iseed)%forward_nstep, &
5149 topology(iseed)%backward_status, &
5150 topology(iseed)%forward_status
5151 if (io_status/=0) exit
5152 if (do_twist) then
5153 write(csv_unit,'(",",i0,",",l1)',advance='no',iostat=io_status) &
5154 topology(iseed)%status_twist,topology(iseed)%valid_twist
5155 if (io_status/=0) exit
5156 endif
5157 write(csv_unit,'(",",l1)',iostat=io_status) valid
5158 if (io_status/=0) then
5159 close(csv_unit)
5160 call mpistop(trim(caller)//' could not write CSV data')
5161 endif
5162 enddo
5163 enddo
5164
5165 close(csv_unit)
5166 end subroutine mt_write_spherical_rmin_csv
5167
5168 subroutine mt_write_spherical_topology_vtu(vtu_file,topology,n1,n2, &
5169 caller,do_twist,do_q,q_results,do_qperp,qperp_results)
5170 character(len=*), intent(in) :: vtu_file,caller
5171 integer, intent(in) :: n1,n2
5172 type(trace_topology_result), intent(in) :: topology(n1*n2)
5173 logical, intent(in) :: do_twist,do_q,do_qperp
5174 type(trace_qperp_result), intent(in) :: q_results(:)
5175 type(trace_qperp_result), intent(in) :: qperp_results(:)
5176
5177 integer :: vtu_unit,io_status,npoint,ncell
5178
5179 npoint=n1*n2
5180 ncell=0
5181 if (n1>1 .and. n2>1) ncell=(n1-1)*(n2-1)
5182 if (ncell==0) ncell=npoint
5183
5184 open(newunit=vtu_unit,file=trim(vtu_file),status='replace', &
5185 action='write',form='formatted',iostat=io_status)
5186 if (io_status/=0) then
5187 call mpistop(trim(caller)//' could not open VTU file')
5188 endif
5189
5190 call mt_write_vtu_file_header(vtu_unit,npoint,ncell)
5191 call mt_write_vtu_spherical_topology_pointdata(vtu_unit,topology, &
5192 npoint,do_twist,do_q,q_results,do_qperp,qperp_results,io_status)
5193 if (io_status==0) call mt_write_vtu_topology_points(vtu_unit, &
5194 topology,npoint,io_status)
5195 if (io_status==0) then
5196 if (n1>1 .and. n2>1) then
5197 call mt_write_vtu_quad_cells(vtu_unit,n1,n2,io_status)
5198 else
5199 call mt_write_vtu_vertex_cells(vtu_unit,npoint,io_status)
5200 endif
5201 endif
5202 if (io_status==0) call mt_write_vtu_file_footer(vtu_unit,io_status)
5203 close(vtu_unit)
5204 if (io_status/=0) then
5205 call mpistop(trim(caller)//' could not write VTU file')
5206 endif
5207 end subroutine mt_write_spherical_topology_vtu
5208
5209 subroutine mt_write_spherical_cloud_csv(topology,n1,n2,n3,csv_file, &
5210 caller,do_twist,do_qperp,qperp_results)
5211 integer, intent(in) :: n1,n2,n3
5212 type(trace_topology_result), intent(in) :: topology(n1*n2*n3)
5213 character(len=*), intent(in) :: csv_file,caller
5214 logical, intent(in) :: do_twist,do_qperp
5215 type(trace_qperp_result), intent(in) :: qperp_results(:)
5216
5217 integer :: csv_unit,io_status,i,j,k,iseed,connection_type
5218 logical :: valid
5219 character(len=2048) :: header
5220
5221 open(newunit=csv_unit,file=trim(csv_file),status='replace', &
5222 action='write',form='formatted',iostat=io_status)
5223 if (io_status/=0) then
5224 call mpistop(trim(caller)//' could not open CSV file')
5225 endif
5226
5227 header='i,j,k,seed_r,seed_theta,seed_phi,'// &
5228 'length_total,length_backward,length_forward'
5229 if (do_twist) then
5230 header=trim(header)//','// &
5231 'twist_total,twist_backward,twist_forward'
5232 endif
5233 if (do_qperp) then
5234 header=trim(header)//','// &
5235 'logQperp,valid_Qperp,status_Qperp'
5236 endif
5237 header=trim(header)//','// &
5238 'r_b,theta_b,phi_b,r_f,theta_f,phi_f,'// &
5239 'face_backward,face_forward,connection_type_spherical,'// &
5240 'nstep_backward,nstep_forward,status_backward,status_forward'
5241 if (do_twist) then
5242 header=trim(header)//','// &
5243 'status_twist,valid_twist'
5244 endif
5245 header=trim(header)//',valid'
5246 write(csv_unit,'(a)',iostat=io_status) trim(header)
5247 if (io_status/=0) then
5248 close(csv_unit)
5249 call mpistop(trim(caller)//' could not write CSV header')
5250 endif
5251
5252 do k=1,n3
5253 do j=1,n2
5254 do i=1,n1
5255 iseed=(k-1)*n1*n2+(j-1)*n1+i
5256 valid=topology(iseed)%valid
5257 connection_type=mt_spherical_connection_type( &
5258 topology(iseed)%backward_face,topology(iseed)%forward_face, &
5259 valid)
5260 write(csv_unit,'(i0,",",i0,",",i0,6(",",es24.16))', &
5261 advance='no',iostat=io_status) i,j,k,topology(iseed)%seed, &
5262 topology(iseed)%length_total, &
5263 topology(iseed)%length_backward, &
5264 topology(iseed)%length_forward
5265 if (io_status/=0) exit
5266 if (do_twist) then
5267 write(csv_unit,'(3(",",es24.16))',advance='no', &
5268 iostat=io_status) topology(iseed)%twist_total, &
5269 topology(iseed)%twist_backward, &
5270 topology(iseed)%twist_forward
5271 if (io_status/=0) exit
5272 endif
5273 if (do_qperp) then
5274 write(csv_unit,'(",",es24.16,",",l1,",",i0)',advance='no', &
5275 iostat=io_status) qperp_results(iseed)%logqperp, &
5276 qperp_results(iseed)%valid,qperp_results(iseed)%status
5277 if (io_status/=0) exit
5278 endif
5279 write(csv_unit,'(6(",",es24.16),7(",",i0))',advance='no', &
5280 iostat=io_status) topology(iseed)%backward_endpoint, &
5281 topology(iseed)%forward_endpoint, &
5282 topology(iseed)%backward_face,topology(iseed)%forward_face, &
5283 connection_type,topology(iseed)%backward_nstep, &
5284 topology(iseed)%forward_nstep, &
5285 topology(iseed)%backward_status, &
5286 topology(iseed)%forward_status
5287 if (io_status/=0) exit
5288 if (do_twist) then
5289 write(csv_unit,'(",",i0,",",l1)',advance='no', &
5290 iostat=io_status) topology(iseed)%status_twist, &
5291 topology(iseed)%valid_twist
5292 if (io_status/=0) exit
5293 endif
5294 write(csv_unit,'(",",l1)',iostat=io_status) valid
5295 if (io_status/=0) exit
5296 enddo
5297 if (io_status/=0) exit
5298 enddo
5299 if (io_status/=0) exit
5300 enddo
5301
5302 if (io_status/=0) then
5303 close(csv_unit)
5304 call mpistop(trim(caller)//' could not write CSV data')
5305 endif
5306 close(csv_unit)
5307 end subroutine mt_write_spherical_cloud_csv
5308
5309 subroutine mt_write_spherical_cloud_vtu(vtu_file,topology,npoint,caller, &
5310 do_twist,do_q,q_results,do_qperp,qperp_results)
5311 character(len=*), intent(in) :: vtu_file,caller
5312 integer, intent(in) :: npoint
5313 type(trace_topology_result), intent(in) :: topology(npoint)
5314 logical, intent(in) :: do_twist,do_q,do_qperp
5315 type(trace_qperp_result), intent(in) :: q_results(:)
5316 type(trace_qperp_result), intent(in) :: qperp_results(:)
5317
5318 integer :: vtu_unit,io_status
5319
5320 open(newunit=vtu_unit,file=trim(vtu_file),status='replace', &
5321 action='write',form='formatted',iostat=io_status)
5322 if (io_status/=0) then
5323 call mpistop(trim(caller)//' could not open VTU file')
5324 endif
5325
5326 call mt_write_vtu_file_header(vtu_unit,npoint,npoint)
5327 call mt_write_vtu_spherical_topology_pointdata(vtu_unit,topology, &
5328 npoint,do_twist,do_q,q_results,do_qperp,qperp_results,io_status)
5329 if (io_status==0) call mt_write_vtu_topology_points(vtu_unit, &
5330 topology,npoint,io_status)
5331 if (io_status==0) call mt_write_vtu_vertex_cells(vtu_unit,npoint, &
5332 io_status)
5333 if (io_status==0) call mt_write_vtu_file_footer(vtu_unit,io_status)
5334 close(vtu_unit)
5335 if (io_status/=0) then
5336 call mpistop(trim(caller)//' could not write VTU file')
5337 endif
5338 end subroutine mt_write_spherical_cloud_vtu
5339
5340 subroutine mt_write_fieldline_products_seeds_csv(length_results, &
5341 twist_results,q_results,qperp_results,nseed,csv_file,do_twist, &
5342 do_q,do_qperp)
5343 integer, intent(in) :: nseed
5344 type(trace_length_result), intent(in) :: length_results(nseed)
5345 type(trace_twist_result), intent(in) :: twist_results(:)
5346 type(trace_qperp_result), intent(in) :: q_results(:)
5347 type(trace_qperp_result), intent(in) :: qperp_results(:)
5348 character(len=*), intent(in) :: csv_file
5349 logical, intent(in) :: do_twist,do_q,do_qperp
5350
5351 double precision :: seed_xyz(3)
5352 double precision :: bseed_norm,bf_norm,bb_norm
5353 character(len=2048) :: header
5354 integer :: csv_unit,io_status,iseed
5355
5356 open(newunit=csv_unit,file=trim(csv_file),status='replace', &
5357 action='write',form='formatted',iostat=io_status)
5358 if (io_status/=0) then
5359 call mpistop('mt_fieldline_products_seeds could not open CSV file')
5360 endif
5361
5362 header='seed_id,seed_x,seed_y,seed_z,'// &
5363 'length_total,length_backward,length_forward,'// &
5364 'nstep_backward_length,nstep_forward_length,'// &
5365 'status_backward_length,status_forward_length'
5366 if (do_twist) then
5367 header=trim(header)//','// &
5368 'twist_total,twist_backward,twist_forward,'// &
5369 'nstep_backward_twist,nstep_forward_twist,'// &
5370 'status_backward_twist,status_forward_twist'
5371 endif
5372 if (do_q) then
5373 header=trim(header)//','// &
5374 'logQ,valid_Q,status_Q,'// &
5375 'face_forward_Q,face_backward_Q,'// &
5376 'status_forward_Q,status_backward_Q,'// &
5377 'length_forward_Q,length_backward_Q,'// &
5378 'x_f_Q,y_f_Q,z_f_Q,x_b_Q,y_b_Q,z_b_Q'
5379 endif
5380 if (do_qperp) then
5381 header=trim(header)//','// &
5382 'qperp,logqperp,valid_qperp,status_qperp,'// &
5383 'N2,bfactor,'// &
5384 'face_forward_qperp,face_backward_qperp,'// &
5385 'status_forward_qperp,status_backward_qperp,'// &
5386 'length_forward_qperp,length_backward_qperp,'// &
5387 'Bseed_norm,Bf_norm,Bb_norm,'// &
5388 'x_f_qperp,y_f_qperp,z_f_qperp,'// &
5389 'x_b_qperp,y_b_qperp,z_b_qperp'
5390 endif
5391 write(csv_unit,'(a)',iostat=io_status) trim(header)
5392 if (io_status/=0) then
5393 close(csv_unit)
5394 call mpistop('mt_fieldline_products_seeds could not write CSV header')
5395 endif
5396
5397 do iseed=1,nseed
5398 seed_xyz=0.d0
5399 seed_xyz(1:ndim)=length_results(iseed)%seed
5400 write(csv_unit,'(i0,6(",",es24.16),4(",",i0))', &
5401 advance='no',iostat=io_status) &
5402 iseed,seed_xyz,length_results(iseed)%total_length, &
5403 length_results(iseed)%backward_length, &
5404 length_results(iseed)%forward_length, &
5405 length_results(iseed)%backward_nstep, &
5406 length_results(iseed)%forward_nstep, &
5407 length_results(iseed)%backward_status, &
5408 length_results(iseed)%forward_status
5409 if (io_status/=0) exit
5410
5411 if (do_twist) then
5412 write(csv_unit,'(3(",",es24.16),4(",",i0))', &
5413 advance='no',iostat=io_status) &
5414 twist_results(iseed)%total_twist, &
5415 twist_results(iseed)%backward_twist, &
5416 twist_results(iseed)%forward_twist, &
5417 twist_results(iseed)%line%backward_nstep, &
5418 twist_results(iseed)%line%forward_nstep, &
5419 twist_results(iseed)%line%backward_status, &
5420 twist_results(iseed)%line%forward_status
5421 if (io_status/=0) exit
5422 endif
5423
5424 if (do_q) then
5425 write(csv_unit, &
5426 '(",",es24.16,",",l1,",",i0,4(",",i0),8(",",es24.16))', &
5427 advance='no',iostat=io_status) &
5428 q_results(iseed)%logq0, &
5429 q_results(iseed)%valid_q0,q_results(iseed)%status_q0, &
5430 q_results(iseed)%forward_face, &
5431 q_results(iseed)%backward_face, &
5432 q_results(iseed)%forward_status, &
5433 q_results(iseed)%backward_status, &
5434 q_results(iseed)%forward_length, &
5435 q_results(iseed)%backward_length, &
5436 q_results(iseed)%forward_endpoint, &
5437 q_results(iseed)%backward_endpoint
5438 if (io_status/=0) exit
5439 endif
5440
5441 if (do_qperp) then
5442 bseed_norm=dsqrt(sum(qperp_results(iseed)%B_seed**2))
5443 bf_norm=dsqrt(sum(qperp_results(iseed)%forward_B**2))
5444 bb_norm=dsqrt(sum(qperp_results(iseed)%backward_B**2))
5445 write(csv_unit, &
5446 '(2(",",es24.16),",",l1,",",i0,2(",",es24.16),'// &
5447 '4(",",i0),11(",",es24.16))', &
5448 advance='no',iostat=io_status) &
5449 qperp_results(iseed)%qperp, &
5450 qperp_results(iseed)%logqperp, &
5451 qperp_results(iseed)%valid,qperp_results(iseed)%status, &
5452 qperp_results(iseed)%N2,qperp_results(iseed)%bfactor, &
5453 qperp_results(iseed)%forward_face, &
5454 qperp_results(iseed)%backward_face, &
5455 qperp_results(iseed)%forward_status, &
5456 qperp_results(iseed)%backward_status, &
5457 qperp_results(iseed)%forward_length, &
5458 qperp_results(iseed)%backward_length, &
5459 bseed_norm,bf_norm,bb_norm, &
5460 qperp_results(iseed)%forward_endpoint, &
5461 qperp_results(iseed)%backward_endpoint
5462 if (io_status/=0) exit
5463 endif
5464
5465 write(csv_unit,'()',iostat=io_status)
5466 if (io_status/=0) exit
5467 enddo
5468
5469 if (io_status/=0) then
5470 close(csv_unit)
5471 call mpistop('mt_fieldline_products_seeds could not write CSV data')
5472 endif
5473 close(csv_unit)
5474 end subroutine mt_write_fieldline_products_seeds_csv
5475
5476 subroutine mt_fieldline_products_append_header(header,do_twist,do_q,do_qperp)
5477 character(len=*), intent(inout) :: header
5478 logical, intent(in) :: do_twist,do_q,do_qperp
5479
5480 header=trim(header)//','// &
5481 'length_total,length_backward,length_forward,'// &
5482 'nstep_backward_length,nstep_forward_length,'// &
5483 'status_backward_length,status_forward_length'
5484 if (do_twist) then
5485 header=trim(header)//','// &
5486 'twist_total,twist_backward,twist_forward,'// &
5487 'nstep_backward_twist,nstep_forward_twist,'// &
5488 'status_backward_twist,status_forward_twist'
5489 endif
5490 if (do_q) then
5491 header=trim(header)//','// &
5492 'logQ,valid_Q,status_Q,'// &
5493 'face_forward_Q,face_backward_Q,'// &
5494 'status_forward_Q,status_backward_Q,'// &
5495 'length_forward_Q,length_backward_Q,'// &
5496 'x_f_Q,y_f_Q,z_f_Q,x_b_Q,y_b_Q,z_b_Q'
5497 endif
5498 if (do_qperp) then
5499 header=trim(header)//','// &
5500 'qperp,logqperp,valid_qperp,status_qperp,'// &
5501 'N2,bfactor,'// &
5502 'face_forward_qperp,face_backward_qperp,'// &
5503 'status_forward_qperp,status_backward_qperp,'// &
5504 'length_forward_qperp,length_backward_qperp,'// &
5505 'Bseed_norm,Bf_norm,Bb_norm,'// &
5506 'x_f_qperp,y_f_qperp,z_f_qperp,'// &
5507 'x_b_qperp,y_b_qperp,z_b_qperp'
5508 endif
5509 end subroutine mt_fieldline_products_append_header
5510
5511 subroutine mt_write_fieldline_products_plane_arbitrary_header(csv_file, &
5512 caller,do_twist,do_q,do_qperp)
5513 character(len=*), intent(in) :: csv_file,caller
5514 logical, intent(in) :: do_twist,do_q,do_qperp
5515
5516 character(len=2048) :: header
5517 integer :: csv_unit,io_status
5518
5519 open(newunit=csv_unit,file=trim(csv_file),status='replace', &
5520 action='write',form='formatted',iostat=io_status)
5521 if (io_status/=0) then
5522 call mpistop(trim(caller)//' could not open CSV file')
5523 endif
5524
5525 header='i,j,s1,s2,seed_x,seed_y,seed_z'
5526 call mt_fieldline_products_append_header(header,do_twist,do_q,do_qperp)
5527 write(csv_unit,'(a)',iostat=io_status) trim(header)
5528 if (io_status/=0) then
5529 close(csv_unit)
5530 call mpistop(trim(caller)//' could not write CSV header')
5531 endif
5532
5533 close(csv_unit)
5534 end subroutine mt_write_fieldline_products_plane_arbitrary_header
5535
5536 subroutine mt_write_fieldline_products_plane_arbitrary_csv( &
5537 length_results,twist_results,q_results,qperp_results,s1,s2,n1,n2, &
5538 csv_file,do_twist,do_q,do_qperp,caller)
5539 integer, intent(in) :: n1,n2
5540 type(trace_length_result), intent(in) :: length_results(n1*n2)
5541 type(trace_twist_result), intent(in) :: twist_results(:)
5542 type(trace_qperp_result), intent(in) :: q_results(:)
5543 type(trace_qperp_result), intent(in) :: qperp_results(:)
5544 double precision, intent(in) :: s1(n1*n2),s2(n1*n2)
5545 character(len=*), intent(in) :: csv_file,caller
5546 logical, intent(in) :: do_twist,do_q,do_qperp
5547
5548 double precision :: seed_xyz(3)
5549 double precision :: bseed_norm,bf_norm,bb_norm
5550 character(len=2048) :: header
5551 integer :: csv_unit,io_status,i,j,iseed
5552
5553 open(newunit=csv_unit,file=trim(csv_file),status='replace', &
5554 action='write',form='formatted',iostat=io_status)
5555 if (io_status/=0) then
5556 call mpistop(trim(caller)//' could not open CSV file')
5557 endif
5558
5559 header='i,j,s1,s2,seed_x,seed_y,seed_z'
5560 call mt_fieldline_products_append_header(header,do_twist,do_q,do_qperp)
5561 write(csv_unit,'(a)',iostat=io_status) trim(header)
5562 if (io_status/=0) then
5563 close(csv_unit)
5564 call mpistop(trim(caller)//' could not write CSV header')
5565 endif
5566
5567 do j=1,n2
5568 do i=1,n1
5569 iseed=(j-1)*n1+i
5570 seed_xyz=0.d0
5571 seed_xyz(1:ndim)=length_results(iseed)%seed
5572 write(csv_unit,'(i0,",",i0,8(",",es24.16),4(",",i0))', &
5573 advance='no',iostat=io_status) &
5574 i,j,s1(iseed),s2(iseed),seed_xyz, &
5575 length_results(iseed)%total_length, &
5576 length_results(iseed)%backward_length, &
5577 length_results(iseed)%forward_length, &
5578 length_results(iseed)%backward_nstep, &
5579 length_results(iseed)%forward_nstep, &
5580 length_results(iseed)%backward_status, &
5581 length_results(iseed)%forward_status
5582 if (io_status/=0) exit
5583
5584 if (do_twist) then
5585 write(csv_unit,'(3(",",es24.16),4(",",i0))', &
5586 advance='no',iostat=io_status) &
5587 twist_results(iseed)%total_twist, &
5588 twist_results(iseed)%backward_twist, &
5589 twist_results(iseed)%forward_twist, &
5590 twist_results(iseed)%line%backward_nstep, &
5591 twist_results(iseed)%line%forward_nstep, &
5592 twist_results(iseed)%line%backward_status, &
5593 twist_results(iseed)%line%forward_status
5594 if (io_status/=0) exit
5595 endif
5596
5597 if (do_q) then
5598 write(csv_unit, &
5599 '(",",es24.16,",",l1,",",i0,4(",",i0),8(",",es24.16))', &
5600 advance='no',iostat=io_status) &
5601 q_results(iseed)%logq0, &
5602 q_results(iseed)%valid_q0,q_results(iseed)%status_q0, &
5603 q_results(iseed)%forward_face, &
5604 q_results(iseed)%backward_face, &
5605 q_results(iseed)%forward_status, &
5606 q_results(iseed)%backward_status, &
5607 q_results(iseed)%forward_length, &
5608 q_results(iseed)%backward_length, &
5609 q_results(iseed)%forward_endpoint, &
5610 q_results(iseed)%backward_endpoint
5611 if (io_status/=0) exit
5612 endif
5613
5614 if (do_qperp) then
5615 bseed_norm=dsqrt(sum(qperp_results(iseed)%B_seed**2))
5616 bf_norm=dsqrt(sum(qperp_results(iseed)%forward_B**2))
5617 bb_norm=dsqrt(sum(qperp_results(iseed)%backward_B**2))
5618 write(csv_unit, &
5619 '(2(",",es24.16),",",l1,",",i0,2(",",es24.16),'// &
5620 '4(",",i0),11(",",es24.16))', &
5621 advance='no',iostat=io_status) &
5622 qperp_results(iseed)%qperp, &
5623 qperp_results(iseed)%logqperp, &
5624 qperp_results(iseed)%valid,qperp_results(iseed)%status, &
5625 qperp_results(iseed)%N2,qperp_results(iseed)%bfactor, &
5626 qperp_results(iseed)%forward_face, &
5627 qperp_results(iseed)%backward_face, &
5628 qperp_results(iseed)%forward_status, &
5629 qperp_results(iseed)%backward_status, &
5630 qperp_results(iseed)%forward_length, &
5631 qperp_results(iseed)%backward_length, &
5632 bseed_norm,bf_norm,bb_norm, &
5633 qperp_results(iseed)%forward_endpoint, &
5634 qperp_results(iseed)%backward_endpoint
5635 if (io_status/=0) exit
5636 endif
5637
5638 write(csv_unit,'()',iostat=io_status)
5639 if (io_status/=0) exit
5640 enddo
5641 if (io_status/=0) exit
5642 enddo
5643
5644 if (io_status/=0) then
5645 close(csv_unit)
5646 call mpistop(trim(caller)//' could not write CSV data')
5647 endif
5648 close(csv_unit)
5649 end subroutine mt_write_fieldline_products_plane_arbitrary_csv
5650
5651 subroutine mt_write_fieldline_products_vtu_empty(vtu_file,do_twist, &
5652 do_q,do_qperp,caller,do_length)
5653 character(len=*), intent(in) :: vtu_file,caller
5654 logical, intent(in) :: do_twist,do_q,do_qperp
5655 logical, intent(in), optional :: do_length
5656
5657 integer :: vtu_unit,io_status
5658 logical :: do_length_eff
5659
5660 open(newunit=vtu_unit,file=trim(vtu_file),status='replace', &
5661 action='write',form='formatted',iostat=io_status)
5662 if (io_status/=0) then
5663 call mpistop(trim(caller)//' could not open VTU file')
5664 endif
5665
5666 call mt_write_vtu_file_header(vtu_unit,0,0)
5667 do_length_eff=.true.
5668 if (present(do_length)) do_length_eff=do_length
5669 call mt_write_vtu_empty_pointdata(vtu_unit,do_length_eff,do_twist, &
5670 do_q,do_qperp)
5671 write(vtu_unit,'(a)',iostat=io_status) '<CellData>'
5672 if (io_status==0) write(vtu_unit,'(a)',iostat=io_status) '</CellData>'
5673 if (io_status==0) then
5674 write(vtu_unit,'(a)',iostat=io_status) '<Points>'
5675 endif
5676 if (io_status==0) then
5677 write(vtu_unit,'(a)',iostat=io_status) &
5678 '<DataArray type="Float64" NumberOfComponents="3" format="ascii">'
5679 endif
5680 if (io_status==0) write(vtu_unit,'(a)',iostat=io_status) '</DataArray>'
5681 if (io_status==0) write(vtu_unit,'(a)',iostat=io_status) '</Points>'
5682 if (io_status==0) call mt_write_vtu_cells_empty(vtu_unit,io_status)
5683 if (io_status==0) call mt_write_vtu_file_footer(vtu_unit,io_status)
5684 if (io_status/=0) then
5685 close(vtu_unit)
5686 call mpistop(trim(caller)//' could not write VTU file')
5687 endif
5688
5689 close(vtu_unit)
5690 end subroutine mt_write_fieldline_products_vtu_empty
5691
5692 subroutine mt_write_fieldline_products_vtu_vertices(vtu_file, &
5693 length_results,twist_results,q_results,qperp_results,npoint, &
5694 do_length,do_twist,do_q,do_qperp,caller)
5695 integer, intent(in) :: npoint
5696 type(trace_length_result), intent(in) :: length_results(npoint)
5697 type(trace_twist_result), intent(in) :: twist_results(:)
5698 type(trace_qperp_result), intent(in) :: q_results(:)
5699 type(trace_qperp_result), intent(in) :: qperp_results(:)
5700 character(len=*), intent(in) :: vtu_file,caller
5701 logical, intent(in) :: do_length,do_twist,do_q,do_qperp
5702
5703 integer :: vtu_unit,io_status
5704
5705 open(newunit=vtu_unit,file=trim(vtu_file),status='replace', &
5706 action='write',form='formatted',iostat=io_status)
5707 if (io_status/=0) then
5708 call mpistop(trim(caller)//' could not open VTU file')
5709 endif
5710
5711 call mt_write_vtu_file_header(vtu_unit,npoint,npoint)
5712 call mt_write_vtu_product_pointdata(vtu_unit,length_results, &
5713 twist_results,q_results,qperp_results,npoint,do_twist,do_q, &
5714 do_qperp,io_status,do_length=do_length)
5715 if (io_status==0) write(vtu_unit,'(a)',iostat=io_status) '<CellData>'
5716 if (io_status==0) write(vtu_unit,'(a)',iostat=io_status) '</CellData>'
5717 if (io_status==0) call mt_write_vtu_points(vtu_unit,length_results, &
5718 npoint,io_status)
5719 if (io_status==0) call mt_write_vtu_vertex_cells(vtu_unit,npoint, &
5720 io_status)
5721 if (io_status==0) call mt_write_vtu_file_footer(vtu_unit,io_status)
5722 if (io_status/=0) then
5723 close(vtu_unit)
5724 call mpistop(trim(caller)//' could not write VTU file')
5725 endif
5726
5727 close(vtu_unit)
5728 end subroutine mt_write_fieldline_products_vtu_vertices
5729
5730 subroutine mt_write_fieldline_products_vtu_plane(vtu_file, &
5731 length_results,twist_results,q_results,qperp_results,n1,n2,do_twist, &
5732 do_q,do_qperp,caller,do_length)
5733 integer, intent(in) :: n1,n2
5734 type(trace_length_result), intent(in) :: length_results(n1*n2)
5735 type(trace_twist_result), intent(in) :: twist_results(:)
5736 type(trace_qperp_result), intent(in) :: q_results(:)
5737 type(trace_qperp_result), intent(in) :: qperp_results(:)
5738 character(len=*), intent(in) :: vtu_file,caller
5739 logical, intent(in) :: do_twist,do_q,do_qperp
5740 logical, intent(in), optional :: do_length
5741
5742 integer :: npoint,ncell,vtu_unit,io_status
5743 logical :: do_length_eff
5744
5745 npoint=n1*n2
5746 if (n1>1 .and. n2>1) then
5747 ncell=(n1-1)*(n2-1)
5748 else
5749 ncell=npoint
5750 endif
5751
5752 open(newunit=vtu_unit,file=trim(vtu_file),status='replace', &
5753 action='write',form='formatted',iostat=io_status)
5754 if (io_status/=0) then
5755 call mpistop(trim(caller)//' could not open VTU file')
5756 endif
5757
5758 call mt_write_vtu_file_header(vtu_unit,npoint,ncell)
5759 do_length_eff=.true.
5760 if (present(do_length)) do_length_eff=do_length
5761 call mt_write_vtu_product_pointdata(vtu_unit,length_results, &
5762 twist_results,q_results,qperp_results,npoint,do_twist,do_q, &
5763 do_qperp,io_status,do_length=do_length_eff)
5764 if (io_status==0) write(vtu_unit,'(a)',iostat=io_status) '<CellData>'
5765 if (io_status==0) write(vtu_unit,'(a)',iostat=io_status) '</CellData>'
5766 if (io_status==0) call mt_write_vtu_points(vtu_unit,length_results, &
5767 npoint,io_status)
5768 if (io_status==0) then
5769 if (n1>1 .and. n2>1) then
5770 call mt_write_vtu_quad_cells(vtu_unit,n1,n2,io_status)
5771 else
5772 call mt_write_vtu_vertex_cells(vtu_unit,npoint,io_status)
5773 endif
5774 endif
5775 if (io_status==0) call mt_write_vtu_file_footer(vtu_unit,io_status)
5776 if (io_status/=0) then
5777 close(vtu_unit)
5778 call mpistop(trim(caller)//' could not write VTU file')
5779 endif
5780
5781 close(vtu_unit)
5782 end subroutine mt_write_fieldline_products_vtu_plane
5783
5784 subroutine mt_write_qsl_plane_vtu(vtu_file,length_results,twist_results, &
5785 mapping_results,qperp_results,n1,n2,caller)
5786 integer, intent(in) :: n1,n2
5787 type(trace_length_result), intent(in) :: length_results(n1*n2)
5788 type(trace_twist_result), intent(in) :: twist_results(n1*n2)
5789 type(trace_mapping_result), intent(in) :: mapping_results(n1*n2)
5790 type(trace_qperp_result), intent(in) :: qperp_results(n1*n2)
5791 character(len=*), intent(in) :: vtu_file,caller
5792
5793 integer :: npoint,ncell,vtu_unit,io_status
5794
5795 npoint=n1*n2
5796 if (n1>1 .and. n2>1) then
5797 ncell=(n1-1)*(n2-1)
5798 else
5799 ncell=npoint
5800 endif
5801
5802 open(newunit=vtu_unit,file=trim(vtu_file),status='replace', &
5803 action='write',form='formatted',iostat=io_status)
5804 if (io_status/=0) then
5805 call mpistop(trim(caller)//' could not open VTU file')
5806 endif
5807
5808 call mt_write_vtu_file_header(vtu_unit,npoint,ncell)
5809 call mt_write_qsl_plane_vtu_pointdata(vtu_unit,length_results, &
5810 twist_results,mapping_results,qperp_results,npoint,io_status)
5811 if (io_status==0) write(vtu_unit,'(a)',iostat=io_status) '<CellData>'
5812 if (io_status==0) write(vtu_unit,'(a)',iostat=io_status) '</CellData>'
5813 if (io_status==0) call mt_write_vtu_points(vtu_unit,length_results, &
5814 npoint,io_status)
5815 if (io_status==0) then
5816 if (n1>1 .and. n2>1) then
5817 call mt_write_vtu_quad_cells(vtu_unit,n1,n2,io_status)
5818 else
5819 call mt_write_vtu_vertex_cells(vtu_unit,npoint,io_status)
5820 endif
5821 endif
5822 if (io_status==0) call mt_write_vtu_file_footer(vtu_unit,io_status)
5823 if (io_status/=0) then
5824 close(vtu_unit)
5825 call mpistop(trim(caller)//' could not write VTU file')
5826 endif
5827
5828 close(vtu_unit)
5829 end subroutine mt_write_qsl_plane_vtu
5830
5831 subroutine mt_write_qsl_plane_vtu_pointdata(vtu_unit,length_results, &
5832 twist_results,mapping_results,qperp_results,npoint,io_status)
5833 integer, intent(in) :: vtu_unit,npoint
5834 type(trace_length_result), intent(in) :: length_results(npoint)
5835 type(trace_twist_result), intent(in) :: twist_results(npoint)
5836 type(trace_mapping_result), intent(in) :: mapping_results(npoint)
5837 type(trace_qperp_result), intent(in) :: qperp_results(npoint)
5838 integer, intent(inout) :: io_status
5839
5840 write(vtu_unit,'(a)',iostat=io_status) '<PointData>'
5841 if (io_status/=0) return
5842
5843 if (mt_vtk_detail_is_full()) then
5844 call mt_write_vtu_length_pointdata(vtu_unit,length_results,npoint, &
5845 io_status)
5846 call mt_write_vtu_twist_pointdata(vtu_unit,twist_results,npoint, &
5847 io_status)
5848 call mt_write_vtu_mapping_pointdata(vtu_unit,mapping_results,npoint, &
5849 io_status)
5850 call mt_write_vtu_q_product_pointdata(vtu_unit,qperp_results, &
5851 npoint,.true.,io_status)
5852 call mt_write_vtu_qperp_public_pointdata(vtu_unit,qperp_results, &
5853 npoint,io_status)
5854 call mt_write_vtu_qperp_method2_pointdata(vtu_unit,qperp_results, &
5855 npoint,io_status)
5856 else
5857 call mt_write_vtu_qsl_minimal_pointdata(vtu_unit,length_results, &
5858 twist_results,qperp_results,npoint,io_status)
5859 endif
5860
5861 if (io_status==0) write(vtu_unit,'(a)',iostat=io_status) '</PointData>'
5862 end subroutine mt_write_qsl_plane_vtu_pointdata
5863
5864 subroutine mt_write_vtu_qsl_minimal_pointdata(vtu_unit,length_results, &
5865 twist_results,qperp_results,npoint,io_status)
5866 integer, intent(in) :: vtu_unit,npoint
5867 type(trace_length_result), intent(in) :: length_results(npoint)
5868 type(trace_twist_result), intent(in) :: twist_results(npoint)
5869 type(trace_qperp_result), intent(in) :: qperp_results(npoint)
5870 integer, intent(inout) :: io_status
5871
5872 integer :: ipoint
5873
5874 call mt_write_vtu_float_array_start(vtu_unit,'length_total',io_status)
5875 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
5876 (mt_visual_float(length_results(ipoint)%total_length), &
5877 ipoint=1,npoint)
5878 call mt_write_vtu_data_array_end(vtu_unit,io_status)
5879
5880 call mt_write_vtu_float_array_start(vtu_unit,'twist_total',io_status)
5881 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
5882 (mt_visual_float(twist_results(ipoint)%total_twist), &
5883 ipoint=1,npoint)
5884 call mt_write_vtu_data_array_end(vtu_unit,io_status)
5885
5886 call mt_write_vtu_float_array_start(vtu_unit,'logQ',io_status)
5887 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
5888 (mt_visual_valid_float(qperp_results(ipoint)%logq0, &
5889 qperp_results(ipoint)%valid_q0),ipoint=1,npoint)
5890 call mt_write_vtu_data_array_end(vtu_unit,io_status)
5891
5892 call mt_write_vtu_float_array_start(vtu_unit,'logQperp',io_status)
5893 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
5894 (mt_visual_valid_float(qperp_results(ipoint)%logqperp, &
5895 qperp_results(ipoint)%valid),ipoint=1,npoint)
5896 call mt_write_vtu_data_array_end(vtu_unit,io_status)
5897
5898 end subroutine mt_write_vtu_qsl_minimal_pointdata
5899
5900 double precision function mt_vti_axis_spacing(xmin,xmax,n)
5901 integer, intent(in) :: n
5902 double precision, intent(in) :: xmin,xmax
5903
5904 if (n>1) then
5905 mt_vti_axis_spacing=(xmax-xmin)/dble(n-1)
5906 else
5907 mt_vti_axis_spacing=0.d0
5908 endif
5909 end function mt_vti_axis_spacing
5910
5911 subroutine mt_allocate_volume_products(products,nseed,do_twist,do_q, &
5912 do_qperp)
5913 type(mt_volume_products), intent(inout) :: products
5914 integer, intent(in) :: nseed
5915 logical, intent(in) :: do_twist,do_q,do_qperp
5916
5917 allocate(products%length_total(nseed))
5918 allocate(products%length_backward(nseed))
5919 allocate(products%length_forward(nseed))
5920 allocate(products%nstep_backward_length(nseed))
5921 allocate(products%nstep_forward_length(nseed))
5922 allocate(products%status_backward_length(nseed))
5923 allocate(products%status_forward_length(nseed))
5924
5925 if (do_twist) then
5926 allocate(products%twist_total(nseed))
5927 allocate(products%twist_backward(nseed))
5928 allocate(products%twist_forward(nseed))
5929 allocate(products%nstep_backward_twist(nseed))
5930 allocate(products%nstep_forward_twist(nseed))
5931 allocate(products%status_backward_twist(nseed))
5932 allocate(products%status_forward_twist(nseed))
5933 endif
5934
5935 if (do_q) then
5936 allocate(products%q(nseed))
5937 allocate(products%logq(nseed))
5938 allocate(products%N2_q(nseed))
5939 allocate(products%bfactor_q(nseed))
5940 allocate(products%length_forward_q(nseed))
5941 allocate(products%length_backward_q(nseed))
5942 allocate(products%Bseed_norm_q(nseed))
5943 allocate(products%Bf_norm_q(nseed))
5944 allocate(products%Bb_norm_q(nseed))
5945 allocate(products%valid_q(nseed))
5946 allocate(products%status_q(nseed))
5947 allocate(products%face_forward_q(nseed))
5948 allocate(products%face_backward_q(nseed))
5949 allocate(products%status_forward_q(nseed))
5950 allocate(products%status_backward_q(nseed))
5951 endif
5952
5953 if (do_qperp) then
5954 allocate(products%qperp(nseed))
5955 allocate(products%logqperp(nseed))
5956 allocate(products%N2(nseed))
5957 allocate(products%bfactor(nseed))
5958 allocate(products%length_forward_qperp(nseed))
5959 allocate(products%length_backward_qperp(nseed))
5960 allocate(products%Bseed_norm(nseed))
5961 allocate(products%Bf_norm(nseed))
5962 allocate(products%Bb_norm(nseed))
5963 allocate(products%valid_qperp(nseed))
5964 allocate(products%status_qperp(nseed))
5965 allocate(products%face_forward_qperp(nseed))
5966 allocate(products%face_backward_qperp(nseed))
5967 allocate(products%status_forward_qperp(nseed))
5968 allocate(products%status_backward_qperp(nseed))
5969 endif
5970 end subroutine mt_allocate_volume_products
5971
5972 subroutine mt_deallocate_volume_products(products)
5973 type(mt_volume_products), intent(inout) :: products
5974
5975 if (allocated(products%length_total)) deallocate(products%length_total)
5976 if (allocated(products%length_backward)) deallocate(products%length_backward)
5977 if (allocated(products%length_forward)) deallocate(products%length_forward)
5978 if (allocated(products%nstep_backward_length)) &
5979 deallocate(products%nstep_backward_length)
5980 if (allocated(products%nstep_forward_length)) &
5981 deallocate(products%nstep_forward_length)
5982 if (allocated(products%status_backward_length)) &
5983 deallocate(products%status_backward_length)
5984 if (allocated(products%status_forward_length)) &
5985 deallocate(products%status_forward_length)
5986
5987 if (allocated(products%twist_total)) deallocate(products%twist_total)
5988 if (allocated(products%twist_backward)) deallocate(products%twist_backward)
5989 if (allocated(products%twist_forward)) deallocate(products%twist_forward)
5990 if (allocated(products%nstep_backward_twist)) &
5991 deallocate(products%nstep_backward_twist)
5992 if (allocated(products%nstep_forward_twist)) &
5993 deallocate(products%nstep_forward_twist)
5994 if (allocated(products%status_backward_twist)) &
5995 deallocate(products%status_backward_twist)
5996 if (allocated(products%status_forward_twist)) &
5997 deallocate(products%status_forward_twist)
5998
5999 if (allocated(products%q)) deallocate(products%q)
6000 if (allocated(products%logq)) deallocate(products%logq)
6001 if (allocated(products%N2_q)) deallocate(products%N2_q)
6002 if (allocated(products%bfactor_q)) deallocate(products%bfactor_q)
6003 if (allocated(products%length_forward_q)) &
6004 deallocate(products%length_forward_q)
6005 if (allocated(products%length_backward_q)) &
6006 deallocate(products%length_backward_q)
6007 if (allocated(products%Bseed_norm_q)) deallocate(products%Bseed_norm_q)
6008 if (allocated(products%Bf_norm_q)) deallocate(products%Bf_norm_q)
6009 if (allocated(products%Bb_norm_q)) deallocate(products%Bb_norm_q)
6010 if (allocated(products%valid_q)) deallocate(products%valid_q)
6011 if (allocated(products%status_q)) deallocate(products%status_q)
6012 if (allocated(products%face_forward_q)) &
6013 deallocate(products%face_forward_q)
6014 if (allocated(products%face_backward_q)) &
6015 deallocate(products%face_backward_q)
6016 if (allocated(products%status_forward_q)) &
6017 deallocate(products%status_forward_q)
6018 if (allocated(products%status_backward_q)) &
6019 deallocate(products%status_backward_q)
6020
6021 if (allocated(products%qperp)) deallocate(products%qperp)
6022 if (allocated(products%logqperp)) deallocate(products%logqperp)
6023 if (allocated(products%N2)) deallocate(products%N2)
6024 if (allocated(products%bfactor)) deallocate(products%bfactor)
6025 if (allocated(products%length_forward_qperp)) &
6026 deallocate(products%length_forward_qperp)
6027 if (allocated(products%length_backward_qperp)) &
6028 deallocate(products%length_backward_qperp)
6029 if (allocated(products%Bseed_norm)) deallocate(products%Bseed_norm)
6030 if (allocated(products%Bf_norm)) deallocate(products%Bf_norm)
6031 if (allocated(products%Bb_norm)) deallocate(products%Bb_norm)
6032 if (allocated(products%valid_qperp)) deallocate(products%valid_qperp)
6033 if (allocated(products%status_qperp)) deallocate(products%status_qperp)
6034 if (allocated(products%face_forward_qperp)) &
6035 deallocate(products%face_forward_qperp)
6036 if (allocated(products%face_backward_qperp)) &
6037 deallocate(products%face_backward_qperp)
6038 if (allocated(products%status_forward_qperp)) &
6039 deallocate(products%status_forward_qperp)
6040 if (allocated(products%status_backward_qperp)) &
6041 deallocate(products%status_backward_qperp)
6042 end subroutine mt_deallocate_volume_products
6043
6044 subroutine mt_build_volume_slab_seeds(seeds,xmin,ymin,zmin,spacing, &
6045 nx,ny,k_start,slab_nz)
6046 double precision, intent(out) :: seeds(:,:)
6047 double precision, intent(in) :: xmin,ymin,zmin,spacing(3)
6048 integer, intent(in) :: nx,ny,k_start,slab_nz
6049
6050 integer :: i,j,k,kk,iseed
6051
6052 do kk=1,slab_nz
6053 k=k_start+kk-1
6054 do j=1,ny
6055 do i=1,nx
6056 iseed=(kk-1)*nx*ny+(j-1)*nx+i
6057 seeds(iseed,1)=xmin+dble(i-1)*spacing(1)
6058 seeds(iseed,2)=ymin+dble(j-1)*spacing(2)
6059 seeds(iseed,3)=zmin+dble(k-1)*spacing(3)
6060 enddo
6061 enddo
6062 enddo
6063 end subroutine mt_build_volume_slab_seeds
6064
6065 subroutine mt_copy_volume_length_slab(products,results,nx,ny,k_start, &
6066 slab_nz)
6067 type(mt_volume_products), intent(inout) :: products
6068 type(trace_length_result), intent(in) :: results(:)
6069 integer, intent(in) :: nx,ny,k_start,slab_nz
6070
6071 integer :: i,j,kk,k,ilocal,iglobal
6072
6073 do kk=1,slab_nz
6074 k=k_start+kk-1
6075 do j=1,ny
6076 do i=1,nx
6077 ilocal=(kk-1)*nx*ny+(j-1)*nx+i
6078 iglobal=(k-1)*nx*ny+(j-1)*nx+i
6079 products%length_total(iglobal)=results(ilocal)%total_length
6080 products%length_backward(iglobal)=results(ilocal)%backward_length
6081 products%length_forward(iglobal)=results(ilocal)%forward_length
6082 products%nstep_backward_length(iglobal)= &
6083 results(ilocal)%backward_nstep
6084 products%nstep_forward_length(iglobal)= &
6085 results(ilocal)%forward_nstep
6086 products%status_backward_length(iglobal)= &
6087 results(ilocal)%backward_status
6088 products%status_forward_length(iglobal)= &
6089 results(ilocal)%forward_status
6090 enddo
6091 enddo
6092 enddo
6093 end subroutine mt_copy_volume_length_slab
6094
6095 subroutine mt_copy_volume_twist_slab(products,results,nx,ny,k_start, &
6096 slab_nz)
6097 type(mt_volume_products), intent(inout) :: products
6098 type(trace_twist_result), intent(in) :: results(:)
6099 integer, intent(in) :: nx,ny,k_start,slab_nz
6100
6101 integer :: i,j,kk,k,ilocal,iglobal
6102
6103 do kk=1,slab_nz
6104 k=k_start+kk-1
6105 do j=1,ny
6106 do i=1,nx
6107 ilocal=(kk-1)*nx*ny+(j-1)*nx+i
6108 iglobal=(k-1)*nx*ny+(j-1)*nx+i
6109 products%twist_total(iglobal)=results(ilocal)%total_twist
6110 products%twist_backward(iglobal)=results(ilocal)%backward_twist
6111 products%twist_forward(iglobal)=results(ilocal)%forward_twist
6112 products%nstep_backward_twist(iglobal)= &
6113 results(ilocal)%line%backward_nstep
6114 products%nstep_forward_twist(iglobal)= &
6115 results(ilocal)%line%forward_nstep
6116 products%status_backward_twist(iglobal)= &
6117 results(ilocal)%line%backward_status
6118 products%status_forward_twist(iglobal)= &
6119 results(ilocal)%line%forward_status
6120 enddo
6121 enddo
6122 enddo
6123 end subroutine mt_copy_volume_twist_slab
6124
6125 subroutine mt_copy_volume_q_slab(products,results,nx,ny,k_start,slab_nz)
6126 type(mt_volume_products), intent(inout) :: products
6127 type(trace_qperp_result), intent(in) :: results(:)
6128 integer, intent(in) :: nx,ny,k_start,slab_nz
6129
6130 integer :: i,j,kk,k,ilocal,iglobal
6131
6132 do kk=1,slab_nz
6133 k=k_start+kk-1
6134 do j=1,ny
6135 do i=1,nx
6136 ilocal=(kk-1)*nx*ny+(j-1)*nx+i
6137 iglobal=(k-1)*nx*ny+(j-1)*nx+i
6138 products%q(iglobal)=results(ilocal)%q0
6139 products%logq(iglobal)=results(ilocal)%logq0
6140 products%N2_q(iglobal)=results(ilocal)%N2_qperp0
6141 products%bfactor_q(iglobal)=results(ilocal)%bfactor_qperp0
6142 products%length_forward_q(iglobal)=results(ilocal)%forward_length
6143 products%length_backward_q(iglobal)=results(ilocal)%backward_length
6144 products%Bseed_norm_q(iglobal)=dsqrt(sum(results(ilocal)%B_seed**2))
6145 products%Bf_norm_q(iglobal)=dsqrt(sum(results(ilocal)%forward_B**2))
6146 products%Bb_norm_q(iglobal)=dsqrt(sum(results(ilocal)%backward_B**2))
6147 products%valid_q(iglobal)=merge(1,0,results(ilocal)%valid_q0)
6148 products%status_q(iglobal)=results(ilocal)%status_q0
6149 products%face_forward_q(iglobal)=results(ilocal)%forward_face
6150 products%face_backward_q(iglobal)=results(ilocal)%backward_face
6151 products%status_forward_q(iglobal)=results(ilocal)%forward_status
6152 products%status_backward_q(iglobal)=results(ilocal)%backward_status
6153 enddo
6154 enddo
6155 enddo
6156 end subroutine mt_copy_volume_q_slab
6157
6158 subroutine mt_copy_volume_qperp_slab(products,results,nx,ny,k_start, &
6159 slab_nz)
6160 type(mt_volume_products), intent(inout) :: products
6161 type(trace_qperp_result), intent(in) :: results(:)
6162 integer, intent(in) :: nx,ny,k_start,slab_nz
6163
6164 integer :: i,j,kk,k,ilocal,iglobal
6165
6166 do kk=1,slab_nz
6167 k=k_start+kk-1
6168 do j=1,ny
6169 do i=1,nx
6170 ilocal=(kk-1)*nx*ny+(j-1)*nx+i
6171 iglobal=(k-1)*nx*ny+(j-1)*nx+i
6172 products%qperp(iglobal)=results(ilocal)%qperp
6173 products%logqperp(iglobal)=results(ilocal)%logqperp
6174 products%N2(iglobal)=results(ilocal)%N2
6175 products%bfactor(iglobal)=results(ilocal)%bfactor
6176 products%length_forward_qperp(iglobal)= &
6177 results(ilocal)%forward_length
6178 products%length_backward_qperp(iglobal)= &
6179 results(ilocal)%backward_length
6180 products%Bseed_norm(iglobal)=dsqrt(sum(results(ilocal)%B_seed**2))
6181 products%Bf_norm(iglobal)=dsqrt(sum(results(ilocal)%forward_B**2))
6182 products%Bb_norm(iglobal)=dsqrt(sum(results(ilocal)%backward_B**2))
6183 products%valid_qperp(iglobal)=merge(1,0,results(ilocal)%valid)
6184 products%status_qperp(iglobal)=results(ilocal)%status
6185 products%face_forward_qperp(iglobal)=results(ilocal)%forward_face
6186 products%face_backward_qperp(iglobal)=results(ilocal)%backward_face
6187 products%status_forward_qperp(iglobal)= &
6188 results(ilocal)%forward_status
6189 products%status_backward_qperp(iglobal)= &
6190 results(ilocal)%backward_status
6191 enddo
6192 enddo
6193 enddo
6194 end subroutine mt_copy_volume_qperp_slab
6195
6196 subroutine mt_build_vti_desc(desc,name,array_kind,npoint)
6197 type(mt_vti_array_desc), intent(out) :: desc
6198 character(len=*), intent(in) :: name
6199 integer, intent(in) :: array_kind,npoint
6200
6201 desc%name=''
6202 desc%name=trim(name)
6203 desc%kind=array_kind
6204 select case (array_kind)
6205 case (mt_vti_kind_float64)
6206 desc%nbytes=int(npoint,kind=8)*8_8
6207 case (mt_vti_kind_int32)
6208 desc%nbytes=int(npoint,kind=8)*4_8
6209 case default
6210 desc%nbytes=0_8
6211 end select
6212 desc%offset=0_8
6213 end subroutine mt_build_vti_desc
6214
6215 subroutine mt_finalize_vti_desc_offsets(descs,ndesc)
6216 integer, intent(in) :: ndesc
6217 type(mt_vti_array_desc), intent(inout) :: descs(ndesc)
6218
6219 integer :: idesc
6220 integer(kind=8) :: offset
6221
6222 offset=0_8
6223 do idesc=1,ndesc
6224 descs(idesc)%offset=offset
6225 offset=offset+descs(idesc)%nbytes+4_8
6226 enddo
6227 end subroutine mt_finalize_vti_desc_offsets
6228
6229 subroutine mt_append_vti_desc(descs,idesc,name,array_kind,npoint)
6230 type(mt_vti_array_desc), intent(inout) :: descs(:)
6231 integer, intent(inout) :: idesc
6232 character(len=*), intent(in) :: name
6233 integer, intent(in) :: array_kind,npoint
6234
6235 idesc=idesc+1
6236 call mt_build_vti_desc(descs(idesc),name,array_kind,npoint)
6237 end subroutine mt_append_vti_desc
6238
6239 subroutine mt_build_cartesian_vti_pointdata_descs(npoint,descs,ndesc)
6240 integer, intent(in) :: npoint
6241 type(mt_vti_array_desc), allocatable, intent(out) :: descs(:)
6242 integer, intent(out) :: ndesc
6243
6244 ndesc=3
6245 allocate(descs(ndesc))
6246 call mt_build_vti_desc(descs(1),'length_total',mt_vti_kind_float64, &
6247 npoint)
6248 call mt_build_vti_desc(descs(2),'qperp',mt_vti_kind_float64,npoint)
6249 call mt_build_vti_desc(descs(3),'status',mt_vti_kind_int32,npoint)
6250 call mt_finalize_vti_desc_offsets(descs,ndesc)
6251 end subroutine mt_build_cartesian_vti_pointdata_descs
6252
6253 subroutine mt_build_volume_vti_descs(npoint,do_length,do_twist,do_q, &
6254 do_qperp,descs,ndesc)
6255 integer, intent(in) :: npoint
6256 logical, intent(in) :: do_length,do_twist,do_q,do_qperp
6257 type(mt_vti_array_desc), allocatable, intent(out) :: descs(:)
6258 integer, intent(out) :: ndesc
6259
6260 integer :: idesc,max_desc
6261
6262 if (.not.mt_vtk_detail_is_full()) then
6263 max_desc=0
6264 if (do_length) max_desc=max_desc+1
6265 if (do_twist) max_desc=max_desc+1
6266 if (do_q) max_desc=max_desc+1
6267 if (do_qperp) max_desc=max_desc+1
6268 else
6269 max_desc=0
6270 if (do_length) max_desc=max_desc+7
6271 if (do_twist) max_desc=max_desc+7
6272 if (do_q) max_desc=max_desc+15
6273 if (do_qperp) max_desc=max_desc+15
6274 endif
6275 allocate(descs(max_desc))
6276
6277 idesc=0
6278 if (do_length) then
6279 call mt_append_vti_desc(descs,idesc,'length_total', &
6280 mt_vti_kind_float64,npoint)
6281 endif
6282 if (.not.mt_vtk_detail_is_full()) then
6283 if (do_twist) then
6284 call mt_append_vti_desc(descs,idesc,'twist_total', &
6285 mt_vti_kind_float64,npoint)
6286 endif
6287 if (do_q) then
6288 call mt_append_vti_desc(descs,idesc,'logQ', &
6289 mt_vti_kind_float64,npoint)
6290 endif
6291 if (do_qperp) then
6292 call mt_append_vti_desc(descs,idesc,'logQperp', &
6293 mt_vti_kind_float64,npoint)
6294 endif
6295 ndesc=idesc
6296 call mt_finalize_vti_desc_offsets(descs,ndesc)
6297 return
6298 endif
6299
6300 if (do_length) then
6301 call mt_append_vti_desc(descs,idesc,'length_backward', &
6302 mt_vti_kind_float64,npoint)
6303 call mt_append_vti_desc(descs,idesc,'length_forward', &
6304 mt_vti_kind_float64,npoint)
6305 call mt_append_vti_desc(descs,idesc,'nstep_backward_length', &
6306 mt_vti_kind_int32,npoint)
6307 call mt_append_vti_desc(descs,idesc,'nstep_forward_length', &
6308 mt_vti_kind_int32,npoint)
6309 call mt_append_vti_desc(descs,idesc,'status_backward_length', &
6310 mt_vti_kind_int32,npoint)
6311 call mt_append_vti_desc(descs,idesc,'status_forward_length', &
6312 mt_vti_kind_int32,npoint)
6313 endif
6314
6315 if (do_twist) then
6316 call mt_append_vti_desc(descs,idesc,'twist_total', &
6317 mt_vti_kind_float64,npoint)
6318 call mt_append_vti_desc(descs,idesc,'twist_backward', &
6319 mt_vti_kind_float64,npoint)
6320 call mt_append_vti_desc(descs,idesc,'twist_forward', &
6321 mt_vti_kind_float64,npoint)
6322 call mt_append_vti_desc(descs,idesc,'nstep_backward_twist', &
6323 mt_vti_kind_int32,npoint)
6324 call mt_append_vti_desc(descs,idesc,'nstep_forward_twist', &
6325 mt_vti_kind_int32,npoint)
6326 call mt_append_vti_desc(descs,idesc,'status_backward_twist', &
6327 mt_vti_kind_int32,npoint)
6328 call mt_append_vti_desc(descs,idesc,'status_forward_twist', &
6329 mt_vti_kind_int32,npoint)
6330 endif
6331
6332 if (do_q) then
6333 call mt_append_vti_desc(descs,idesc,'q',mt_vti_kind_float64,npoint)
6334 call mt_append_vti_desc(descs,idesc,'logq', &
6335 mt_vti_kind_float64,npoint)
6336 call mt_append_vti_desc(descs,idesc,'N2_q',mt_vti_kind_float64,npoint)
6337 call mt_append_vti_desc(descs,idesc,'bfactor_q', &
6338 mt_vti_kind_float64,npoint)
6339 call mt_append_vti_desc(descs,idesc,'length_forward_q', &
6340 mt_vti_kind_float64,npoint)
6341 call mt_append_vti_desc(descs,idesc,'length_backward_q', &
6342 mt_vti_kind_float64,npoint)
6343 call mt_append_vti_desc(descs,idesc,'Bseed_norm_q', &
6344 mt_vti_kind_float64,npoint)
6345 call mt_append_vti_desc(descs,idesc,'Bf_norm_q', &
6346 mt_vti_kind_float64,npoint)
6347 call mt_append_vti_desc(descs,idesc,'Bb_norm_q', &
6348 mt_vti_kind_float64,npoint)
6349 call mt_append_vti_desc(descs,idesc,'valid_Q', &
6350 mt_vti_kind_int32,npoint)
6351 call mt_append_vti_desc(descs,idesc,'status_Q', &
6352 mt_vti_kind_int32,npoint)
6353 call mt_append_vti_desc(descs,idesc,'face_forward_Q', &
6354 mt_vti_kind_int32,npoint)
6355 call mt_append_vti_desc(descs,idesc,'face_backward_Q', &
6356 mt_vti_kind_int32,npoint)
6357 call mt_append_vti_desc(descs,idesc,'status_forward_Q', &
6358 mt_vti_kind_int32,npoint)
6359 call mt_append_vti_desc(descs,idesc,'status_backward_Q', &
6360 mt_vti_kind_int32,npoint)
6361 endif
6362
6363 if (do_qperp) then
6364 call mt_append_vti_desc(descs,idesc,'qperp', &
6365 mt_vti_kind_float64,npoint)
6366 call mt_append_vti_desc(descs,idesc,'logqperp', &
6367 mt_vti_kind_float64,npoint)
6368 call mt_append_vti_desc(descs,idesc,'N2',mt_vti_kind_float64, &
6369 npoint)
6370 call mt_append_vti_desc(descs,idesc,'bfactor', &
6371 mt_vti_kind_float64,npoint)
6372 call mt_append_vti_desc(descs,idesc,'length_forward_qperp', &
6373 mt_vti_kind_float64,npoint)
6374 call mt_append_vti_desc(descs,idesc,'length_backward_qperp', &
6375 mt_vti_kind_float64,npoint)
6376 call mt_append_vti_desc(descs,idesc,'Bseed_norm', &
6377 mt_vti_kind_float64,npoint)
6378 call mt_append_vti_desc(descs,idesc,'Bf_norm', &
6379 mt_vti_kind_float64,npoint)
6380 call mt_append_vti_desc(descs,idesc,'Bb_norm', &
6381 mt_vti_kind_float64,npoint)
6382 call mt_append_vti_desc(descs,idesc,'valid_qperp', &
6383 mt_vti_kind_int32,npoint)
6384 call mt_append_vti_desc(descs,idesc,'status_qperp', &
6385 mt_vti_kind_int32,npoint)
6386 call mt_append_vti_desc(descs,idesc,'face_forward_qperp', &
6387 mt_vti_kind_int32,npoint)
6388 call mt_append_vti_desc(descs,idesc,'face_backward_qperp', &
6389 mt_vti_kind_int32,npoint)
6390 call mt_append_vti_desc(descs,idesc,'status_forward_qperp', &
6391 mt_vti_kind_int32,npoint)
6392 call mt_append_vti_desc(descs,idesc,'status_backward_qperp', &
6393 mt_vti_kind_int32,npoint)
6394 endif
6395
6396 ndesc=idesc
6397 call mt_finalize_vti_desc_offsets(descs,ndesc)
6398 end subroutine mt_build_volume_vti_descs
6399
6400 character(len=8) function mt_vti_type_name(array_kind)
6401 integer, intent(in) :: array_kind
6402
6403 select case (array_kind)
6404 case (mt_vti_kind_float64)
6405 mt_vti_type_name='Float64'
6406 case (mt_vti_kind_int32)
6407 mt_vti_type_name='Int32'
6408 case default
6409 mt_vti_type_name='Unknown'
6410 end select
6411 end function mt_vti_type_name
6412
6413 subroutine mt_write_vti_image_header(vti_unit,origin,spacing,nx,ny,nz, &
6414 descs,ndesc,io_status)
6415 integer, intent(in) :: vti_unit,nx,ny,nz,ndesc
6416 double precision, intent(in) :: origin(3),spacing(3)
6417 type(mt_vti_array_desc), intent(in) :: descs(ndesc)
6418 integer, intent(out) :: io_status
6419
6420 integer :: extent(6),idesc
6421
6422 extent=(/ 0,nx-1,0,ny-1,0,nz-1 /)
6423 write(vti_unit,'(a)',iostat=io_status) '<?xml version="1.0"?>'
6424 if (io_status/=0) return
6425 write(vti_unit,'(a)',iostat=io_status) &
6426 '<VTKFile type="ImageData" version="0.1" byte_order="LittleEndian">'
6427 if (io_status/=0) return
6428 write(vti_unit,'(a,3(1pe24.16),a,6(i0,1x),a,3(1pe24.16),a)', &
6429 iostat=io_status) ' <ImageData Origin="',origin, &
6430 '" WholeExtent="',extent,'" Spacing="',spacing,'">'
6431 if (io_status/=0) return
6432 write(vti_unit,'(a,6(i0,1x),a)',iostat=io_status) &
6433 ' <Piece Extent="',extent,'">'
6434 if (io_status/=0) return
6435 write(vti_unit,'(a)',iostat=io_status) ' <PointData>'
6436 if (io_status/=0) return
6437
6438 do idesc=1,ndesc
6439 call mt_write_vti_appended_array(vti_unit, &
6440 mt_vti_type_name(descs(idesc)%kind),trim(descs(idesc)%name), &
6441 descs(idesc)%offset,io_status)
6442 if (io_status/=0) return
6443 enddo
6444
6445 write(vti_unit,'(a)',iostat=io_status) ' </PointData>'
6446 if (io_status/=0) return
6447 write(vti_unit,'(a)',iostat=io_status) ' </Piece>'
6448 if (io_status/=0) return
6449 write(vti_unit,'(a)',iostat=io_status) ' </ImageData>'
6450 if (io_status/=0) return
6451 write(vti_unit,'(a)',iostat=io_status) '<AppendedData encoding="raw">'
6452 end subroutine mt_write_vti_image_header
6453
6454 subroutine mt_write_fieldline_products_volume_vti(vti_file,origin, &
6455 spacing,nx,ny,nz,products,do_length,do_twist,do_q,do_qperp,caller)
6456 integer, intent(in) :: nx,ny,nz
6457 double precision, intent(in) :: origin(3),spacing(3)
6458 type(mt_volume_products), intent(in) :: products
6459 logical, intent(in) :: do_length,do_twist,do_q,do_qperp
6460 character(len=*), intent(in) :: vti_file,caller
6461
6462 integer :: vti_unit,io_status,npoint
6463 character(len=1) :: marker
6464 type(mt_vti_array_desc), allocatable :: descs(:)
6465 integer :: ndesc
6466
6467 npoint=nx*ny*nz
6468 call mt_check_vti_byte_count(npoint,caller)
6469 call mt_build_volume_vti_descs(npoint,do_length,do_twist,do_q, &
6470 do_qperp,descs,ndesc)
6471
6472 open(newunit=vti_unit,file=trim(vti_file),status='replace', &
6473 action='write',form='formatted',iostat=io_status)
6474 if (io_status/=0) then
6475 call mpistop(trim(caller)//' could not open VTI file')
6476 endif
6477
6478 call mt_write_vti_image_header(vti_unit,origin,spacing,nx,ny,nz, &
6479 descs,ndesc,io_status)
6480 if (io_status/=0) then
6481 close(vti_unit)
6482 call mpistop(trim(caller)//' could not write VTI header')
6483 endif
6484 close(vti_unit)
6485
6486 open(newunit=vti_unit,file=trim(vti_file),access='stream', &
6487 form='unformatted',status='old',position='append', &
6488 action='write',iostat=io_status)
6489 if (io_status/=0) then
6490 call mpistop(trim(caller)//' could not append VTI payload')
6491 endif
6492
6493 marker='_'
6494 write(vti_unit,iostat=io_status) marker
6495 if (io_status==0) then
6496 call mt_write_volume_vti_payload(vti_unit,products,npoint,descs, &
6497 ndesc,io_status)
6498 endif
6499 close(vti_unit)
6500 if (io_status/=0) then
6501 call mpistop(trim(caller)//' could not write VTI payload')
6502 endif
6503
6504 open(newunit=vti_unit,file=trim(vti_file),status='old', &
6505 action='write',form='formatted',position='append',iostat=io_status)
6506 if (io_status/=0) then
6507 call mpistop(trim(caller)//' could not append VTI footer')
6508 endif
6509 write(vti_unit,'(a)',iostat=io_status) '</AppendedData>'
6510 if (io_status==0) write(vti_unit,'(a)',iostat=io_status) '</VTKFile>'
6511 close(vti_unit)
6512 if (io_status/=0) then
6513 call mpistop(trim(caller)//' could not write VTI footer')
6514 endif
6515 deallocate(descs)
6516 end subroutine mt_write_fieldline_products_volume_vti
6517
6518 subroutine mt_write_volume_vti_payload(vti_unit,products,npoint,descs, &
6519 ndesc,io_status)
6520 integer, intent(in) :: vti_unit,npoint,ndesc
6521 type(mt_volume_products), intent(in) :: products
6522 type(mt_vti_array_desc), intent(in) :: descs(ndesc)
6523 integer, intent(inout) :: io_status
6524
6525 integer :: idesc
6526
6527 do idesc=1,ndesc
6528 select case (trim(descs(idesc)%name))
6529 case ('length_total')
6530 if (mt_vtk_detail_is_full()) then
6531 call mt_write_vti_payload_float64(vti_unit,products%length_total, &
6532 npoint,io_status)
6533 else
6534 call mt_write_vti_payload_float64_visual(vti_unit, &
6535 products%length_total,npoint,io_status)
6536 endif
6537 case ('length_backward')
6538 call mt_write_vti_payload_float64(vti_unit,products%length_backward, &
6539 npoint,io_status)
6540 case ('length_forward')
6541 call mt_write_vti_payload_float64(vti_unit,products%length_forward, &
6542 npoint,io_status)
6543 case ('nstep_backward_length')
6544 call mt_write_vti_payload_int32(vti_unit, &
6545 products%nstep_backward_length,npoint,io_status)
6546 case ('nstep_forward_length')
6547 call mt_write_vti_payload_int32(vti_unit, &
6548 products%nstep_forward_length,npoint,io_status)
6549 case ('status_backward_length')
6550 call mt_write_vti_payload_int32(vti_unit, &
6551 products%status_backward_length,npoint,io_status)
6552 case ('status_forward_length')
6553 call mt_write_vti_payload_int32(vti_unit, &
6554 products%status_forward_length,npoint,io_status)
6555 case ('twist_total')
6556 if (mt_vtk_detail_is_full()) then
6557 call mt_write_vti_payload_float64(vti_unit,products%twist_total, &
6558 npoint,io_status)
6559 else
6560 call mt_write_vti_payload_float64_visual(vti_unit, &
6561 products%twist_total,npoint,io_status)
6562 endif
6563 case ('twist_backward')
6564 call mt_write_vti_payload_float64(vti_unit,products%twist_backward, &
6565 npoint,io_status)
6566 case ('twist_forward')
6567 call mt_write_vti_payload_float64(vti_unit,products%twist_forward, &
6568 npoint,io_status)
6569 case ('nstep_backward_twist')
6570 call mt_write_vti_payload_int32(vti_unit, &
6571 products%nstep_backward_twist,npoint,io_status)
6572 case ('nstep_forward_twist')
6573 call mt_write_vti_payload_int32(vti_unit, &
6574 products%nstep_forward_twist,npoint,io_status)
6575 case ('status_backward_twist')
6576 call mt_write_vti_payload_int32(vti_unit, &
6577 products%status_backward_twist,npoint,io_status)
6578 case ('status_forward_twist')
6579 call mt_write_vti_payload_int32(vti_unit, &
6580 products%status_forward_twist,npoint,io_status)
6581 case ('q')
6582 call mt_write_vti_payload_float64(vti_unit,products%q,npoint, &
6583 io_status)
6584 case ('logq')
6585 call mt_write_vti_payload_float64(vti_unit,products%logq,npoint, &
6586 io_status)
6587 case ('logQ')
6588 call mt_write_vti_payload_logq_visual(vti_unit,products,npoint, &
6589 io_status)
6590 case ('N2_q')
6591 call mt_write_vti_payload_float64(vti_unit,products%N2_q,npoint, &
6592 io_status)
6593 case ('bfactor_q')
6594 call mt_write_vti_payload_float64(vti_unit,products%bfactor_q, &
6595 npoint,io_status)
6596 case ('length_forward_q')
6597 call mt_write_vti_payload_float64(vti_unit, &
6598 products%length_forward_q,npoint,io_status)
6599 case ('length_backward_q')
6600 call mt_write_vti_payload_float64(vti_unit, &
6601 products%length_backward_q,npoint,io_status)
6602 case ('Bseed_norm_q')
6603 call mt_write_vti_payload_float64(vti_unit,products%Bseed_norm_q, &
6604 npoint,io_status)
6605 case ('Bf_norm_q')
6606 call mt_write_vti_payload_float64(vti_unit,products%Bf_norm_q,npoint, &
6607 io_status)
6608 case ('Bb_norm_q')
6609 call mt_write_vti_payload_float64(vti_unit,products%Bb_norm_q,npoint, &
6610 io_status)
6611 case ('valid_Q')
6612 call mt_write_vti_payload_int32(vti_unit,products%valid_q,npoint, &
6613 io_status)
6614 case ('status_Q')
6615 call mt_write_vti_payload_int32(vti_unit,products%status_q,npoint, &
6616 io_status)
6617 case ('face_forward_Q')
6618 call mt_write_vti_payload_int32(vti_unit,products%face_forward_q, &
6619 npoint,io_status)
6620 case ('face_backward_Q')
6621 call mt_write_vti_payload_int32(vti_unit,products%face_backward_q, &
6622 npoint,io_status)
6623 case ('status_forward_Q')
6624 call mt_write_vti_payload_int32(vti_unit,products%status_forward_q, &
6625 npoint,io_status)
6626 case ('status_backward_Q')
6627 call mt_write_vti_payload_int32(vti_unit,products%status_backward_q, &
6628 npoint,io_status)
6629 case ('qperp')
6630 call mt_write_vti_payload_float64(vti_unit,products%qperp,npoint, &
6631 io_status)
6632 case ('logqperp')
6633 call mt_write_vti_payload_float64(vti_unit,products%logqperp, &
6634 npoint,io_status)
6635 case ('logQperp')
6636 call mt_write_vti_payload_logqperp_visual(vti_unit,products,npoint, &
6637 io_status)
6638 case ('N2')
6639 call mt_write_vti_payload_float64(vti_unit,products%N2,npoint, &
6640 io_status)
6641 case ('bfactor')
6642 call mt_write_vti_payload_float64(vti_unit,products%bfactor,npoint, &
6643 io_status)
6644 case ('length_forward_qperp')
6645 call mt_write_vti_payload_float64(vti_unit, &
6646 products%length_forward_qperp,npoint,io_status)
6647 case ('length_backward_qperp')
6648 call mt_write_vti_payload_float64(vti_unit, &
6649 products%length_backward_qperp,npoint,io_status)
6650 case ('Bseed_norm')
6651 call mt_write_vti_payload_float64(vti_unit,products%Bseed_norm, &
6652 npoint,io_status)
6653 case ('Bf_norm')
6654 call mt_write_vti_payload_float64(vti_unit,products%Bf_norm,npoint, &
6655 io_status)
6656 case ('Bb_norm')
6657 call mt_write_vti_payload_float64(vti_unit,products%Bb_norm,npoint, &
6658 io_status)
6659 case ('valid_qperp')
6660 call mt_write_vti_payload_int32(vti_unit,products%valid_qperp, &
6661 npoint,io_status)
6662 case ('valid_Qperp')
6663 call mt_write_vti_payload_int32(vti_unit,products%valid_qperp, &
6664 npoint,io_status)
6665 case ('status_qperp')
6666 call mt_write_vti_payload_int32(vti_unit,products%status_qperp, &
6667 npoint,io_status)
6668 case ('status_Qperp')
6669 call mt_write_vti_payload_int32(vti_unit,products%status_qperp, &
6670 npoint,io_status)
6671 case ('face_forward_qperp')
6672 call mt_write_vti_payload_int32(vti_unit, &
6673 products%face_forward_qperp,npoint,io_status)
6674 case ('face_backward_qperp')
6675 call mt_write_vti_payload_int32(vti_unit, &
6676 products%face_backward_qperp,npoint,io_status)
6677 case ('status_forward_qperp')
6678 call mt_write_vti_payload_int32(vti_unit, &
6679 products%status_forward_qperp,npoint,io_status)
6680 case ('status_backward_qperp')
6681 call mt_write_vti_payload_int32(vti_unit, &
6682 products%status_backward_qperp,npoint,io_status)
6683 case default
6684 io_status=1
6685 end select
6686 if (io_status/=0) exit
6687 enddo
6688 end subroutine mt_write_volume_vti_payload
6689
6690 subroutine mt_write_vti_payload_logq_visual(vti_unit,products,npoint, &
6691 io_status)
6692 integer, intent(in) :: vti_unit,npoint
6693 type(mt_volume_products), intent(in) :: products
6694 integer, intent(inout) :: io_status
6695
6696 double precision, allocatable :: visual_values(:)
6697 integer :: ipoint
6698
6699 allocate(visual_values(npoint))
6700 do ipoint=1,npoint
6701 visual_values(ipoint)=mt_visual_valid_float(products%logq(ipoint), &
6702 products%valid_q(ipoint)==1)
6703 enddo
6704 call mt_write_vti_payload_float64(vti_unit,visual_values,npoint, &
6705 io_status)
6706 deallocate(visual_values)
6707 end subroutine mt_write_vti_payload_logq_visual
6708
6709 subroutine mt_write_vti_payload_float64_visual(vti_unit,values,npoint, &
6710 io_status)
6711 integer, intent(in) :: vti_unit,npoint
6712 double precision, intent(in) :: values(npoint)
6713 integer, intent(inout) :: io_status
6714
6715 double precision, allocatable :: visual_values(:)
6716 integer :: ipoint
6717
6718 if (io_status/=0) return
6719 allocate(visual_values(npoint))
6720 do ipoint=1,npoint
6721 visual_values(ipoint)=mt_visual_float(values(ipoint))
6722 enddo
6723 call mt_write_vti_payload_float64(vti_unit,visual_values,npoint, &
6724 io_status)
6725 deallocate(visual_values)
6726 end subroutine mt_write_vti_payload_float64_visual
6727
6728 subroutine mt_write_vti_payload_logqperp_visual(vti_unit,products,npoint, &
6729 io_status)
6730 integer, intent(in) :: vti_unit,npoint
6731 type(mt_volume_products), intent(in) :: products
6732 integer, intent(inout) :: io_status
6733
6734 double precision, allocatable :: visual_values(:)
6735 integer :: ipoint
6736
6737 if (io_status/=0) return
6738 allocate(visual_values(npoint))
6739 do ipoint=1,npoint
6740 visual_values(ipoint)=mt_visual_valid_float(products%logqperp(ipoint), &
6741 products%valid_qperp(ipoint)==1)
6742 enddo
6743 call mt_write_vti_payload_float64(vti_unit,visual_values,npoint, &
6744 io_status)
6745 deallocate(visual_values)
6746 end subroutine mt_write_vti_payload_logqperp_visual
6747
6748 subroutine mt_check_vti_byte_count(npoint,caller)
6749 integer, intent(in) :: npoint
6750 character(len=*), intent(in) :: caller
6751
6752 if (int(npoint,kind=8)*8_8>int(huge(0),kind=8)) then
6753 call mpistop(trim(caller)//' exceeds 32-bit VTI byte count')
6754 endif
6755 end subroutine mt_check_vti_byte_count
6756
6757 subroutine mt_write_vti_payload_float64(vti_unit,values,npoint,io_status)
6758 integer, intent(in) :: vti_unit,npoint
6759 double precision, intent(in) :: values(npoint)
6760 integer, intent(inout) :: io_status
6761
6762 integer :: byte_count
6763
6764 if (io_status/=0) return
6765 byte_count=npoint*8
6766 write(vti_unit,iostat=io_status) byte_count
6767 if (io_status==0) write(vti_unit,iostat=io_status) values
6768 end subroutine mt_write_vti_payload_float64
6769
6770 subroutine mt_write_vti_payload_int32(vti_unit,values,npoint,io_status)
6771 integer, intent(in) :: vti_unit,npoint
6772 integer, intent(in) :: values(npoint)
6773 integer, intent(inout) :: io_status
6774
6775 integer :: byte_count
6776
6777 if (io_status/=0) return
6778 byte_count=npoint*4
6779 write(vti_unit,iostat=io_status) byte_count
6780 if (io_status==0) write(vti_unit,iostat=io_status) values
6781 end subroutine mt_write_vti_payload_int32
6782
6783 subroutine mt_write_vti_pointdata_fixed(vti_file,origin,spacing,nx,ny,nz, &
6784 length_total,qperp,status,caller)
6785 character(len=*), intent(in) :: vti_file,caller
6786 integer, intent(in) :: nx,ny,nz
6787 double precision, intent(in) :: origin(3),spacing(3)
6788 double precision, intent(in) :: length_total(nx*ny*nz),qperp(nx*ny*nz)
6789 integer, intent(in) :: status(nx*ny*nz)
6790
6791 integer :: vti_unit,io_status,npoint
6792 integer :: idesc,ndesc
6793 character(len=1) :: marker
6794 type(mt_vti_array_desc), allocatable :: descs(:)
6795
6796 npoint=nx*ny*nz
6797 call mt_check_vti_byte_count(npoint,caller)
6798 call mt_build_cartesian_vti_pointdata_descs(npoint,descs,ndesc)
6799
6800 open(newunit=vti_unit,file=trim(vti_file),status='replace', &
6801 action='write',form='formatted',iostat=io_status)
6802 if (io_status/=0) then
6803 call mpistop(trim(caller)//' could not open VTI file')
6804 endif
6805
6806 call mt_write_vti_image_header(vti_unit,origin,spacing,nx,ny,nz, &
6807 descs,ndesc,io_status)
6808 if (io_status/=0) then
6809 close(vti_unit)
6810 call mpistop(trim(caller)//' could not write VTI header')
6811 endif
6812 close(vti_unit)
6813
6814 open(newunit=vti_unit,file=trim(vti_file),access='stream', &
6815 form='unformatted',status='old',position='append', &
6816 action='write',iostat=io_status)
6817 if (io_status/=0) then
6818 call mpistop(trim(caller)//' could not append VTI payload')
6819 endif
6820
6821 marker='_'
6822 write(vti_unit,iostat=io_status) marker
6823 do idesc=1,ndesc
6824 if (io_status/=0) exit
6825 select case (trim(descs(idesc)%name))
6826 case ('length_total')
6827 call mt_write_vti_payload_float64(vti_unit,length_total,npoint, &
6828 io_status)
6829 case ('qperp')
6830 call mt_write_vti_payload_float64(vti_unit,qperp,npoint,io_status)
6831 case ('status')
6832 call mt_write_vti_payload_int32(vti_unit,status,npoint,io_status)
6833 case default
6834 io_status=1
6835 end select
6836 enddo
6837 close(vti_unit)
6838 if (io_status/=0) then
6839 call mpistop(trim(caller)//' could not write VTI payload')
6840 endif
6841
6842 open(newunit=vti_unit,file=trim(vti_file),status='old', &
6843 action='write',form='formatted',position='append',iostat=io_status)
6844 if (io_status/=0) then
6845 call mpistop(trim(caller)//' could not append VTI footer')
6846 endif
6847 write(vti_unit,'(a)',iostat=io_status) '</AppendedData>'
6848 if (io_status==0) write(vti_unit,'(a)',iostat=io_status) '</VTKFile>'
6849 close(vti_unit)
6850 if (io_status/=0) then
6851 call mpistop(trim(caller)//' could not write VTI footer')
6852 endif
6853 deallocate(descs)
6854 end subroutine mt_write_vti_pointdata_fixed
6855
6856 subroutine mt_write_vti_appended_array(vti_unit,vtk_type,name,offset, &
6857 io_status)
6858 integer, intent(in) :: vti_unit
6859 character(len=*), intent(in) :: vtk_type,name
6860 integer(kind=8), intent(in) :: offset
6861 integer, intent(out) :: io_status
6862
6863 write(vti_unit,'(a)',advance='no',iostat=io_status) &
6864 ' <DataArray type="'
6865 if (io_status==0) write(vti_unit,'(a)',advance='no', &
6866 iostat=io_status) trim(vtk_type)
6867 if (io_status==0) write(vti_unit,'(a)',advance='no', &
6868 iostat=io_status) '" Name="'
6869 if (io_status==0) write(vti_unit,'(a)',advance='no', &
6870 iostat=io_status) trim(name)
6871 if (io_status==0) write(vti_unit,'(a)',advance='no', &
6872 iostat=io_status) '" format="appended" offset="'
6873 if (io_status==0) write(vti_unit,'(i0)',advance='no', &
6874 iostat=io_status) offset
6875 if (io_status==0) write(vti_unit,'(a)',iostat=io_status) '"/>'
6876 end subroutine mt_write_vti_appended_array
6877
6878 subroutine mt_write_vtu_length_pointdata(vtu_unit,length_results,npoint, &
6879 io_status)
6880 integer, intent(in) :: vtu_unit,npoint
6881 type(trace_length_result), intent(in) :: length_results(npoint)
6882 integer, intent(inout) :: io_status
6883
6884 integer :: ipoint
6885
6886 call mt_write_vtu_float_array_start(vtu_unit,'length_total',io_status)
6887 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
6888 (length_results(ipoint)%total_length,ipoint=1,npoint)
6889 call mt_write_vtu_data_array_end(vtu_unit,io_status)
6890 call mt_write_vtu_float_array_start(vtu_unit,'length_backward', &
6891 io_status)
6892 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
6893 (length_results(ipoint)%backward_length,ipoint=1,npoint)
6894 call mt_write_vtu_data_array_end(vtu_unit,io_status)
6895 call mt_write_vtu_float_array_start(vtu_unit,'length_forward', &
6896 io_status)
6897 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
6898 (length_results(ipoint)%forward_length,ipoint=1,npoint)
6899 call mt_write_vtu_data_array_end(vtu_unit,io_status)
6900
6901 call mt_write_vtu_int_array_start(vtu_unit,'nstep_backward_length', &
6902 io_status)
6903 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
6904 (length_results(ipoint)%backward_nstep,ipoint=1,npoint)
6905 call mt_write_vtu_data_array_end(vtu_unit,io_status)
6906 call mt_write_vtu_int_array_start(vtu_unit,'nstep_forward_length', &
6907 io_status)
6908 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
6909 (length_results(ipoint)%forward_nstep,ipoint=1,npoint)
6910 call mt_write_vtu_data_array_end(vtu_unit,io_status)
6911 call mt_write_vtu_int_array_start(vtu_unit,'status_backward_length', &
6912 io_status)
6913 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
6914 (length_results(ipoint)%backward_status,ipoint=1,npoint)
6915 call mt_write_vtu_data_array_end(vtu_unit,io_status)
6916 call mt_write_vtu_int_array_start(vtu_unit,'status_forward_length', &
6917 io_status)
6918 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
6919 (length_results(ipoint)%forward_status,ipoint=1,npoint)
6920 call mt_write_vtu_data_array_end(vtu_unit,io_status)
6921 end subroutine mt_write_vtu_length_pointdata
6922
6923 subroutine mt_write_vtu_mapping_pointdata(vtu_unit,mapping_results, &
6924 npoint,io_status)
6925 integer, intent(in) :: vtu_unit,npoint
6926 type(trace_mapping_result), intent(in) :: mapping_results(npoint)
6927 integer, intent(inout) :: io_status
6928
6929 integer :: ipoint
6930
6931 call mt_write_vtu_float_array_start(vtu_unit,'x_f_mapping',io_status)
6932 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
6933 (mt_vc(mapping_results(ipoint)%forward_footpoint,1),ipoint=1,npoint)
6934 call mt_write_vtu_data_array_end(vtu_unit,io_status)
6935 call mt_write_vtu_float_array_start(vtu_unit,'y_f_mapping',io_status)
6936 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
6937 (mt_vc(mapping_results(ipoint)%forward_footpoint,2),ipoint=1,npoint)
6938 call mt_write_vtu_data_array_end(vtu_unit,io_status)
6939 call mt_write_vtu_float_array_start(vtu_unit,'z_f_mapping',io_status)
6940 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
6941 (mt_vc(mapping_results(ipoint)%forward_footpoint,3),ipoint=1,npoint)
6942 call mt_write_vtu_data_array_end(vtu_unit,io_status)
6943 call mt_write_vtu_float_array_start(vtu_unit,'x_b_mapping',io_status)
6944 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
6945 (mt_vc(mapping_results(ipoint)%backward_footpoint,1),ipoint=1,npoint)
6946 call mt_write_vtu_data_array_end(vtu_unit,io_status)
6947 call mt_write_vtu_float_array_start(vtu_unit,'y_b_mapping',io_status)
6948 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
6949 (mt_vc(mapping_results(ipoint)%backward_footpoint,2),ipoint=1,npoint)
6950 call mt_write_vtu_data_array_end(vtu_unit,io_status)
6951 call mt_write_vtu_float_array_start(vtu_unit,'z_b_mapping',io_status)
6952 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
6953 (mt_vc(mapping_results(ipoint)%backward_footpoint,3),ipoint=1,npoint)
6954 call mt_write_vtu_data_array_end(vtu_unit,io_status)
6955
6956 call mt_write_vtu_float_array_start(vtu_unit,'source_Bn_mapping', &
6957 io_status)
6958 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
6959 (mapping_results(ipoint)%source_Bn,ipoint=1,npoint)
6960 call mt_write_vtu_data_array_end(vtu_unit,io_status)
6961 call mt_write_vtu_float_array_start(vtu_unit,'forward_Bn_mapping', &
6962 io_status)
6963 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
6964 (mapping_results(ipoint)%forward_Bn,ipoint=1,npoint)
6965 call mt_write_vtu_data_array_end(vtu_unit,io_status)
6966 call mt_write_vtu_float_array_start(vtu_unit,'backward_Bn_mapping', &
6967 io_status)
6968 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
6969 (mapping_results(ipoint)%backward_Bn,ipoint=1,npoint)
6970 call mt_write_vtu_data_array_end(vtu_unit,io_status)
6971
6972 call mt_write_vtu_int_array_start(vtu_unit,'face_forward_mapping', &
6973 io_status)
6974 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
6975 (mapping_results(ipoint)%forward_face,ipoint=1,npoint)
6976 call mt_write_vtu_data_array_end(vtu_unit,io_status)
6977 call mt_write_vtu_int_array_start(vtu_unit,'face_backward_mapping', &
6978 io_status)
6979 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
6980 (mapping_results(ipoint)%backward_face,ipoint=1,npoint)
6981 call mt_write_vtu_data_array_end(vtu_unit,io_status)
6982 call mt_write_vtu_int_array_start(vtu_unit,'status_forward_mapping', &
6983 io_status)
6984 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
6985 (mapping_results(ipoint)%forward_status,ipoint=1,npoint)
6986 call mt_write_vtu_data_array_end(vtu_unit,io_status)
6987 call mt_write_vtu_int_array_start(vtu_unit,'status_backward_mapping', &
6988 io_status)
6989 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
6990 (mapping_results(ipoint)%backward_status,ipoint=1,npoint)
6991 call mt_write_vtu_data_array_end(vtu_unit,io_status)
6992 call mt_write_vtu_int_array_start(vtu_unit,'valid_mapping',io_status)
6993 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
6994 (merge(1,0,mapping_results(ipoint)%valid),ipoint=1,npoint)
6995 call mt_write_vtu_data_array_end(vtu_unit,io_status)
6996 end subroutine mt_write_vtu_mapping_pointdata
6997
6998 subroutine mt_write_vtu_qperp_public_pointdata(vtu_unit,qperp_results, &
6999 npoint,io_status)
7000 integer, intent(in) :: vtu_unit,npoint
7001 type(trace_qperp_result), intent(in) :: qperp_results(npoint)
7002 integer, intent(inout) :: io_status
7003
7004 integer :: ipoint
7005
7006 call mt_write_vtu_float_array_start(vtu_unit,'logQperp',io_status)
7007 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7008 (mt_visual_valid_float(qperp_results(ipoint)%logqperp, &
7009 qperp_results(ipoint)%valid),ipoint=1,npoint)
7010 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7011 call mt_write_vtu_int_array_start(vtu_unit,'valid_Qperp',io_status)
7012 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7013 (merge(1,0,qperp_results(ipoint)%valid),ipoint=1,npoint)
7014 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7015 call mt_write_vtu_int_array_start(vtu_unit,'status_Qperp',io_status)
7016 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7017 (qperp_results(ipoint)%status,ipoint=1,npoint)
7018 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7019 end subroutine mt_write_vtu_qperp_public_pointdata
7020
7021 subroutine mt_write_vtu_qperp_method2_pointdata(vtu_unit,qperp_results, &
7022 npoint,io_status)
7023 integer, intent(in) :: vtu_unit,npoint
7024 type(trace_qperp_result), intent(in) :: qperp_results(npoint)
7025 integer, intent(inout) :: io_status
7026
7027 integer :: ipoint
7028
7029 call mt_write_vtu_float_array_start(vtu_unit,'qperp_method2',io_status)
7030 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7031 (qperp_results(ipoint)%qperp,ipoint=1,npoint)
7032 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7033 call mt_write_vtu_float_array_start(vtu_unit,'logqperp_method2', &
7034 io_status)
7035 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7036 (qperp_results(ipoint)%logqperp,ipoint=1,npoint)
7037 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7038 call mt_write_vtu_float_array_start(vtu_unit,'N2_qperp',io_status)
7039 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7040 (qperp_results(ipoint)%N2,ipoint=1,npoint)
7041 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7042 call mt_write_vtu_float_array_start(vtu_unit,'bfactor_qperp',io_status)
7043 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7044 (qperp_results(ipoint)%bfactor,ipoint=1,npoint)
7045 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7046 call mt_write_vtu_float_array_start(vtu_unit,'length_forward_qperp', &
7047 io_status)
7048 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7049 (qperp_results(ipoint)%forward_length,ipoint=1,npoint)
7050 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7051 call mt_write_vtu_float_array_start(vtu_unit,'length_backward_qperp', &
7052 io_status)
7053 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7054 (qperp_results(ipoint)%backward_length,ipoint=1,npoint)
7055 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7056
7057 call mt_write_vtu_float_array_start(vtu_unit,'Bseed_norm_qperp', &
7058 io_status)
7059 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7060 (dsqrt(sum(qperp_results(ipoint)%B_seed**2)),ipoint=1,npoint)
7061 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7062 call mt_write_vtu_float_array_start(vtu_unit,'Bf_norm_qperp',io_status)
7063 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7064 (dsqrt(sum(qperp_results(ipoint)%forward_B**2)),ipoint=1,npoint)
7065 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7066 call mt_write_vtu_float_array_start(vtu_unit,'Bb_norm_qperp',io_status)
7067 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7068 (dsqrt(sum(qperp_results(ipoint)%backward_B**2)),ipoint=1,npoint)
7069 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7070
7071 call mt_write_vtu_float_array_start(vtu_unit,'x_f_qperp',io_status)
7072 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7073 (mt_vc(qperp_results(ipoint)%forward_endpoint,1),ipoint=1,npoint)
7074 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7075 call mt_write_vtu_float_array_start(vtu_unit,'y_f_qperp',io_status)
7076 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7077 (mt_vc(qperp_results(ipoint)%forward_endpoint,2),ipoint=1,npoint)
7078 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7079 call mt_write_vtu_float_array_start(vtu_unit,'z_f_qperp',io_status)
7080 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7081 (mt_vc(qperp_results(ipoint)%forward_endpoint,3),ipoint=1,npoint)
7082 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7083 call mt_write_vtu_float_array_start(vtu_unit,'x_b_qperp',io_status)
7084 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7085 (mt_vc(qperp_results(ipoint)%backward_endpoint,1),ipoint=1,npoint)
7086 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7087 call mt_write_vtu_float_array_start(vtu_unit,'y_b_qperp',io_status)
7088 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7089 (mt_vc(qperp_results(ipoint)%backward_endpoint,2),ipoint=1,npoint)
7090 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7091 call mt_write_vtu_float_array_start(vtu_unit,'z_b_qperp',io_status)
7092 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7093 (mt_vc(qperp_results(ipoint)%backward_endpoint,3),ipoint=1,npoint)
7094 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7095
7096 call mt_write_vtu_int_array_start(vtu_unit,'valid_qperp_method2', &
7097 io_status)
7098 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7099 (merge(1,0,qperp_results(ipoint)%valid),ipoint=1,npoint)
7100 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7101 call mt_write_vtu_int_array_start(vtu_unit,'status_qperp_method2', &
7102 io_status)
7103 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7104 (qperp_results(ipoint)%status,ipoint=1,npoint)
7105 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7106 call mt_write_vtu_int_array_start(vtu_unit,'face_forward_qperp', &
7107 io_status)
7108 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7109 (qperp_results(ipoint)%forward_face,ipoint=1,npoint)
7110 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7111 call mt_write_vtu_int_array_start(vtu_unit,'face_backward_qperp', &
7112 io_status)
7113 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7114 (qperp_results(ipoint)%backward_face,ipoint=1,npoint)
7115 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7116 call mt_write_vtu_int_array_start(vtu_unit,'status_forward_qperp', &
7117 io_status)
7118 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7119 (qperp_results(ipoint)%forward_status,ipoint=1,npoint)
7120 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7121 call mt_write_vtu_int_array_start(vtu_unit,'status_backward_qperp', &
7122 io_status)
7123 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7124 (qperp_results(ipoint)%backward_status,ipoint=1,npoint)
7125 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7126 end subroutine mt_write_vtu_qperp_method2_pointdata
7127
7128 subroutine mt_write_vtu_q_product_pointdata(vtu_unit,qperp_results, &
7129 npoint,write_raw_q,io_status)
7130 integer, intent(in) :: vtu_unit,npoint
7131 type(trace_qperp_result), intent(in) :: qperp_results(npoint)
7132 logical, intent(in) :: write_raw_q
7133 integer, intent(inout) :: io_status
7134
7135 integer :: ipoint
7136
7137 if (write_raw_q) then
7138 call mt_write_vtu_float_array_start(vtu_unit,'q',io_status)
7139 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7140 (qperp_results(ipoint)%q0,ipoint=1,npoint)
7141 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7142 endif
7143
7144 call mt_write_vtu_float_array_start(vtu_unit,'logQ',io_status)
7145 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7146 (mt_visual_valid_float(qperp_results(ipoint)%logq0, &
7147 qperp_results(ipoint)%valid_q0),ipoint=1,npoint)
7148 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7149 call mt_write_vtu_int_array_start(vtu_unit,'valid_Q',io_status)
7150 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7151 (merge(1,0,qperp_results(ipoint)%valid_q0),ipoint=1,npoint)
7152 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7153 call mt_write_vtu_int_array_start(vtu_unit,'status_Q',io_status)
7154 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7155 (qperp_results(ipoint)%status_q0,ipoint=1,npoint)
7156 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7157 call mt_write_vtu_int_array_start(vtu_unit,'face_pair_Q',io_status)
7158 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7159 (mt_q_result_face_pair(qperp_results(ipoint)),ipoint=1,npoint)
7160 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7161 call mt_write_vtu_int_array_start(vtu_unit,'connection_type_Q', &
7162 io_status)
7163 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7164 (mt_q_result_connection_type(qperp_results(ipoint)),ipoint=1,npoint)
7165 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7166 end subroutine mt_write_vtu_q_product_pointdata
7167
7168 subroutine mt_write_vtu_spherical_topology_pointdata(vtu_unit,topology, &
7169 npoint,do_twist,do_q,q_results,do_qperp,qperp_results,io_status)
7170 integer, intent(in) :: vtu_unit,npoint
7171 type(trace_topology_result), intent(in) :: topology(npoint)
7172 logical, intent(in) :: do_twist,do_q,do_qperp
7173 type(trace_qperp_result), intent(in) :: q_results(:)
7174 type(trace_qperp_result), intent(in) :: qperp_results(:)
7175 integer, intent(inout) :: io_status
7176
7177 integer :: ipoint
7178
7179 write(vtu_unit,'(a)',iostat=io_status) '<PointData>'
7180 if (io_status/=0) return
7181
7182 if (.not.mt_vtk_detail_is_full()) then
7183 call mt_write_vtu_spherical_minimal_pointdata(vtu_unit,topology, &
7184 npoint,do_twist,do_q,q_results,do_qperp,qperp_results, &
7185 io_status)
7186 if (io_status==0) write(vtu_unit,'(a)',iostat=io_status) &
7187 '</PointData>'
7188 return
7189 endif
7190
7191 call mt_write_vtu_float_array_start(vtu_unit,'length_total',io_status)
7192 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7193 (mt_visual_float(topology(ipoint)%length_total),ipoint=1,npoint)
7194 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7195 call mt_write_vtu_float_array_start(vtu_unit,'length_backward', &
7196 io_status)
7197 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7198 (topology(ipoint)%length_backward,ipoint=1,npoint)
7199 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7200 call mt_write_vtu_float_array_start(vtu_unit,'length_forward', &
7201 io_status)
7202 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7203 (topology(ipoint)%length_forward,ipoint=1,npoint)
7204 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7205
7206 if (do_twist) then
7207 call mt_write_vtu_float_array_start(vtu_unit,'twist_total',io_status)
7208 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7209 (mt_visual_valid_float(topology(ipoint)%twist_total, &
7210 topology(ipoint)%valid_twist),ipoint=1,npoint)
7211 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7212 call mt_write_vtu_float_array_start(vtu_unit,'twist_backward', &
7213 io_status)
7214 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7215 (mt_visual_valid_float(topology(ipoint)%twist_backward, &
7216 topology(ipoint)%valid_twist),ipoint=1,npoint)
7217 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7218 call mt_write_vtu_float_array_start(vtu_unit,'twist_forward', &
7219 io_status)
7220 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7221 (mt_visual_valid_float(topology(ipoint)%twist_forward, &
7222 topology(ipoint)%valid_twist),ipoint=1,npoint)
7223 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7224 call mt_write_vtu_int_array_start(vtu_unit,'valid_twist',io_status)
7225 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7226 (merge(1,0,topology(ipoint)%valid_twist),ipoint=1,npoint)
7227 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7228 call mt_write_vtu_int_array_start(vtu_unit,'status_twist',io_status)
7229 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7230 (topology(ipoint)%status_twist,ipoint=1,npoint)
7231 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7232 endif
7233
7234 if (do_q) then
7235 call mt_write_vtu_float_array_start(vtu_unit,'logQ',io_status)
7236 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7237 (mt_visual_valid_float(q_results(ipoint)%logq0, &
7238 q_results(ipoint)%valid_q0),ipoint=1,npoint)
7239 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7240 call mt_write_vtu_int_array_start(vtu_unit,'valid_Q',io_status)
7241 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7242 (merge(1,0,q_results(ipoint)%valid_q0),ipoint=1,npoint)
7243 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7244 call mt_write_vtu_int_array_start(vtu_unit,'status_Q',io_status)
7245 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7246 (q_results(ipoint)%status_q0,ipoint=1,npoint)
7247 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7248 endif
7249
7250 if (do_qperp) then
7251 call mt_write_vtu_float_array_start(vtu_unit,'logQperp',io_status)
7252 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7253 (mt_visual_valid_float(qperp_results(ipoint)%logqperp, &
7254 qperp_results(ipoint)%valid),ipoint=1,npoint)
7255 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7256 call mt_write_vtu_int_array_start(vtu_unit,'valid_Qperp',io_status)
7257 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7258 (merge(1,0,qperp_results(ipoint)%valid),ipoint=1,npoint)
7259 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7260 call mt_write_vtu_int_array_start(vtu_unit,'status_Qperp',io_status)
7261 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7262 (qperp_results(ipoint)%status,ipoint=1,npoint)
7263 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7264 endif
7265
7266 call mt_write_vtu_float_array_start(vtu_unit,'r_b',io_status)
7267 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7268 (topology(ipoint)%backward_endpoint(1),ipoint=1,npoint)
7269 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7270 call mt_write_vtu_float_array_start(vtu_unit,'theta_b',io_status)
7271 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7272 (mt_vc(topology(ipoint)%backward_endpoint,2), &
7273 ipoint=1,npoint)
7274 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7275 call mt_write_vtu_float_array_start(vtu_unit,'phi_b',io_status)
7276 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7277 (mt_vc(topology(ipoint)%backward_endpoint,3), &
7278 ipoint=1,npoint)
7279 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7280 call mt_write_vtu_float_array_start(vtu_unit,'r_f',io_status)
7281 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7282 (topology(ipoint)%forward_endpoint(1),ipoint=1,npoint)
7283 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7284 call mt_write_vtu_float_array_start(vtu_unit,'theta_f',io_status)
7285 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7286 (mt_vc(topology(ipoint)%forward_endpoint,2), &
7287 ipoint=1,npoint)
7288 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7289 call mt_write_vtu_float_array_start(vtu_unit,'phi_f',io_status)
7290 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7291 (mt_vc(topology(ipoint)%forward_endpoint,3), &
7292 ipoint=1,npoint)
7293 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7294
7295 call mt_write_vtu_int_array_start(vtu_unit,'face_backward',io_status)
7296 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7297 (topology(ipoint)%backward_face,ipoint=1,npoint)
7298 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7299 call mt_write_vtu_int_array_start(vtu_unit,'face_forward',io_status)
7300 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7301 (topology(ipoint)%forward_face,ipoint=1,npoint)
7302 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7303 call mt_write_vtu_int_array_start(vtu_unit,'connection_type_spherical', &
7304 io_status)
7305 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7306 (mt_spherical_connection_type(topology(ipoint)%backward_face, &
7307 topology(ipoint)%forward_face,topology(ipoint)%valid), &
7308 ipoint=1,npoint)
7309 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7310 call mt_write_vtu_int_array_start(vtu_unit,'nstep_backward',io_status)
7311 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7312 (topology(ipoint)%backward_nstep,ipoint=1,npoint)
7313 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7314 call mt_write_vtu_int_array_start(vtu_unit,'nstep_forward',io_status)
7315 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7316 (topology(ipoint)%forward_nstep,ipoint=1,npoint)
7317 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7318 call mt_write_vtu_int_array_start(vtu_unit,'status_backward',io_status)
7319 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7320 (topology(ipoint)%backward_status,ipoint=1,npoint)
7321 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7322 call mt_write_vtu_int_array_start(vtu_unit,'status_forward',io_status)
7323 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7324 (topology(ipoint)%forward_status,ipoint=1,npoint)
7325 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7326 call mt_write_vtu_int_array_start(vtu_unit,'valid',io_status)
7327 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7328 (merge(1,0,topology(ipoint)%valid),ipoint=1,npoint)
7329 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7330
7331 if (io_status==0) write(vtu_unit,'(a)',iostat=io_status) '</PointData>'
7332 end subroutine mt_write_vtu_spherical_topology_pointdata
7333
7334 subroutine mt_write_vtu_spherical_minimal_pointdata(vtu_unit,topology, &
7335 npoint,do_twist,do_q,q_results,do_qperp,qperp_results,io_status)
7336 integer, intent(in) :: vtu_unit,npoint
7337 type(trace_topology_result), intent(in) :: topology(npoint)
7338 logical, intent(in) :: do_twist,do_q,do_qperp
7339 type(trace_qperp_result), intent(in) :: q_results(:)
7340 type(trace_qperp_result), intent(in) :: qperp_results(:)
7341 integer, intent(inout) :: io_status
7342
7343 integer :: ipoint
7344
7345 call mt_write_vtu_float_array_start(vtu_unit,'length_total',io_status)
7346 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7347 (mt_visual_float(topology(ipoint)%length_total),ipoint=1,npoint)
7348 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7349
7350 if (do_twist) then
7351 call mt_write_vtu_float_array_start(vtu_unit,'twist_total',io_status)
7352 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7353 (mt_visual_valid_float(topology(ipoint)%twist_total, &
7354 topology(ipoint)%valid_twist),ipoint=1,npoint)
7355 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7356 endif
7357
7358 if (do_q) then
7359 call mt_write_vtu_float_array_start(vtu_unit,'logQ',io_status)
7360 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7361 (mt_visual_valid_float(q_results(ipoint)%logq0, &
7362 q_results(ipoint)%valid_q0),ipoint=1,npoint)
7363 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7364 endif
7365
7366 if (do_qperp) then
7367 call mt_write_vtu_float_array_start(vtu_unit,'logQperp',io_status)
7368 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7369 (mt_visual_valid_float(qperp_results(ipoint)%logqperp, &
7370 qperp_results(ipoint)%valid),ipoint=1,npoint)
7371 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7372 endif
7373 end subroutine mt_write_vtu_spherical_minimal_pointdata
7374
7375 subroutine mt_write_vtu_file_header(vtu_unit,npoint,ncell)
7376 integer, intent(in) :: vtu_unit,npoint,ncell
7377
7378 write(vtu_unit,'(a)') '<?xml version="1.0"?>'
7379 write(vtu_unit,'(a)') &
7380 '<VTKFile type="UnstructuredGrid" version="0.1" byte_order="LittleEndian">'
7381 write(vtu_unit,'(a)') '<UnstructuredGrid>'
7382 write(vtu_unit,'(a,i0,a,i0,a)') '<Piece NumberOfPoints="',npoint, &
7383 '" NumberOfCells="',ncell,'">'
7384 end subroutine mt_write_vtu_file_header
7385
7386 subroutine mt_write_vtu_file_footer(vtu_unit,io_status)
7387 integer, intent(in) :: vtu_unit
7388 integer, intent(inout) :: io_status
7389
7390 write(vtu_unit,'(a)',iostat=io_status) '</Piece>'
7391 if (io_status==0) write(vtu_unit,'(a)',iostat=io_status) &
7392 '</UnstructuredGrid>'
7393 if (io_status==0) write(vtu_unit,'(a)',iostat=io_status) '</VTKFile>'
7394 end subroutine mt_write_vtu_file_footer
7395
7396 subroutine mt_write_vtu_product_pointdata(vtu_unit,length_results, &
7397 twist_results,q_results,qperp_results,npoint,do_twist,do_q, &
7398 do_qperp,io_status,do_length)
7399 integer, intent(in) :: vtu_unit,npoint
7400 type(trace_length_result), intent(in) :: length_results(npoint)
7401 type(trace_twist_result), intent(in) :: twist_results(:)
7402 type(trace_qperp_result), intent(in) :: q_results(:)
7403 type(trace_qperp_result), intent(in) :: qperp_results(:)
7404 logical, intent(in) :: do_twist,do_q,do_qperp
7405 integer, intent(inout) :: io_status
7406 logical, intent(in), optional :: do_length
7407
7408 integer :: ipoint
7409 logical :: do_length_eff
7410
7411 write(vtu_unit,'(a)',iostat=io_status) '<PointData>'
7412 if (io_status/=0) return
7413 do_length_eff=.true.
7414 if (present(do_length)) do_length_eff=do_length
7415
7416 if (.not.mt_vtk_detail_is_full()) then
7417 call mt_write_vtu_product_minimal_pointdata(vtu_unit,length_results, &
7418 twist_results,q_results,qperp_results,npoint,do_twist,do_q, &
7419 do_qperp,io_status,do_length=do_length_eff)
7420 if (io_status==0) write(vtu_unit,'(a)',iostat=io_status) &
7421 '</PointData>'
7422 return
7423 endif
7424
7425 if (do_length_eff) then
7426 call mt_write_vtu_float_array_start(vtu_unit,'length_total',io_status)
7427 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7428 (length_results(ipoint)%total_length,ipoint=1,npoint)
7429 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7430 call mt_write_vtu_float_array_start(vtu_unit,'length_backward', &
7431 io_status)
7432 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7433 (length_results(ipoint)%backward_length,ipoint=1,npoint)
7434 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7435 call mt_write_vtu_float_array_start(vtu_unit,'length_forward', &
7436 io_status)
7437 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7438 (length_results(ipoint)%forward_length,ipoint=1,npoint)
7439 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7440
7441 call mt_write_vtu_int_array_start(vtu_unit,'nstep_backward_length', &
7442 io_status)
7443 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7444 (length_results(ipoint)%backward_nstep,ipoint=1,npoint)
7445 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7446 call mt_write_vtu_int_array_start(vtu_unit,'nstep_forward_length', &
7447 io_status)
7448 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7449 (length_results(ipoint)%forward_nstep,ipoint=1,npoint)
7450 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7451 call mt_write_vtu_int_array_start(vtu_unit,'status_backward_length', &
7452 io_status)
7453 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7454 (length_results(ipoint)%backward_status,ipoint=1,npoint)
7455 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7456 call mt_write_vtu_int_array_start(vtu_unit,'status_forward_length', &
7457 io_status)
7458 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7459 (length_results(ipoint)%forward_status,ipoint=1,npoint)
7460 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7461 endif
7462
7463 if (do_twist) then
7464 call mt_write_vtu_twist_pointdata(vtu_unit,twist_results,npoint, &
7465 io_status)
7466 endif
7467 if (do_q) then
7468 call mt_write_vtu_q_product_pointdata(vtu_unit,q_results,npoint, &
7469 .false.,io_status)
7470 endif
7471 if (do_qperp) then
7472 call mt_write_vtu_qperp_pointdata(vtu_unit,qperp_results,npoint, &
7473 io_status)
7474 endif
7475
7476 if (io_status==0) write(vtu_unit,'(a)',iostat=io_status) '</PointData>'
7477 end subroutine mt_write_vtu_product_pointdata
7478
7479 subroutine mt_write_vtu_product_minimal_pointdata(vtu_unit, &
7480 length_results,twist_results,q_results,qperp_results,npoint, &
7481 do_twist,do_q,do_qperp,io_status,do_length)
7482 integer, intent(in) :: vtu_unit,npoint
7483 type(trace_length_result), intent(in) :: length_results(npoint)
7484 type(trace_twist_result), intent(in) :: twist_results(:)
7485 type(trace_qperp_result), intent(in) :: q_results(:)
7486 type(trace_qperp_result), intent(in) :: qperp_results(:)
7487 logical, intent(in) :: do_twist,do_q,do_qperp
7488 integer, intent(inout) :: io_status
7489 logical, intent(in), optional :: do_length
7490
7491 integer :: ipoint
7492 logical :: do_length_eff
7493
7494 do_length_eff=.true.
7495 if (present(do_length)) do_length_eff=do_length
7496
7497 if (do_length_eff) then
7498 call mt_write_vtu_float_array_start(vtu_unit,'length_total',io_status)
7499 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7500 (mt_visual_float(length_results(ipoint)%total_length), &
7501 ipoint=1,npoint)
7502 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7503 endif
7504
7505 if (do_twist) then
7506 call mt_write_vtu_float_array_start(vtu_unit,'twist_total',io_status)
7507 if (io_status==0) write(vtu_unit,'(4(1pe24.16))', &
7508 iostat=io_status) &
7509 (mt_visual_float(twist_results(ipoint)%total_twist), &
7510 ipoint=1,npoint)
7511 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7512 endif
7513
7514 if (do_q) then
7515 call mt_write_vtu_float_array_start(vtu_unit,'logQ',io_status)
7516 if (io_status==0) write(vtu_unit,'(4(1pe24.16))', &
7517 iostat=io_status) &
7518 (mt_visual_valid_float(q_results(ipoint)%logq0, &
7519 q_results(ipoint)%valid_q0),ipoint=1,npoint)
7520 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7521 endif
7522
7523 if (do_qperp) then
7524 call mt_write_vtu_float_array_start(vtu_unit,'logQperp',io_status)
7525 if (io_status==0) write(vtu_unit,'(4(1pe24.16))', &
7526 iostat=io_status) &
7527 (mt_visual_valid_float(qperp_results(ipoint)%logqperp, &
7528 qperp_results(ipoint)%valid),ipoint=1,npoint)
7529 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7530 endif
7531 end subroutine mt_write_vtu_product_minimal_pointdata
7532
7533 subroutine mt_write_vtu_twist_pointdata(vtu_unit,twist_results,npoint, &
7534 io_status)
7535 integer, intent(in) :: vtu_unit,npoint
7536 type(trace_twist_result), intent(in) :: twist_results(npoint)
7537 integer, intent(inout) :: io_status
7538
7539 integer :: ipoint
7540
7541 call mt_write_vtu_float_array_start(vtu_unit,'twist_total',io_status)
7542 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7543 (twist_results(ipoint)%total_twist,ipoint=1,npoint)
7544 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7545 call mt_write_vtu_float_array_start(vtu_unit,'twist_backward', &
7546 io_status)
7547 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7548 (twist_results(ipoint)%backward_twist,ipoint=1,npoint)
7549 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7550 call mt_write_vtu_float_array_start(vtu_unit,'twist_forward', &
7551 io_status)
7552 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7553 (twist_results(ipoint)%forward_twist,ipoint=1,npoint)
7554 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7555
7556 call mt_write_vtu_int_array_start(vtu_unit,'nstep_backward_twist', &
7557 io_status)
7558 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7559 (twist_results(ipoint)%line%backward_nstep,ipoint=1,npoint)
7560 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7561 call mt_write_vtu_int_array_start(vtu_unit,'nstep_forward_twist', &
7562 io_status)
7563 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7564 (twist_results(ipoint)%line%forward_nstep,ipoint=1,npoint)
7565 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7566 call mt_write_vtu_int_array_start(vtu_unit,'status_backward_twist', &
7567 io_status)
7568 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7569 (twist_results(ipoint)%line%backward_status,ipoint=1,npoint)
7570 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7571 call mt_write_vtu_int_array_start(vtu_unit,'status_forward_twist', &
7572 io_status)
7573 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7574 (twist_results(ipoint)%line%forward_status,ipoint=1,npoint)
7575 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7576 end subroutine mt_write_vtu_twist_pointdata
7577
7578 subroutine mt_write_vtu_qperp_pointdata(vtu_unit,qperp_results,npoint, &
7579 io_status)
7580 integer, intent(in) :: vtu_unit,npoint
7581 type(trace_qperp_result), intent(in) :: qperp_results(npoint)
7582 integer, intent(inout) :: io_status
7583
7584 integer :: ipoint
7585
7586 call mt_write_vtu_float_array_start(vtu_unit,'qperp',io_status)
7587 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7588 (qperp_results(ipoint)%qperp,ipoint=1,npoint)
7589 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7590 call mt_write_vtu_float_array_start(vtu_unit,'logqperp',io_status)
7591 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7592 (qperp_results(ipoint)%logqperp,ipoint=1,npoint)
7593 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7594 call mt_write_vtu_float_array_start(vtu_unit,'N2',io_status)
7595 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7596 (qperp_results(ipoint)%N2,ipoint=1,npoint)
7597 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7598 call mt_write_vtu_float_array_start(vtu_unit,'bfactor',io_status)
7599 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7600 (qperp_results(ipoint)%bfactor,ipoint=1,npoint)
7601 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7602 call mt_write_vtu_float_array_start(vtu_unit,'length_forward_qperp', &
7603 io_status)
7604 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7605 (qperp_results(ipoint)%forward_length,ipoint=1,npoint)
7606 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7607 call mt_write_vtu_float_array_start(vtu_unit,'length_backward_qperp', &
7608 io_status)
7609 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7610 (qperp_results(ipoint)%backward_length,ipoint=1,npoint)
7611 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7612
7613 call mt_write_vtu_float_array_start(vtu_unit,'Bseed_norm',io_status)
7614 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7615 (dsqrt(sum(qperp_results(ipoint)%B_seed**2)),ipoint=1,npoint)
7616 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7617 call mt_write_vtu_float_array_start(vtu_unit,'Bf_norm',io_status)
7618 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7619 (dsqrt(sum(qperp_results(ipoint)%forward_B**2)),ipoint=1,npoint)
7620 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7621 call mt_write_vtu_float_array_start(vtu_unit,'Bb_norm',io_status)
7622 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7623 (dsqrt(sum(qperp_results(ipoint)%backward_B**2)),ipoint=1,npoint)
7624 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7625
7626 call mt_write_vtu_qperp_endpoint_pointdata(vtu_unit,qperp_results, &
7627 npoint,io_status)
7628 call mt_write_vtu_qperp_int_pointdata(vtu_unit,qperp_results,npoint, &
7629 io_status)
7630 end subroutine mt_write_vtu_qperp_pointdata
7631
7632 subroutine mt_write_vtu_qperp_endpoint_pointdata(vtu_unit,qperp_results, &
7633 npoint,io_status)
7634 integer, intent(in) :: vtu_unit,npoint
7635 type(trace_qperp_result), intent(in) :: qperp_results(npoint)
7636 integer, intent(inout) :: io_status
7637
7638 integer :: ipoint
7639
7640 call mt_write_vtu_float_array_start(vtu_unit,'x_f_qperp',io_status)
7641 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7642 (mt_vc(qperp_results(ipoint)%forward_endpoint,1),ipoint=1,npoint)
7643 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7644 call mt_write_vtu_float_array_start(vtu_unit,'y_f_qperp',io_status)
7645 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7646 (mt_vc(qperp_results(ipoint)%forward_endpoint,2),ipoint=1,npoint)
7647 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7648 call mt_write_vtu_float_array_start(vtu_unit,'z_f_qperp',io_status)
7649 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7650 (mt_vc(qperp_results(ipoint)%forward_endpoint,3),ipoint=1,npoint)
7651 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7652 call mt_write_vtu_float_array_start(vtu_unit,'x_b_qperp',io_status)
7653 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7654 (mt_vc(qperp_results(ipoint)%backward_endpoint,1),ipoint=1,npoint)
7655 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7656 call mt_write_vtu_float_array_start(vtu_unit,'y_b_qperp',io_status)
7657 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7658 (mt_vc(qperp_results(ipoint)%backward_endpoint,2),ipoint=1,npoint)
7659 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7660 call mt_write_vtu_float_array_start(vtu_unit,'z_b_qperp',io_status)
7661 if (io_status==0) write(vtu_unit,'(4(1pe24.16))',iostat=io_status) &
7662 (mt_vc(qperp_results(ipoint)%backward_endpoint,3),ipoint=1,npoint)
7663 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7664 end subroutine mt_write_vtu_qperp_endpoint_pointdata
7665
7666 subroutine mt_write_vtu_qperp_int_pointdata(vtu_unit,qperp_results, &
7667 npoint,io_status)
7668 integer, intent(in) :: vtu_unit,npoint
7669 type(trace_qperp_result), intent(in) :: qperp_results(npoint)
7670 integer, intent(inout) :: io_status
7671
7672 integer :: ipoint
7673
7674 call mt_write_vtu_int_array_start(vtu_unit,'valid_qperp',io_status)
7675 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7676 (merge(1,0,qperp_results(ipoint)%valid),ipoint=1,npoint)
7677 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7678 call mt_write_vtu_int_array_start(vtu_unit,'status_qperp',io_status)
7679 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7680 (qperp_results(ipoint)%status,ipoint=1,npoint)
7681 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7682 call mt_write_vtu_int_array_start(vtu_unit,'face_forward_qperp', &
7683 io_status)
7684 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7685 (qperp_results(ipoint)%forward_face,ipoint=1,npoint)
7686 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7687 call mt_write_vtu_int_array_start(vtu_unit,'face_backward_qperp', &
7688 io_status)
7689 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7690 (qperp_results(ipoint)%backward_face,ipoint=1,npoint)
7691 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7692 call mt_write_vtu_int_array_start(vtu_unit,'status_forward_qperp', &
7693 io_status)
7694 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7695 (qperp_results(ipoint)%forward_status,ipoint=1,npoint)
7696 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7697 call mt_write_vtu_int_array_start(vtu_unit,'status_backward_qperp', &
7698 io_status)
7699 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7700 (qperp_results(ipoint)%backward_status,ipoint=1,npoint)
7701 call mt_write_vtu_data_array_end(vtu_unit,io_status)
7702 end subroutine mt_write_vtu_qperp_int_pointdata
7703
7704 subroutine mt_write_vtu_empty_pointdata(vtu_unit,do_length,do_twist, &
7705 do_q,do_qperp)
7706 integer, intent(in) :: vtu_unit
7707 logical, intent(in) :: do_length,do_twist,do_q,do_qperp
7708
7709 write(vtu_unit,'(a)') '<PointData>'
7710 if (.not.mt_vtk_detail_is_full()) then
7711 if (do_length) then
7712 call mt_write_vtu_empty_float_array(vtu_unit,'length_total')
7713 endif
7714 if (do_twist) then
7715 call mt_write_vtu_empty_float_array(vtu_unit,'twist_total')
7716 endif
7717 if (do_q) then
7718 call mt_write_vtu_empty_float_array(vtu_unit,'logQ')
7719 endif
7720 if (do_qperp) then
7721 call mt_write_vtu_empty_float_array(vtu_unit,'logQperp')
7722 endif
7723 write(vtu_unit,'(a)') '</PointData>'
7724 return
7725 endif
7726 if (do_length) then
7727 call mt_write_vtu_empty_float_array(vtu_unit,'length_total')
7728 call mt_write_vtu_empty_float_array(vtu_unit,'length_backward')
7729 call mt_write_vtu_empty_float_array(vtu_unit,'length_forward')
7730 call mt_write_vtu_empty_int_array(vtu_unit,'nstep_backward_length')
7731 call mt_write_vtu_empty_int_array(vtu_unit,'nstep_forward_length')
7732 call mt_write_vtu_empty_int_array(vtu_unit,'status_backward_length')
7733 call mt_write_vtu_empty_int_array(vtu_unit,'status_forward_length')
7734 endif
7735 if (do_twist) then
7736 call mt_write_vtu_empty_float_array(vtu_unit,'twist_total')
7737 call mt_write_vtu_empty_float_array(vtu_unit,'twist_backward')
7738 call mt_write_vtu_empty_float_array(vtu_unit,'twist_forward')
7739 call mt_write_vtu_empty_int_array(vtu_unit,'nstep_backward_twist')
7740 call mt_write_vtu_empty_int_array(vtu_unit,'nstep_forward_twist')
7741 call mt_write_vtu_empty_int_array(vtu_unit,'status_backward_twist')
7742 call mt_write_vtu_empty_int_array(vtu_unit,'status_forward_twist')
7743 endif
7744 if (do_q) then
7745 call mt_write_vtu_empty_float_array(vtu_unit,'q')
7746 call mt_write_vtu_empty_float_array(vtu_unit,'logQ')
7747 call mt_write_vtu_empty_float_array(vtu_unit,'N2_q')
7748 call mt_write_vtu_empty_float_array(vtu_unit,'bfactor_q')
7749 call mt_write_vtu_empty_float_array(vtu_unit,'length_forward_q')
7750 call mt_write_vtu_empty_float_array(vtu_unit,'length_backward_q')
7751 call mt_write_vtu_empty_float_array(vtu_unit,'Bseed_norm_q')
7752 call mt_write_vtu_empty_float_array(vtu_unit,'Bf_norm_q')
7753 call mt_write_vtu_empty_float_array(vtu_unit,'Bb_norm_q')
7754 call mt_write_vtu_empty_int_array(vtu_unit,'valid_Q')
7755 call mt_write_vtu_empty_int_array(vtu_unit,'status_Q')
7756 call mt_write_vtu_empty_int_array(vtu_unit,'face_forward_Q')
7757 call mt_write_vtu_empty_int_array(vtu_unit,'face_backward_Q')
7758 call mt_write_vtu_empty_int_array(vtu_unit,'status_forward_Q')
7759 call mt_write_vtu_empty_int_array(vtu_unit,'status_backward_Q')
7760 endif
7761 if (do_qperp) then
7762 call mt_write_vtu_empty_float_array(vtu_unit,'qperp')
7763 call mt_write_vtu_empty_float_array(vtu_unit,'logqperp')
7764 call mt_write_vtu_empty_float_array(vtu_unit,'N2')
7765 call mt_write_vtu_empty_float_array(vtu_unit,'bfactor')
7766 call mt_write_vtu_empty_float_array(vtu_unit,'length_forward_qperp')
7767 call mt_write_vtu_empty_float_array(vtu_unit,'length_backward_qperp')
7768 call mt_write_vtu_empty_float_array(vtu_unit,'Bseed_norm')
7769 call mt_write_vtu_empty_float_array(vtu_unit,'Bf_norm')
7770 call mt_write_vtu_empty_float_array(vtu_unit,'Bb_norm')
7771 call mt_write_vtu_empty_float_array(vtu_unit,'x_f_qperp')
7772 call mt_write_vtu_empty_float_array(vtu_unit,'y_f_qperp')
7773 call mt_write_vtu_empty_float_array(vtu_unit,'z_f_qperp')
7774 call mt_write_vtu_empty_float_array(vtu_unit,'x_b_qperp')
7775 call mt_write_vtu_empty_float_array(vtu_unit,'y_b_qperp')
7776 call mt_write_vtu_empty_float_array(vtu_unit,'z_b_qperp')
7777 call mt_write_vtu_empty_int_array(vtu_unit,'valid_qperp')
7778 call mt_write_vtu_empty_int_array(vtu_unit,'status_qperp')
7779 call mt_write_vtu_empty_int_array(vtu_unit,'face_forward_qperp')
7780 call mt_write_vtu_empty_int_array(vtu_unit,'face_backward_qperp')
7781 call mt_write_vtu_empty_int_array(vtu_unit,'status_forward_qperp')
7782 call mt_write_vtu_empty_int_array(vtu_unit,'status_backward_qperp')
7783 endif
7784 write(vtu_unit,'(a)') '</PointData>'
7785 end subroutine mt_write_vtu_empty_pointdata
7786
7787 subroutine mt_write_vtu_empty_float_array(vtu_unit,name)
7788 integer, intent(in) :: vtu_unit
7789 character(len=*), intent(in) :: name
7790
7791 write(vtu_unit,'(a,a,a)') '<DataArray type="Float64" Name="', &
7792 trim(name),'" format="ascii">'
7793 write(vtu_unit,'(a)') '</DataArray>'
7794 end subroutine mt_write_vtu_empty_float_array
7795
7796 subroutine mt_write_vtu_empty_int_array(vtu_unit,name)
7797 integer, intent(in) :: vtu_unit
7798 character(len=*), intent(in) :: name
7799
7800 write(vtu_unit,'(a,a,a)') '<DataArray type="Int32" Name="', &
7801 trim(name),'" format="ascii">'
7802 write(vtu_unit,'(a)') '</DataArray>'
7803 end subroutine mt_write_vtu_empty_int_array
7804
7805 subroutine mt_write_vtu_float_array_start(vtu_unit,name,io_status)
7806 integer, intent(in) :: vtu_unit
7807 character(len=*), intent(in) :: name
7808 integer, intent(inout) :: io_status
7809
7810 if (io_status/=0) return
7811 write(vtu_unit,'(a,a,a)',iostat=io_status) &
7812 '<DataArray type="Float64" Name="',trim(name),'" format="ascii">'
7813 end subroutine mt_write_vtu_float_array_start
7814
7815 subroutine mt_write_vtu_int_array_start(vtu_unit,name,io_status)
7816 integer, intent(in) :: vtu_unit
7817 character(len=*), intent(in) :: name
7818 integer, intent(inout) :: io_status
7819
7820 if (io_status/=0) return
7821 write(vtu_unit,'(a,a,a)',iostat=io_status) &
7822 '<DataArray type="Int32" Name="',trim(name),'" format="ascii">'
7823 end subroutine mt_write_vtu_int_array_start
7824
7825 subroutine mt_write_vtu_data_array_end(vtu_unit,io_status)
7826 integer, intent(in) :: vtu_unit
7827 integer, intent(inout) :: io_status
7828
7829 if (io_status/=0) return
7830 write(vtu_unit,'(a)',iostat=io_status) '</DataArray>'
7831 end subroutine mt_write_vtu_data_array_end
7832
7833 subroutine mt_write_vtu_points(vtu_unit,length_results,npoint,io_status)
7834 integer, intent(in) :: vtu_unit,npoint
7835 type(trace_length_result), intent(in) :: length_results(npoint)
7836 integer, intent(inout) :: io_status
7837
7838 double precision :: seed_xyz(3)
7839 integer :: ipoint
7840
7841 write(vtu_unit,'(a)',iostat=io_status) '<Points>'
7842 if (io_status==0) then
7843 write(vtu_unit,'(a)',iostat=io_status) &
7844 '<DataArray type="Float64" NumberOfComponents="3" format="ascii">'
7845 endif
7846 do ipoint=1,npoint
7847 call mt_vtu_point_from_coord(length_results(ipoint)%seed,seed_xyz)
7848 if (io_status==0) write(vtu_unit,'(3(1pe24.16))', &
7849 iostat=io_status) seed_xyz
7850 enddo
7851 if (io_status==0) write(vtu_unit,'(a)',iostat=io_status) &
7852 '</DataArray>'
7853 if (io_status==0) write(vtu_unit,'(a)',iostat=io_status) '</Points>'
7854 end subroutine mt_write_vtu_points
7855
7856 subroutine mt_write_vtu_topology_points(vtu_unit,topology,npoint, &
7857 io_status)
7858 integer, intent(in) :: vtu_unit,npoint
7859 type(trace_topology_result), intent(in) :: topology(npoint)
7860 integer, intent(inout) :: io_status
7861
7862 double precision :: seed_xyz(3)
7863 integer :: ipoint
7864
7865 write(vtu_unit,'(a)',iostat=io_status) '<Points>'
7866 if (io_status==0) then
7867 write(vtu_unit,'(a)',iostat=io_status) &
7868 '<DataArray type="Float64" NumberOfComponents="3" format="ascii">'
7869 endif
7870 do ipoint=1,npoint
7871 call mt_vtu_point_from_coord(topology(ipoint)%seed,seed_xyz)
7872 if (io_status==0) write(vtu_unit,'(3(1pe24.16))', &
7873 iostat=io_status) seed_xyz
7874 enddo
7875 if (io_status==0) write(vtu_unit,'(a)',iostat=io_status) &
7876 '</DataArray>'
7877 if (io_status==0) write(vtu_unit,'(a)',iostat=io_status) '</Points>'
7878 end subroutine mt_write_vtu_topology_points
7879
7880 subroutine mt_vtu_point_from_coord(coord,point_xyz)
7881 double precision, intent(in) :: coord(ndim)
7882 double precision, intent(out) :: point_xyz(3)
7883
7884 double precision :: r,theta,phi,sin_theta
7885
7886 point_xyz=0.d0
7887 if (geo_coordinate==geo_spherical .and. ndim==3) then
7888 {^ifthreed
7889 r=coord(1)
7890 theta=coord(2)
7891 phi=coord(3)
7892 sin_theta=dsin(theta)
7893 point_xyz(1)=r*sin_theta*dcos(phi)
7894 point_xyz(2)=r*sin_theta*dsin(phi)
7895 point_xyz(3)=r*dcos(theta)
7896 }
7897 else
7898 point_xyz(1)=mt_vc(coord,1)
7899 point_xyz(2)=mt_vc(coord,2)
7900 point_xyz(3)=mt_vc(coord,3)
7901 endif
7902 end subroutine mt_vtu_point_from_coord
7903
7904 subroutine mt_write_vtu_vertex_cells(vtu_unit,npoint,io_status)
7905 integer, intent(in) :: vtu_unit,npoint
7906 integer, intent(inout) :: io_status
7907
7908 integer :: ipoint
7909
7910 write(vtu_unit,'(a)',iostat=io_status) '<Cells>'
7911 if (io_status==0) write(vtu_unit,'(a)',iostat=io_status) &
7912 '<DataArray type="Int32" Name="connectivity" format="ascii">'
7913 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7914 (ipoint-1,ipoint=1,npoint)
7915 if (io_status==0) write(vtu_unit,'(a)',iostat=io_status) &
7916 '</DataArray>'
7917 if (io_status==0) write(vtu_unit,'(a)',iostat=io_status) &
7918 '<DataArray type="Int32" Name="offsets" format="ascii">'
7919 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7920 (ipoint,ipoint=1,npoint)
7921 if (io_status==0) write(vtu_unit,'(a)',iostat=io_status) &
7922 '</DataArray>'
7923 if (io_status==0) write(vtu_unit,'(a)',iostat=io_status) &
7924 '<DataArray type="UInt8" Name="types" format="ascii">'
7925 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7926 (1,ipoint=1,npoint)
7927 if (io_status==0) write(vtu_unit,'(a)',iostat=io_status) &
7928 '</DataArray>'
7929 if (io_status==0) write(vtu_unit,'(a)',iostat=io_status) '</Cells>'
7930 end subroutine mt_write_vtu_vertex_cells
7931
7932 subroutine mt_write_vtu_quad_cells(vtu_unit,n1,n2,io_status)
7933 integer, intent(in) :: vtu_unit,n1,n2
7934 integer, intent(inout) :: io_status
7935
7936 integer :: i,j,icell,p,ncell
7937
7938 ncell=(n1-1)*(n2-1)
7939 write(vtu_unit,'(a)',iostat=io_status) '<Cells>'
7940 if (io_status==0) write(vtu_unit,'(a)',iostat=io_status) &
7941 '<DataArray type="Int32" Name="connectivity" format="ascii">'
7942 do j=1,n2-1
7943 do i=1,n1-1
7944 p=(j-1)*n1+(i-1)
7945 if (io_status==0) write(vtu_unit,'(4(i0,1x))',iostat=io_status) &
7946 p,p+1,p+1+n1,p+n1
7947 enddo
7948 enddo
7949 if (io_status==0) write(vtu_unit,'(a)',iostat=io_status) &
7950 '</DataArray>'
7951 if (io_status==0) write(vtu_unit,'(a)',iostat=io_status) &
7952 '<DataArray type="Int32" Name="offsets" format="ascii">'
7953 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7954 (4*icell,icell=1,ncell)
7955 if (io_status==0) write(vtu_unit,'(a)',iostat=io_status) &
7956 '</DataArray>'
7957 if (io_status==0) write(vtu_unit,'(a)',iostat=io_status) &
7958 '<DataArray type="UInt8" Name="types" format="ascii">'
7959 if (io_status==0) write(vtu_unit,'(12(i0,1x))',iostat=io_status) &
7960 (9,icell=1,ncell)
7961 if (io_status==0) write(vtu_unit,'(a)',iostat=io_status) &
7962 '</DataArray>'
7963 if (io_status==0) write(vtu_unit,'(a)',iostat=io_status) '</Cells>'
7964 end subroutine mt_write_vtu_quad_cells
7965
7966 subroutine mt_write_vtu_cells_empty(vtu_unit,io_status)
7967 integer, intent(in) :: vtu_unit
7968 integer, intent(inout) :: io_status
7969
7970 write(vtu_unit,'(a)',iostat=io_status) '<Cells>'
7971 if (io_status==0) write(vtu_unit,'(a)',iostat=io_status) &
7972 '<DataArray type="Int32" Name="connectivity" format="ascii">'
7973 if (io_status==0) write(vtu_unit,'(a)',iostat=io_status) &
7974 '</DataArray>'
7975 if (io_status==0) write(vtu_unit,'(a)',iostat=io_status) &
7976 '<DataArray type="Int32" Name="offsets" format="ascii">'
7977 if (io_status==0) write(vtu_unit,'(a)',iostat=io_status) &
7978 '</DataArray>'
7979 if (io_status==0) write(vtu_unit,'(a)',iostat=io_status) &
7980 '<DataArray type="UInt8" Name="types" format="ascii">'
7981 if (io_status==0) write(vtu_unit,'(a)',iostat=io_status) &
7982 '</DataArray>'
7983 if (io_status==0) write(vtu_unit,'(a)',iostat=io_status) '</Cells>'
7984 end subroutine mt_write_vtu_cells_empty
7985
7986 subroutine mt_write_twist_plane_csv(results,n1,n2,csv_file,caller, &
7987 index_header)
7988 integer, intent(in) :: n1,n2
7989 type(trace_twist_result), intent(in) :: results(n1*n2)
7990 character(len=*), intent(in) :: csv_file,caller,index_header
7991
7992 double precision :: seed_xyz(3)
7993 integer :: csv_unit,io_status,i,j,iseed
7994
7995 open(newunit=csv_unit,file=trim(csv_file),status='replace', &
7996 action='write',form='formatted',iostat=io_status)
7997 if (io_status/=0) then
7998 call mpistop(trim(caller)//' could not open CSV file')
7999 endif
8000
8001 write(csv_unit,'(a)',iostat=io_status) &
8002 trim(index_header)//',seed_x,seed_y,seed_z,'// &
8003 'length_total,length_backward,length_forward,'// &
8004 'twist_total,twist_backward,twist_forward,'// &
8005 'nstep_backward,nstep_forward,'// &
8006 'status_backward,status_forward'
8007 if (io_status/=0) then
8008 close(csv_unit)
8009 call mpistop(trim(caller)//' could not write CSV header')
8010 endif
8011
8012 do j=1,n2
8013 do i=1,n1
8014 iseed=(j-1)*n1+i
8015 seed_xyz=0.d0
8016 seed_xyz(1:ndim)=results(iseed)%line%seed
8017 write(csv_unit,'(i0,",",i0,9(",",es24.16),4(",",i0))', &
8018 iostat=io_status) i,j,seed_xyz, &
8019 results(iseed)%line%total_length, &
8020 results(iseed)%line%backward_length, &
8021 results(iseed)%line%forward_length, &
8022 results(iseed)%total_twist, &
8023 results(iseed)%backward_twist, &
8024 results(iseed)%forward_twist, &
8025 results(iseed)%line%backward_nstep, &
8026 results(iseed)%line%forward_nstep, &
8027 results(iseed)%line%backward_status, &
8028 results(iseed)%line%forward_status
8029 if (io_status/=0) then
8030 close(csv_unit)
8031 call mpistop(trim(caller)//' could not write CSV data')
8032 endif
8033 enddo
8034 enddo
8035
8036 close(csv_unit)
8037 end subroutine mt_write_twist_plane_csv
8038
8039 subroutine mt_write_q_plane_csv(results,n1,n2,csv_file,caller, &
8040 index_header)
8041 integer, intent(in) :: n1,n2
8042 type(trace_qperp_result), intent(in) :: results(n1*n2)
8043 character(len=*), intent(in) :: csv_file,caller,index_header
8044
8045 integer :: csv_unit,io_status,i,j,iseed
8046
8047 open(newunit=csv_unit,file=trim(csv_file),status='replace', &
8048 action='write',form='formatted',iostat=io_status)
8049 if (io_status/=0) then
8050 call mpistop(trim(caller)//' could not open CSV file')
8051 endif
8052
8053 write(csv_unit,'(a)',iostat=io_status) &
8054 trim(index_header)//',seed_x,seed_y,seed_z,'// &
8055 'logQ,valid_Q,status_Q,'// &
8056 'face_forward_Q,face_backward_Q,'// &
8057 'status_forward_Q,status_backward_Q,'// &
8058 'length_forward_Q,length_backward_Q,'// &
8059 'x_f_Q,y_f_Q,z_f_Q,x_b_Q,y_b_Q,z_b_Q'
8060 if (io_status/=0) then
8061 close(csv_unit)
8062 call mpistop(trim(caller)//' could not write CSV header')
8063 endif
8064
8065 do j=1,n2
8066 do i=1,n1
8067 iseed=(j-1)*n1+i
8068 write(csv_unit, &
8069 '(i0,",",i0,4(",",es24.16),",",l1,5(",",i0),'// &
8070 '8(",",es24.16))',iostat=io_status) &
8071 i,j,results(iseed)%seed, &
8072 results(iseed)%logq0, &
8073 results(iseed)%valid_q0,results(iseed)%status_q0, &
8074 results(iseed)%forward_face,results(iseed)%backward_face, &
8075 results(iseed)%forward_status,results(iseed)%backward_status, &
8076 results(iseed)%forward_length,results(iseed)%backward_length, &
8077 results(iseed)%forward_endpoint, &
8078 results(iseed)%backward_endpoint
8079 if (io_status/=0) then
8080 close(csv_unit)
8081 call mpistop(trim(caller)//' could not write CSV data')
8082 endif
8083 enddo
8084 enddo
8085
8086 close(csv_unit)
8087 end subroutine mt_write_q_plane_csv
8088
8089 subroutine mt_write_qperp_plane_csv(results,n1,n2,csv_file,caller, &
8090 index_header)
8091 integer, intent(in) :: n1,n2
8092 type(trace_qperp_result), intent(in) :: results(n1*n2)
8093 character(len=*), intent(in) :: csv_file,caller,index_header
8094
8095 double precision :: bseed_norm,bf_norm,bb_norm
8096 integer :: csv_unit,io_status,i,j,iseed
8097
8098 open(newunit=csv_unit,file=trim(csv_file),status='replace', &
8099 action='write',form='formatted',iostat=io_status)
8100 if (io_status/=0) then
8101 call mpistop(trim(caller)//' could not open CSV file')
8102 endif
8103
8104 write(csv_unit,'(a)',iostat=io_status) &
8105 trim(index_header)//',seed_x,seed_y,seed_z,'// &
8106 'qperp,logqperp,valid,status,'// &
8107 'N2,bfactor,'// &
8108 'face_forward,face_backward,'// &
8109 'status_forward,status_backward,'// &
8110 'length_forward,length_backward,'// &
8111 'Bseed_norm,Bf_norm,Bb_norm,'// &
8112 'x_f,y_f,z_f,x_b,y_b,z_b'
8113 if (io_status/=0) then
8114 close(csv_unit)
8115 call mpistop(trim(caller)//' could not write CSV header')
8116 endif
8117
8118 do j=1,n2
8119 do i=1,n1
8120 iseed=(j-1)*n1+i
8121 bseed_norm=dsqrt(sum(results(iseed)%B_seed**2))
8122 bf_norm=dsqrt(sum(results(iseed)%forward_B**2))
8123 bb_norm=dsqrt(sum(results(iseed)%backward_B**2))
8124 write(csv_unit, &
8125 '(i0,",",i0,5(",",es24.16),",",l1,",",i0,'// &
8126 '2(",",es24.16),4(",",i0),11(",",es24.16))', &
8127 iostat=io_status) &
8128 i,j,results(iseed)%seed, &
8129 results(iseed)%qperp,results(iseed)%logqperp, &
8130 results(iseed)%valid,results(iseed)%status, &
8131 results(iseed)%N2,results(iseed)%bfactor, &
8132 results(iseed)%forward_face,results(iseed)%backward_face, &
8133 results(iseed)%forward_status,results(iseed)%backward_status, &
8134 results(iseed)%forward_length,results(iseed)%backward_length, &
8135 bseed_norm,bf_norm,bb_norm, &
8136 results(iseed)%forward_endpoint, &
8137 results(iseed)%backward_endpoint
8138 if (io_status/=0) then
8139 close(csv_unit)
8140 call mpistop(trim(caller)//' could not write CSV data')
8141 endif
8142 enddo
8143 enddo
8144
8145 close(csv_unit)
8146 end subroutine mt_write_qperp_plane_csv
8147
8148 subroutine mt_write_qperp_arbitrary_header(csv_file,caller)
8149 character(len=*), intent(in) :: csv_file,caller
8150
8151 integer :: csv_unit,io_status
8152
8153 open(newunit=csv_unit,file=trim(csv_file),status='replace', &
8154 action='write',form='formatted',iostat=io_status)
8155 if (io_status/=0) then
8156 call mpistop(trim(caller)//' could not open CSV file')
8157 endif
8158
8159 write(csv_unit,'(a)',iostat=io_status) &
8160 'i,j,s1,s2,seed_x,seed_y,seed_z,'// &
8161 'qperp,logqperp,valid,status,'// &
8162 'N2,bfactor,'// &
8163 'face_forward,face_backward,'// &
8164 'status_forward,status_backward,'// &
8165 'length_forward,length_backward,'// &
8166 'Bseed_norm,Bf_norm,Bb_norm,'// &
8167 'x_f,y_f,z_f,x_b,y_b,z_b'
8168 if (io_status/=0) then
8169 close(csv_unit)
8170 call mpistop(trim(caller)//' could not write CSV header')
8171 endif
8172
8173 close(csv_unit)
8174 end subroutine mt_write_qperp_arbitrary_header
8175
8176 subroutine mt_write_qperp_arbitrary_csv(results,s1,s2,n1,n2,csv_file, &
8177 caller)
8178 integer, intent(in) :: n1,n2
8179 type(trace_qperp_result), intent(in) :: results(n1*n2)
8180 double precision, intent(in) :: s1(n1*n2),s2(n1*n2)
8181 character(len=*), intent(in) :: csv_file,caller
8182
8183 double precision :: bseed_norm,bf_norm,bb_norm
8184 integer :: csv_unit,io_status,i,j,iseed
8185
8186 open(newunit=csv_unit,file=trim(csv_file),status='replace', &
8187 action='write',form='formatted',iostat=io_status)
8188 if (io_status/=0) then
8189 call mpistop(trim(caller)//' could not open CSV file')
8190 endif
8191
8192 write(csv_unit,'(a)',iostat=io_status) &
8193 'i,j,s1,s2,seed_x,seed_y,seed_z,'// &
8194 'qperp,logqperp,valid,status,'// &
8195 'N2,bfactor,'// &
8196 'face_forward,face_backward,'// &
8197 'status_forward,status_backward,'// &
8198 'length_forward,length_backward,'// &
8199 'Bseed_norm,Bf_norm,Bb_norm,'// &
8200 'x_f,y_f,z_f,x_b,y_b,z_b'
8201 if (io_status/=0) then
8202 close(csv_unit)
8203 call mpistop(trim(caller)//' could not write CSV header')
8204 endif
8205
8206 do j=1,n2
8207 do i=1,n1
8208 iseed=(j-1)*n1+i
8209 bseed_norm=dsqrt(sum(results(iseed)%B_seed**2))
8210 bf_norm=dsqrt(sum(results(iseed)%forward_B**2))
8211 bb_norm=dsqrt(sum(results(iseed)%backward_B**2))
8212 write(csv_unit, &
8213 '(i0,",",i0,7(",",es24.16),",",l1,",",i0,'// &
8214 '2(",",es24.16),4(",",i0),11(",",es24.16))', &
8215 iostat=io_status) &
8216 i,j,s1(iseed),s2(iseed),results(iseed)%seed, &
8217 results(iseed)%qperp,results(iseed)%logqperp, &
8218 results(iseed)%valid,results(iseed)%status, &
8219 results(iseed)%N2,results(iseed)%bfactor, &
8220 results(iseed)%forward_face,results(iseed)%backward_face, &
8221 results(iseed)%forward_status,results(iseed)%backward_status, &
8222 results(iseed)%forward_length,results(iseed)%backward_length, &
8223 bseed_norm,bf_norm,bb_norm, &
8224 results(iseed)%forward_endpoint, &
8225 results(iseed)%backward_endpoint
8226 if (io_status/=0) then
8227 close(csv_unit)
8228 call mpistop(trim(caller)//' could not write CSV data')
8229 endif
8230 enddo
8231 enddo
8232
8233 close(csv_unit)
8234 end subroutine mt_write_qperp_arbitrary_csv
8235
8236 subroutine mt_write_mapping_plane_xy_csv(results,nx,ny,csv_file)
8237 integer, intent(in) :: nx,ny
8238 type(trace_mapping_result), intent(in) :: results(nx*ny)
8239 character(len=*), intent(in) :: csv_file
8240
8241 call mt_write_mapping_plane_csv(results,nx,ny,csv_file, &
8242 'mt_mapping_plane_xy','ix,iy')
8243 end subroutine mt_write_mapping_plane_xy_csv
8244
8245 subroutine mt_write_mapping_plane_csv(results,n1,n2,csv_file,caller, &
8246 index_header)
8247 integer, intent(in) :: n1,n2
8248 type(trace_mapping_result), intent(in) :: results(n1*n2)
8249 character(len=*), intent(in) :: csv_file,caller,index_header
8250
8251 integer :: csv_unit,io_status,i,j,iseed
8252
8253 open(newunit=csv_unit,file=trim(csv_file),status='replace', &
8254 action='write',form='formatted',iostat=io_status)
8255 if (io_status/=0) then
8256 call mpistop(trim(caller)//' could not open CSV file')
8257 endif
8258
8259 write(csv_unit,'(a)',iostat=io_status) &
8260 trim(index_header)//','// &
8261 'seed_x,seed_y,seed_z,'// &
8262 'source_Bx,source_By,source_Bz,source_Bn,'// &
8263 'backward_x,backward_y,backward_z,'// &
8264 'backward_Bx,backward_By,backward_Bz,backward_Bn,'// &
8265 'backward_face,backward_length,backward_status,'// &
8266 'forward_x,forward_y,forward_z,'// &
8267 'forward_Bx,forward_By,forward_Bz,forward_Bn,'// &
8268 'forward_face,forward_length,forward_status,valid'
8269 if (io_status/=0) then
8270 close(csv_unit)
8271 call mpistop(trim(caller)//' could not write CSV header')
8272 endif
8273
8274 do j=1,n2
8275 do i=1,n1
8276 iseed=(j-1)*n1+i
8277 write(csv_unit, &
8278 '(i0,",",i0,14(",",es24.16),",",i0,",",es24.16,'// &
8279 '",",i0,7(",",es24.16),",",i0,",",es24.16,'// &
8280 '",",i0,",",l1)',iostat=io_status) &
8281 i,j, &
8282 results(iseed)%seed, &
8283 results(iseed)%source_B,results(iseed)%source_Bn, &
8284 results(iseed)%backward_footpoint, &
8285 results(iseed)%backward_B,results(iseed)%backward_Bn, &
8286 results(iseed)%backward_face, &
8287 results(iseed)%backward_length, &
8288 results(iseed)%backward_status, &
8289 results(iseed)%forward_footpoint, &
8290 results(iseed)%forward_B,results(iseed)%forward_Bn, &
8291 results(iseed)%forward_face, &
8292 results(iseed)%forward_length, &
8293 results(iseed)%forward_status, &
8294 results(iseed)%valid
8295 if (io_status/=0) then
8296 close(csv_unit)
8297 call mpistop(trim(caller)//' could not write CSV data')
8298 endif
8299 enddo
8300 enddo
8301
8302 close(csv_unit)
8303 end subroutine mt_write_mapping_plane_csv
8304
8305 integer function mt_q_result_face_pair(qperp_result) result(face_pair)
8306 type(trace_qperp_result), intent(in) :: qperp_result
8307
8308 face_pair=0
8309 if (.not.qperp_result%valid_q0) return
8310 face_pair=mt_q_face_pair_from_faces(qperp_result%backward_face, &
8311 qperp_result%forward_face)
8312 end function mt_q_result_face_pair
8313
8314 integer function mt_q_result_connection_type(qperp_result) &
8315 result(connection_type)
8316 type(trace_qperp_result), intent(in) :: qperp_result
8317
8318 connection_type=0
8319 if (.not.qperp_result%valid_q0) return
8320 connection_type=mt_q_connection_type_from_faces( &
8321 qperp_result%backward_face,qperp_result%forward_face)
8322 end function mt_q_result_connection_type
8323
8324 integer function mt_q_face_pair_from_faces(face_b,face_f) result(face_pair)
8325 integer, intent(in) :: face_b,face_f
8326
8327 face_pair=0
8328 if (.not.mt_q_face_valid(face_b)) return
8329 if (.not.mt_q_face_valid(face_f)) return
8330 face_pair=10*face_b+face_f
8331 end function mt_q_face_pair_from_faces
8332
8333 integer function mt_q_connection_type_from_faces(face_b,face_f) &
8334 result(connection_type)
8335 integer, intent(in) :: face_b,face_f
8336
8337 connection_type=0
8338 if (.not.mt_q_face_valid(face_b)) return
8339 if (.not.mt_q_face_valid(face_f)) return
8340 if (face_b==trace_face_zmin .and. face_f==trace_face_zmin) then
8341 connection_type=1
8342 else if (face_b==trace_face_zmax .and. face_f==trace_face_zmax) then
8343 connection_type=2
8344 else if ((face_b==trace_face_zmin .and. face_f==trace_face_zmax) .or. &
8345 (face_b==trace_face_zmax .and. face_f==trace_face_zmin)) then
8346 connection_type=3
8347 else if (face_b==face_f) then
8348 connection_type=4
8349 else
8350 connection_type=5
8351 endif
8352 end function mt_q_connection_type_from_faces
8353
8354 logical function mt_q_face_valid(face)
8355 integer, intent(in) :: face
8356
8357 mt_q_face_valid=face>=trace_face_xmin .and. face<=trace_face_zmax
8358 end function mt_q_face_valid
8359
8360end module mod_magnetic_topology
subroutine, public mpistop(message)
Exit MPI-AMRVAC with an error message.
Module with geometry-related routines (e.g., divergence, curl)
Definition mod_geometry.t:2
integer coordinate
Definition mod_geometry.t:7
integer, parameter spherical
integer, parameter cartesian
Definition mod_geometry.t:8
integer, parameter cartesian_stretched
Definition mod_geometry.t:9
update ghost cells of all blocks including physical boundaries
subroutine getbc(time, qdt, psb, nwstart, nwbc)
do update ghost cells of all blocks including physical boundaries
This module contains definitions of global parameters and variables and some generic functions/subrou...
integer, parameter unitpar
file handle for IO
double precision global_time
The global simulation time.
integer, parameter ndim
Number of spatial dimensions for grid variables.
character(len=std_len), dimension(:), allocatable par_files
Which par files are used as input.
double precision, dimension(:), allocatable, parameter d
integer npe
The number of MPI tasks.
logical, dimension(ndim) periodb
True for dimensions with periodic boundaries.
logical slab_uniform
uniform Cartesian geometry or not (stretched Cartesian)
subroutine, public mt_write_cartesian_vti_pointdata(vti_file, xmin, xmax, nx, ymin, ymax, ny, zmin, zmax, nz, length_total, qperp, status)
subroutine, public mt_fieldline_products_plane_arbitrary(origin, e1, e2, s1min, s1max, n1, s2min, s2max, n2, dl, max_steps, csv_file, b_min, compute_length, compute_twist, compute_q, compute_qperp, vtu_file, write_csv)
subroutine, public mt_twist_plane_yz(ymin, ymax, ny, zmin, zmax, nz, x0, dl, max_steps, csv_file, b_min)
subroutine, public mt_topology_plane_xy(xmin, xmax, nx, ymin, ymax, ny, z0, dl, max_steps, length_csv, twist_csv, mapping_csv, b_min)
subroutine, public mt_qsl_plane_vtu_yz(ymin, ymax, ny, zmin, zmax, nz, x0, dl, max_steps, vtu_file, b_min)
subroutine, public mt_qperp_plane_xz(xmin, xmax, nx, zmin, zmax, nz, y0, dl, max_steps, csv_file, b_min)
subroutine, public mt_qsl_plane_vtu_xy(xmin, xmax, nx, ymin, ymax, ny, z0, dl, max_steps, vtu_file, b_min)
subroutine, public mt_twist_plane_xz(xmin, xmax, nx, zmin, zmax, nz, y0, dl, max_steps, csv_file, b_min)
subroutine, public mt_length_plane_xy(xmin, xmax, nx, ymin, ymax, ny, z0, dl, max_steps, csv_file, b_min)
subroutine, public mt_fieldline_products_seeds(seeds, nseed, dl, max_steps, csv_file, b_min, compute_length, compute_twist, compute_q, compute_qperp, vtu_file)
subroutine, public mt_length_seeds(seeds, nseed, dl, max_steps, csv_file, b_min)
subroutine, public mt_topology_plane_yz(ymin, ymax, ny, zmin, zmax, nz, x0, dl, max_steps, length_csv, twist_csv, mapping_csv, b_min)
subroutine, public mt_qperp_plane_yz(ymin, ymax, ny, zmin, zmax, nz, x0, dl, max_steps, csv_file, b_min)
subroutine, public mt_qperp_plane_arbitrary(origin, e1, e2, s1min, s1max, n1, s2min, s2max, n2, dl, max_steps, csv_file, b_min)
subroutine, public mt_qperp_plane_xy(xmin, xmax, nx, ymin, ymax, ny, z0, dl, max_steps, csv_file, b_min)
subroutine, public mt_length_plane_xz(xmin, xmax, nx, zmin, zmax, nz, y0, dl, max_steps, csv_file, b_min)
subroutine, public mt_length_single(seed, dl, max_steps, csv_file, b_min)
subroutine, public mt_fieldline_products_volume_vti(xmin, xmax, nx, ymin, ymax, ny, zmin, zmax, nz, dl, max_steps, vti_file, b_min, compute_length, compute_twist, compute_q, compute_qperp, chunk_nz)
subroutine, public mt_qsl_plane_vtu_xz(xmin, xmax, nx, zmin, zmax, nz, y0, dl, max_steps, vtu_file, b_min)
subroutine, public mt_twist_plane_xy(xmin, xmax, nx, ymin, ymax, ny, z0, dl, max_steps, csv_file, b_min)
subroutine, public mt_params_read(files)
subroutine, public mt_topology_plane_xz(xmin, xmax, nx, zmin, zmax, nz, y0, dl, max_steps, length_csv, twist_csv, mapping_csv, b_min)
subroutine, public mt_mapping_plane_xy(xmin, xmax, nx, ymin, ymax, ny, z0, dl, max_steps, csv_file, b_min)
subroutine, public mt_twist_seeds(seeds, nseed, dl, max_steps, csv_file, b_min)
subroutine, public mt_length_plane_yz(ymin, ymax, ny, zmin, zmax, nz, x0, dl, max_steps, csv_file, b_min)
subroutine, public mt_run_topology_task()
subroutine, public mt_twist_single(seed, dl, max_steps, csv_file, b_min)
integer, parameter, public trace_face_ymin
integer, parameter, public trace_face_zmax
subroutine, public trace_spherical_profile_set(enabled)
subroutine, public trace_rk45_stats_reset()
subroutine, public trace_field_twist_multi(seeds, nseed, dl, max_steps, results, b_min)
subroutine, public trace_field_rk2_short_boundary_q_multi(seeds, nseed, dl, max_steps, results, b_min, twist_results)
subroutine, public trace_cartesian_global_min_cell_size(hmin, status)
subroutine, public trace_spherical_curl_cache_clear()
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_field_mapping_single(seed, dl, max_steps, result, b_min, source_normal)
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)
integer, parameter, public trace_face_zmin
integer, parameter, public trace_status_unsupported_geometry
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, public trace_rk2_stats_reset()
subroutine, public trace_spherical_curl_cache_build(status)
subroutine, public trace_spherical_profile_count_seeds(nseed)
subroutine, public trace_spherical_profile_reset()
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, public trace_field_length_single(seed, dl, max_steps, result, b_min)
integer, parameter, public trace_face_xmin
subroutine, public trace_field_mapping_multi(seeds, nseed, dl, max_steps, results, b_min, source_normal)
integer, parameter, public trace_status_active