14 integer,
parameter :: mh_name_len=256
15 integer,
parameter :: mh_nstate=24
16 integer,
parameter :: mh_state_tag=28431
17 integer,
parameter :: mh_debug_tag=28432
18 integer,
parameter :: mh_debug_nvalue=12
19 integer,
parameter :: mh_debug_narray=6
22 integer,
parameter :: mh_q1_b=1,mh_q2_b=4
23 integer,
parameter :: mh_q1_bp=7,mh_q2_bp=10
24 integer,
parameter :: mh_b1=13,mh_b2=16,mh_bp1=19,mh_btop=22
27 integer :: gauge_axis=3
28 double precision :: ratio_tolerance=1.d-12
29 logical :: write_debug_vti=.false.
30 logical :: write_mg_timing=.false.
31 character(len=mh_name_len) :: debug_vti_file=
''
36 double precision :: hm=0.d0,hj=0.d0,hpj=0.d0
37 double precision :: abs_hj_over_abs_hm=0.d0
38 double precision :: energy=0.d0,potential_energy=0.d0,free_energy=0.d0
39 double precision :: hm_physical=0.d0,hj_physical=0.d0
40 double precision :: hpj_physical=0.d0
41 double precision :: energy_physical=0.d0
42 double precision :: potential_energy_physical=0.d0
43 double precision :: free_energy_physical=0.d0
44 double precision :: helicity_unit=1.d0,energy_unit=1.d0
45 double precision :: curl_a_error=0.d0,curl_ap_error=0.d0
46 double precision :: decomposition_error=0.d0
47 double precision :: epsilon_div_b=0.d0
48 double precision :: net_flux_imbalance=0.d0
49 double precision :: boundary_normal_error=0.d0
50 double precision :: mg_residual=0.d0
51 integer :: mg_cycles=0
52 logical :: ratio_is_valid=.false.
55 type,
private :: mh_debug_vti_state
56 logical :: enabled=.false.
59 integer(kind=8) :: data_pos=0_8
60 integer(kind=8) :: offsets(mh_debug_narray)=0_8
61 integer(kind=8) :: nbytes(mh_debug_narray)=0_8
62 end type mh_debug_vti_state
80 character(len=*),
intent(in) :: files(:)
97 open(
unitpar,file=trim(files(n)),status=
'old')
98 read(
unitpar,magnetic_helicity_list,
end=111)
111 'magnetic-helicity conversion requires convert=.true.')
113 'magnetic-helicity conversion requires level_io > 0')
127 subroutine mh_write_result_csv(result)
132 character(len=mh_name_len) :: filename
133 character(len=5) :: helicity_label
134 character(len=3) :: energy_label
135 character(len=5) :: ratio_label
137 integer :: csv_unit,io_status
138 integer(kind=8) :: file_size
153 ratio_label=merge(
'true ',
'false',result%ratio_is_valid)
156 inquire(file=trim(filename),exist=exists)
157 if(exists)
inquire(file=trim(filename),size=file_size)
158 open(newunit=csv_unit,file=trim(filename),status=
'unknown',&
159 action=
'write',position=
'append',iostat=io_status)
160 if(io_status/=0)
call mpistop(
'could not open magnetic-helicity CSV')
161 if(.not.exists .or. file_size==0)
then
162 write(csv_unit,
'(a)')
'snapshot,code_time,physical_time_s,'//&
163 'Hm_code,HJ_code,HPJ_code,abs_HJ_over_abs_Hm,'//&
164 'Hm_'//trim(helicity_label)//
',HJ_'//trim(helicity_label)//&
165 ',HPJ_'//trim(helicity_label)//
',E_code,Ep_code,Efree_code,'//&
166 'E_'//trim(energy_label)//
',Ep_'//trim(energy_label)//&
167 ',Efree_'//trim(energy_label)//
',net_flux_imbalance,'//&
168 'epsilon_div_B,boundary_normal_error,curl_A_error,'//&
169 'curl_Ap_error,decomposition_error,mg_residual,mg_cycles,'//&
176 call mh_csv_real(csv_unit,result%Hm)
177 call mh_csv_real(csv_unit,result%HJ)
178 call mh_csv_real(csv_unit,result%HPJ)
179 if(result%ratio_is_valid)
then
180 call mh_csv_real(csv_unit,result%abs_HJ_over_abs_Hm)
182 write(csv_unit,
'(",")',advance=
'no')
184 call mh_csv_real(csv_unit,result%Hm_physical)
185 call mh_csv_real(csv_unit,result%HJ_physical)
186 call mh_csv_real(csv_unit,result%HPJ_physical)
187 call mh_csv_real(csv_unit,result%energy)
188 call mh_csv_real(csv_unit,result%potential_energy)
189 call mh_csv_real(csv_unit,result%free_energy)
190 call mh_csv_real(csv_unit,result%energy_physical)
191 call mh_csv_real(csv_unit,result%potential_energy_physical)
192 call mh_csv_real(csv_unit,result%free_energy_physical)
193 call mh_csv_real(csv_unit,result%net_flux_imbalance)
194 call mh_csv_real(csv_unit,result%epsilon_div_B)
195 call mh_csv_real(csv_unit,result%boundary_normal_error)
196 call mh_csv_real(csv_unit,result%curl_A_error)
197 call mh_csv_real(csv_unit,result%curl_Ap_error)
198 call mh_csv_real(csv_unit,result%decomposition_error)
199 call mh_csv_real(csv_unit,result%mg_residual)
200 write(csv_unit,
'(",",i0,",",a)') result%mg_cycles,trim(ratio_label)
202 end subroutine mh_write_result_csv
204 subroutine mh_csv_real(csv_unit,value)
205 integer,
intent(in) :: csv_unit
206 double precision,
intent(in) :: value
207 write(csv_unit,
'(",",es24.16)',advance=
'no')
value
208 end subroutine mh_csv_real
218 if(
ndim/=3)
call mpistop(
'finite-volume magnetic helicity requires three dimensions')
220 call mpistop(
'finite-volume magnetic helicity requires Cartesian coordinates')
222 call mpistop(
'finite-volume magnetic helicity requires an unstretched mesh')
223 if(config%gauge_axis<1 .or. config%gauge_axis>3) &
224 call mpistop(
'mh_gauge_axis must be 1, 2, or 3')
225 if(config%ratio_tolerance<=0.d0) &
226 call mpistop(
'magnetic-helicity ratio tolerance must be positive')
229 call mh_compute_3d(config,result)
234 subroutine mh_compute_3d(config,result)
240 type(magnetic_reference_result) :: ref_result
241 type(magnetic_reference_field) :: bp
242 type(mh_debug_vti_state) :: debug_vti
243 double precision,
allocatable :: send_b(:,:,:),recv_b(:,:,:)
244 double precision,
allocatable :: send_bp(:,:,:),recv_bp(:,:,:)
245 double precision,
allocatable :: avec(:,:,:),apvec(:,:,:)
246 double precision,
allocatable :: q_b(:,:,:),q_bp(:,:,:)
247 double precision,
allocatable :: bdiff(:,:,:)
248 double precision,
allocatable :: plane_state(:,:,:)
249 double precision,
allocatable :: debug_plane(:,:)
250 double precision,
allocatable :: face_send(:,:),face_recv(:,:)
251 integer,
allocatable :: count_send(:,:),count_recv(:,:)
252 integer,
allocatable :: face_count_send(:,:),face_count_recv(:,:)
253 double precision :: local_values(11),global_values(11)
254 double precision :: cell_dx(3),du,dv,da,dvolume,denom
255 integer :: nxyz(3),axis,uaxis,vaxis,orientation
256 integer :: nu,nv,na,k,owner,previous_owner,next_owner
257 integer :: request,status(mpi_status_size),state_count
259 call mh_uniform_grid(config%gauge_axis,nxyz,cell_dx,uaxis,vaxis,&
261 axis=config%gauge_axis
268 dvolume=cell_dx(1)*cell_dx(2)*cell_dx(3)
269 if(min(nu,nv,na)<3) &
270 call mpistop(
'magnetic helicity requires at least three cells per direction')
272 call mh_debug_vti_begin(debug_vti,config,nxyz,cell_dx)
274 call solve_magnetic_reference_fv(config%reference,bp,ref_result)
276 allocate(send_b(nu,nv,3),recv_b(nu,nv,3))
277 allocate(send_bp(nu,nv,3),recv_bp(nu,nv,3))
278 allocate(avec(nu,nv,3),apvec(nu,nv,3))
279 allocate(q_b(nu,nv,3),q_bp(nu,nv,3))
280 allocate(bdiff(nu,nv,3))
281 allocate(plane_state(nu,nv,mh_nstate))
282 allocate(face_send(nu,nv),face_recv(nu,nv))
283 allocate(count_send(nu,nv),count_recv(nu,nv))
284 allocate(face_count_send(nu,nv),face_count_recv(nu,nv))
285 if(debug_vti%enabled)
allocate(debug_plane(mh_debug_nvalue,nu*nv))
289 state_count=nu*nv*mh_nstate
291 owner=mh_plane_owner(k)
292 request=mpi_request_null
293 if(k<na .and.
mype==owner)
then
294 previous_owner=mh_plane_owner(k+1)
295 if(previous_owner/=owner)
call mpi_irecv(plane_state,state_count,&
296 mpi_double_precision,previous_owner,mh_state_tag,
icomm,request,&
300 call mh_assemble_plane(axis,uaxis,vaxis,k,nxyz,cell_dx,bp,send_b,&
301 send_bp,count_send,face_send,face_count_send)
302 call mpi_reduce(send_b,recv_b,nu*nv*3,mpi_double_precision,&
304 call mpi_reduce(send_bp,recv_bp,nu*nv*3,mpi_double_precision,&
306 call mpi_reduce(count_send,count_recv,nu*nv,mpi_integer,&
309 call mpi_reduce(face_send,face_recv,nu*nv,mpi_double_precision,&
311 call mpi_reduce(face_count_send,face_count_recv,nu*nv,mpi_integer,&
316 if(request/=mpi_request_null)
call mpi_wait(request,status,
ierrmpi)
317 if(any(count_recv/=1)) &
318 call mpistop(
'magnetic-helicity plane assembly is not one-to-one')
320 if(any(face_count_recv/=1))
call mpistop(&
321 'magnetic-helicity top boundary assembly is not one-to-one')
323 call mh_build_top_b(face_recv,du,dv,uaxis,vaxis,axis,&
324 orientation,plane_state(:,:,mh_btop:mh_btop+2))
326 q_bp=0.5d0*da*recv_bp
327 else if(k==na-1)
then
329 q_b=plane_state(:,:,mh_q1_b:mh_q1_b+2)+0.5d0*da*(&
330 plane_state(:,:,mh_b1:mh_b1+2)+recv_b)
331 q_bp=plane_state(:,:,mh_q1_bp:mh_q1_bp+2)+0.5d0*da*(&
332 plane_state(:,:,mh_bp1:mh_bp1+2)+recv_bp)
336 q_b=plane_state(:,:,mh_q2_b:mh_q2_b+2)+2.d0*da*&
337 plane_state(:,:,mh_b1:mh_b1+2)
338 q_bp=plane_state(:,:,mh_q2_bp:mh_q2_bp+2)+2.d0*da*&
339 plane_state(:,:,mh_bp1:mh_bp1+2)
342 call mh_make_vector_potential(&
343 plane_state(:,:,mh_btop:mh_btop+2),q_b,uaxis,&
344 vaxis,axis,orientation,avec)
345 call mh_make_vector_potential(&
346 plane_state(:,:,mh_btop:mh_btop+2),q_bp,uaxis,&
347 vaxis,axis,orientation,apvec)
348 if(k<=na-2)
call mh_plane_quality(plane_state,q_b,q_bp,recv_b,&
349 uaxis,vaxis,axis,orientation,du,dv,da,dvolume,local_values)
350 call mh_plane_integrals(avec,apvec,recv_b,recv_bp,bdiff,&
351 dvolume,local_values)
352 if(debug_vti%enabled)
call mh_debug_pack_plane(recv_bp,avec,apvec,&
355 plane_state(:,:,mh_q2_b:mh_q2_b+2)=&
356 plane_state(:,:,mh_q1_b:mh_q1_b+2)
357 plane_state(:,:,mh_q1_b:mh_q1_b+2)=q_b
358 plane_state(:,:,mh_q2_bp:mh_q2_bp+2)=&
359 plane_state(:,:,mh_q1_bp:mh_q1_bp+2)
360 plane_state(:,:,mh_q1_bp:mh_q1_bp+2)=q_bp
361 plane_state(:,:,mh_b2:mh_b2+2)=plane_state(:,:,mh_b1:mh_b1+2)
362 plane_state(:,:,mh_b1:mh_b1+2)=recv_b
363 plane_state(:,:,mh_bp1:mh_bp1+2)=recv_bp
366 if(debug_vti%enabled)
call mh_debug_vti_write_plane(debug_vti,owner,&
367 k,uaxis,vaxis,axis,debug_plane)
368 if(
mype==owner .and. k>1)
then
369 next_owner=mh_plane_owner(k-1)
370 if(next_owner/=owner)
call mpi_send(plane_state,state_count,&
371 mpi_double_precision,next_owner,mh_state_tag,
icomm,
ierrmpi)
374 call mh_debug_vti_end(debug_vti)
376 call mpi_allreduce(local_values,global_values,
size(local_values),&
378 result%Hm=global_values(1)
379 result%HJ=global_values(2)
380 result%HPJ=global_values(3)
381 result%energy=global_values(4)
382 result%potential_energy=ref_result%magnetic_energy
383 result%free_energy=result%energy-result%potential_energy
384 result%curl_A_error=dsqrt(global_values(6)/&
385 max(global_values(7),tiny(1.d0)))
386 result%curl_Ap_error=dsqrt(global_values(8)/&
387 max(global_values(9),tiny(1.d0)))
388 result%epsilon_div_B=dsqrt(global_values(10)/&
389 max(global_values(11),tiny(1.d0)))
390 denom=max(abs(result%Hm),abs(result%HJ)+abs(result%HPJ),tiny(1.d0))
391 result%decomposition_error=abs(result%Hm-result%HJ-result%HPJ)/denom
392 result%ratio_is_valid=abs(result%Hm)>&
393 config%ratio_tolerance*max(global_values(5),tiny(1.d0))
394 if(result%ratio_is_valid) &
395 result%abs_HJ_over_abs_Hm=abs(result%HJ)/abs(result%Hm)
397 result%net_flux_imbalance=ref_result%flux_imbalance
398 result%boundary_normal_error=ref_result%boundary_normal_error
399 result%mg_residual=ref_result%residual
400 result%mg_cycles=ref_result%cycles
403 result%Hm_physical=result%Hm*result%helicity_unit
404 result%HJ_physical=result%HJ*result%helicity_unit
405 result%HPJ_physical=result%HPJ*result%helicity_unit
406 result%energy_physical=result%energy*result%energy_unit
407 result%potential_energy_physical=result%potential_energy*result%energy_unit
408 result%free_energy_physical=result%free_energy*result%energy_unit
410 call free_magnetic_reference_field(bp)
411 deallocate(send_b,recv_b,send_bp,recv_bp,avec,apvec,q_b,q_bp,&
413 deallocate(face_send,face_recv,count_send,count_recv)
414 deallocate(face_count_send,face_count_recv)
415 if(
allocated(debug_plane))
deallocate(debug_plane)
416 end subroutine mh_compute_3d
418 integer function mh_plane_owner(k)
420 integer,
intent(in) :: k
421 mh_plane_owner=mod(k-1,
npe)
422 end function mh_plane_owner
424 subroutine mh_uniform_grid(axis,nxyz,cell_dx,uaxis,vaxis,orientation)
427 integer,
intent(in) :: axis
428 integer,
intent(out) :: nxyz(3),uaxis,vaxis,orientation
429 double precision,
intent(out) :: cell_dx(3)
430 integer :: iigrid,igrid,local_min,local_max,grid_min,grid_max
431 double precision :: local_error,global_error
435 do iigrid=1,igridstail
440 call mpi_allreduce(local_min,grid_min,1,mpi_integer,mpi_min,
icomm,
ierrmpi)
441 call mpi_allreduce(local_max,grid_max,1,mpi_integer,mpi_max,
icomm,
ierrmpi)
442 if(grid_min/=grid_max)
call mpistop(&
443 'magnetic helicity requires one uniform AMR level; set level_io')
444 nxyz=(/domain_nx1,domain_nx2,domain_nx3/)*2**(grid_min-1)
445 cell_dx(1)=(xprobmax1-xprobmin1)/dble(nxyz(1))
446 cell_dx(2)=(xprobmax2-xprobmin2)/dble(nxyz(2))
447 cell_dx(3)=(xprobmax3-xprobmin3)/dble(nxyz(3))
449 do iigrid=1,igridstail
451 local_error=max(local_error,abs(
rnode(rpdx1_,igrid)-cell_dx(1))/&
453 local_error=max(local_error,abs(
rnode(rpdx2_,igrid)-cell_dx(2))/&
455 local_error=max(local_error,abs(
rnode(rpdx3_,igrid)-cell_dx(3))/&
458 call mpi_allreduce(local_error,global_error,1,mpi_double_precision,&
460 if(global_error>1.
d-12)
call mpistop(&
461 'magnetic helicity requires a uniform Cartesian cell size')
465 uaxis=2; vaxis=3; orientation=1
467 uaxis=1; vaxis=3; orientation=-1
469 uaxis=1; vaxis=2; orientation=1
471 end subroutine mh_uniform_grid
473 subroutine mh_assemble_plane(axis,uaxis,vaxis,kplane,nxyz,cell_dx,bp,&
474 bsend,bpsend,counts,face_send,face_counts)
476 integer,
intent(in) :: axis,uaxis,vaxis,kplane,nxyz(3)
477 double precision,
intent(in) :: cell_dx(3)
478 type(magnetic_reference_field),
intent(in) :: bp
479 double precision,
intent(out) :: bsend(:,:,:),bpsend(:,:,:)
480 integer,
intent(out) :: counts(:,:)
481 double precision,
intent(out) :: face_send(:,:)
482 integer,
intent(out) :: face_counts(:,:)
483 integer :: iigrid,igrid,i,j,
l,idir,ig,jg,lg,iloc,jloc,lloc
484 integer :: start(3),block_extent(3),gu,gv
491 do iigrid=1,igridstail
493 start(1)=nint((ps(igrid)%x(ixmlo1,ixmlo2,ixmlo3,1)-&
494 xprobmin1)/cell_dx(1)+0.5d0)
495 start(2)=nint((ps(igrid)%x(ixmlo1,ixmlo2,ixmlo3,2)-&
496 xprobmin2)/cell_dx(2)+0.5d0)
497 start(3)=nint((ps(igrid)%x(ixmlo1,ixmlo2,ixmlo3,3)-&
498 xprobmin3)/cell_dx(3)+0.5d0)
499 block_extent=(/ixmhi1-ixmlo1,ixmhi2-ixmlo2,ixmhi3-ixmlo3/)
500 if(kplane<start(axis) .or. &
501 kplane>start(axis)+block_extent(axis)) cycle
504 iloc=ixmlo1+kplane-start(1)
505 do l=ixmlo3,ixmhi3; lg=start(3)+
l-ixmlo3
506 do j=ixmlo2,ixmhi2; jg=start(2)+j-ixmlo2
509 bsend(gu,gv,idir)=mh_total_b(igrid,iloc,j,
l,idir)
510 bpsend(gu,gv,idir)=bp%blocks(igrid)%b(iloc,j,
l,idir)
513 if(kplane==nxyz(axis) .and.&
514 ps(igrid)%is_physical_boundary(2*axis))
then
515 face_send(gu,gv)=mh_boundary_normal(igrid,iloc,j,
l,axis)
521 jloc=ixmlo2+kplane-start(2)
522 do l=ixmlo3,ixmhi3; lg=start(3)+
l-ixmlo3
523 do i=ixmlo1,ixmhi1; ig=start(1)+i-ixmlo1
526 bsend(gu,gv,idir)=mh_total_b(igrid,i,jloc,
l,idir)
527 bpsend(gu,gv,idir)=bp%blocks(igrid)%b(i,jloc,
l,idir)
530 if(kplane==nxyz(axis) .and.&
531 ps(igrid)%is_physical_boundary(2*axis))
then
532 face_send(gu,gv)=mh_boundary_normal(igrid,i,jloc,
l,axis)
538 lloc=ixmlo3+kplane-start(3)
539 do j=ixmlo2,ixmhi2; jg=start(2)+j-ixmlo2
540 do i=ixmlo1,ixmhi1; ig=start(1)+i-ixmlo1
543 bsend(gu,gv,idir)=mh_total_b(igrid,i,j,lloc,idir)
544 bpsend(gu,gv,idir)=bp%blocks(igrid)%b(i,j,lloc,idir)
547 if(kplane==nxyz(axis) .and.&
548 ps(igrid)%is_physical_boundary(2*axis))
then
549 face_send(gu,gv)=mh_boundary_normal(igrid,i,j,lloc,axis)
556 end subroutine mh_assemble_plane
558 double precision function mh_total_b(igrid,i,j,k,idir)
560 integer,
intent(in) :: igrid,i,j,k,idir
561 mh_total_b=ps(igrid)%w(i,j,k,iw_mag(idir))
562 if(
b0field) mh_total_b=mh_total_b+ps(igrid)%B0(i,j,k,idir,0)
563 end function mh_total_b
565 double precision function mh_boundary_normal(igrid,i,j,k,axis)
567 integer,
intent(in) :: igrid,i,j,k,axis
571 mh_boundary_normal=ps(igrid)%ws(i,j,k,axis)
572 if(
b0field) mh_boundary_normal=mh_boundary_normal+&
573 ps(igrid)%B0(i,j,k,axis,axis)
581 mh_boundary_normal=0.5d0*(ps(igrid)%w(i,j,k,iw_mag(axis))+&
582 ps(igrid)%w(ip,jp,kp,iw_mag(axis)))
583 if(
b0field) mh_boundary_normal=mh_boundary_normal+0.5d0*(&
584 ps(igrid)%B0(i,j,k,axis,0)+ps(igrid)%B0(ip,jp,kp,axis,0))
586 end function mh_boundary_normal
588 subroutine mh_build_top_b(bnormal,du,dv,uaxis,vaxis,axis,&
590 double precision,
intent(in) :: bnormal(:,:),du,dv
591 integer,
intent(in) :: uaxis,vaxis,axis,orientation
592 double precision,
intent(out) :: btop(:,:,:)
595 nu=
size(bnormal,1); nv=
size(bnormal,2)
601 btop(2,j,vaxis)=0.25d0*dble(orientation)*du*&
602 (bnormal(1,j)+bnormal(2,j))
604 btop(i,j,vaxis)=btop(i-2,j,vaxis)+&
605 dble(orientation)*du*bnormal(i-1,j)
611 btop(i,2,uaxis)=-0.25d0*dble(orientation)*dv*&
612 (bnormal(i,1)+bnormal(i,2))
614 btop(i,j,uaxis)=btop(i,j-2,uaxis)-&
615 dble(orientation)*dv*bnormal(i,j-1)
620 end subroutine mh_build_top_b
622 subroutine mh_make_vector_potential(btop,q,uaxis,vaxis,axis,&
624 double precision,
intent(in) :: btop(:,:,:),q(:,:,:)
625 integer,
intent(in) :: uaxis,vaxis,axis,orientation
626 double precision,
intent(out) :: avec(:,:,:)
629 avec(:,:,uaxis)=avec(:,:,uaxis)-dble(orientation)*q(:,:,vaxis)
630 avec(:,:,vaxis)=avec(:,:,vaxis)+dble(orientation)*q(:,:,uaxis)
632 end subroutine mh_make_vector_potential
634 subroutine mh_plane_integrals(avec,apvec,b,bp,bdiff,dvolume,values)
635 double precision,
intent(in) :: avec(:,:,:),apvec(:,:,:)
636 double precision,
intent(in) :: b(:,:,:),bp(:,:,:),dvolume
637 double precision,
intent(out) :: bdiff(:,:,:)
638 double precision,
intent(inout) :: values(11)
641 values(1)=values(1)+sum((avec+apvec)*bdiff)*dvolume
642 values(2)=values(2)+sum((avec-apvec)*bdiff)*dvolume
643 values(3)=values(3)+2.d0*sum(apvec*bdiff)*dvolume
644 values(4)=values(4)+0.5d0*sum(b**2)*dvolume
648 values(5)=values(5)+sum((dsqrt(sum(avec**2,dim=3))+&
649 dsqrt(sum(apvec**2,dim=3)))*(dsqrt(sum(b**2,dim=3))+&
650 dsqrt(sum(bp**2,dim=3))))*dvolume
651 end subroutine mh_plane_integrals
653 subroutine mh_plane_quality(state,qcur,qcurp,bcur,uaxis,vaxis,axis,&
654 orientation,du,dv,da,dvolume,values)
655 double precision,
intent(in) :: state(:,:,:),qcur(:,:,:),qcurp(:,:,:)
656 double precision,
intent(in) :: bcur(:,:,:),du,dv,da,dvolume
657 integer,
intent(in) :: uaxis,vaxis,axis,orientation
658 double precision,
intent(inout) :: values(11)
659 double precision :: curl_a(3),curl_ap(3),btarget(3),bptarget(3),divb
660 double precision :: s,du_av,dv_au,du_apv,dv_apu
664 do j=2,
size(state,2)-1
665 do i=2,
size(state,1)-1
668 curl_a(uaxis)=-(state(i,j,mh_q2_b-1+uaxis)-&
669 qcur(i,j,uaxis))/(2.d0*da)
670 curl_a(vaxis)=-(state(i,j,mh_q2_b-1+vaxis)-&
671 qcur(i,j,vaxis))/(2.d0*da)
672 curl_ap(uaxis)=-(state(i,j,mh_q2_bp-1+uaxis)-&
673 qcurp(i,j,uaxis))/(2.d0*da)
674 curl_ap(vaxis)=-(state(i,j,mh_q2_bp-1+vaxis)-&
675 qcurp(i,j,vaxis))/(2.d0*da)
676 du_av=(state(i+1,j,mh_btop-1+vaxis)+&
677 s*state(i+1,j,mh_q1_b-1+uaxis)-&
678 state(i-1,j,mh_btop-1+vaxis)-&
679 s*state(i-1,j,mh_q1_b-1+uaxis))/(2.d0*du)
680 dv_au=(state(i,j+1,mh_btop-1+uaxis)-&
681 s*state(i,j+1,mh_q1_b-1+vaxis)-&
682 state(i,j-1,mh_btop-1+uaxis)+&
683 s*state(i,j-1,mh_q1_b-1+vaxis))/(2.d0*dv)
684 du_apv=(state(i+1,j,mh_btop-1+vaxis)+&
685 s*state(i+1,j,mh_q1_bp-1+uaxis)-&
686 state(i-1,j,mh_btop-1+vaxis)-&
687 s*state(i-1,j,mh_q1_bp-1+uaxis))/(2.d0*du)
688 dv_apu=(state(i,j+1,mh_btop-1+uaxis)-&
689 s*state(i,j+1,mh_q1_bp-1+vaxis)-&
690 state(i,j-1,mh_btop-1+uaxis)+&
691 s*state(i,j-1,mh_q1_bp-1+vaxis))/(2.d0*dv)
692 curl_a(axis)=s*(du_av-dv_au)
693 curl_ap(axis)=s*(du_apv-dv_apu)
694 btarget=state(i,j,mh_b1:mh_b1+2)
695 bptarget=state(i,j,mh_bp1:mh_bp1+2)
696 values(6)=values(6)+sum((curl_a-btarget)**2)*dvolume
697 values(7)=values(7)+sum(btarget**2)*dvolume
698 values(8)=values(8)+sum((curl_ap-bptarget)**2)*dvolume
699 values(9)=values(9)+sum(bptarget**2)*dvolume
700 divb=(state(i+1,j,mh_b1-1+uaxis)-&
701 state(i-1,j,mh_b1-1+uaxis))/(2.d0*du)+&
702 (state(i,j+1,mh_b1-1+vaxis)-&
703 state(i,j-1,mh_b1-1+vaxis))/(2.d0*dv)+&
704 (state(i,j,mh_b2-1+axis)-bcur(i,j,axis))/(2.d0*da)
705 values(10)=values(10)+divb**2*dvolume
706 values(11)=values(11)+sum(btarget**2)*dvolume
709 end subroutine mh_plane_quality
711 subroutine mh_debug_pack_plane(bp,avec,apvec,bdiff,packed)
712 double precision,
intent(in) :: bp(:,:,:),avec(:,:,:),apvec(:,:,:)
713 double precision,
intent(in) :: bdiff(:,:,:)
714 double precision,
intent(out) :: packed(:,:)
721 packed(1:3,ip)=bp(i,j,1:3)
722 packed(4:6,ip)=avec(i,j,1:3)
723 packed(7:9,ip)=apvec(i,j,1:3)
724 packed(10,ip)=sum((avec(i,j,1:3)+apvec(i,j,1:3))*&
726 packed(11,ip)=sum((avec(i,j,1:3)-apvec(i,j,1:3))*&
728 packed(12,ip)=2.d0*sum(apvec(i,j,1:3)*bdiff(i,j,1:3))
731 end subroutine mh_debug_pack_plane
733 subroutine mh_debug_vti_begin(writer,config,nxyz,cell_dx)
737 type(mh_debug_vti_state),
intent(out) :: writer
739 integer,
intent(in) :: nxyz(3)
740 double precision,
intent(in) :: cell_dx(3)
741 character(len=mh_name_len) :: filename
742 character(len=1024) :: line
743 character(len=12) :: byte_order
744 integer :: io_status,i
745 integer(kind=8) :: ncell
747 writer=mh_debug_vti_state()
748 writer%enabled=config%write_debug_vti
750 if(.not.writer%enabled)
return
751 if(len_trim(config%debug_vti_file)>0)
then
752 filename=trim(config%debug_vti_file)
754 write(filename,
'(a,"_helicity_debug",i4.4,".vti")') &
758 ncell=int(nxyz(1),8)*int(nxyz(2),8)*int(nxyz(3),8)
759 writer%nbytes(1:3)=3_8*ncell*8_8
760 writer%nbytes(4:6)=ncell*8_8
761 writer%offsets(1)=0_8
762 do i=2,mh_debug_narray
763 writer%offsets(i)=writer%offsets(i-1)+8_8+writer%nbytes(i-1)
767 byte_order=merge(
'LittleEndian',
'BigEndian ',
type_endian==1)
768 open(newunit=writer%unit,file=trim(filename),status=
'replace',&
769 action=
'write',access=
'stream',form=
'unformatted',iostat=io_status)
770 if(io_status/=0)
call mpistop(
'could not open magnetic-helicity debug VTI')
771 call mh_stream_line(writer%unit,
'<?xml version="1.0"?>')
772 call mh_stream_line(writer%unit,
'<VTKFile type="ImageData" version="1.0" '//&
773 'byte_order="'//trim(byte_order)//
'" header_type="UInt64">')
774 write(line,
'(a,6(i0,1x),a,3(es24.16,1x),a,3(es24.16,1x),a)') &
775 ' <ImageData WholeExtent="',0,nxyz(1),0,nxyz(2),0,nxyz(3),&
776 '" Origin="',xprobmin1,xprobmin2,xprobmin3,
'" Spacing="',&
778 call mh_stream_line(writer%unit,trim(line))
779 write(line,
'(a,6(i0,1x),a)')
' <Piece Extent="',0,nxyz(1),&
780 0,nxyz(2),0,nxyz(3),
'">'
781 call mh_stream_line(writer%unit,trim(line))
782 call mh_stream_line(writer%unit,
' <CellData>')
783 call mh_debug_vti_array_line(writer%unit,
'Bp',3,writer%offsets(1))
784 call mh_debug_vti_array_line(writer%unit,
'A',3,writer%offsets(2))
785 call mh_debug_vti_array_line(writer%unit,
'Ap',3,writer%offsets(3))
786 call mh_debug_vti_array_line(writer%unit,
'h_m',1,writer%offsets(4))
787 call mh_debug_vti_array_line(writer%unit,
'h_J',1,writer%offsets(5))
788 call mh_debug_vti_array_line(writer%unit,
'h_PJ',1,writer%offsets(6))
789 call mh_stream_line(writer%unit,
' </CellData>')
790 call mh_stream_line(writer%unit,
' </Piece>')
791 call mh_stream_line(writer%unit,
' </ImageData>')
792 write(writer%unit)
'<AppendedData encoding="raw">_'
793 inquire(unit=writer%unit,pos=writer%data_pos)
794 do i=1,mh_debug_narray
795 write(writer%unit,pos=writer%data_pos+writer%offsets(i),&
796 iostat=io_status) writer%nbytes(i)
797 if(io_status/=0)
call mpistop(
'could not initialize debug VTI payload')
799 end subroutine mh_debug_vti_begin
801 subroutine mh_debug_vti_array_line(vti_unit,name,ncomponent,offset)
802 integer,
intent(in) :: vti_unit,ncomponent
803 character(len=*),
intent(in) :: name
804 integer(kind=8),
intent(in) :: offset
805 character(len=512) :: line
807 write(line,
'(a,a,a,i0,a,i0,a)') &
808 ' <DataArray type="Float64" Name="',trim(name),&
809 '" NumberOfComponents="',ncomponent,&
810 '" format="appended" offset="',offset,
'"/>'
811 call mh_stream_line(vti_unit,trim(line))
812 end subroutine mh_debug_vti_array_line
814 subroutine mh_stream_line(vti_unit,line)
815 integer,
intent(in) :: vti_unit
816 character(len=*),
intent(in) :: line
817 write(vti_unit) trim(line)//new_line(
'a')
818 end subroutine mh_stream_line
820 subroutine mh_debug_vti_write_plane(writer,owner,kplane,uaxis,vaxis,&
824 type(mh_debug_vti_state),
intent(inout) :: writer
825 integer,
intent(in) :: owner,kplane,uaxis,vaxis,axis
826 double precision,
intent(inout) :: packed(:,:)
827 integer :: status(mpi_status_size),i,j,ip,ixyz(3),io_status
828 integer(kind=8) :: global_index,position
830 if(.not.writer%enabled)
return
832 if(
mype==owner)
call mpi_send(packed,
size(packed),&
834 if(
mype==0)
call mpi_recv(packed,
size(packed),mpi_double_precision,&
840 do j=1,writer%nxyz(vaxis)
841 do i=1,writer%nxyz(uaxis)
847 global_index=int(ixyz(1),8)+int(writer%nxyz(1),8)*(&
848 int(ixyz(2)-1,8)+int(writer%nxyz(2),8)*int(ixyz(3)-1,8))
849 position=writer%data_pos+writer%offsets(1)+8_8+&
850 (global_index-1_8)*24_8
851 write(writer%unit,pos=position,iostat=io_status) packed(1:3,ip)
852 if(io_status/=0)
call mpistop(
'could not write Bp debug VTI payload')
853 position=writer%data_pos+writer%offsets(2)+8_8+&
854 (global_index-1_8)*24_8
855 write(writer%unit,pos=position,iostat=io_status) packed(4:6,ip)
856 if(io_status/=0)
call mpistop(
'could not write A debug VTI payload')
857 position=writer%data_pos+writer%offsets(3)+8_8+&
858 (global_index-1_8)*24_8
859 write(writer%unit,pos=position,iostat=io_status) packed(7:9,ip)
860 if(io_status/=0)
call mpistop(
'could not write Ap debug VTI payload')
861 position=writer%data_pos+writer%offsets(4)+8_8+&
862 (global_index-1_8)*8_8
863 write(writer%unit,pos=position,iostat=io_status) packed(10,ip)
864 if(io_status/=0)
call mpistop(
'could not write hm debug VTI payload')
865 position=writer%data_pos+writer%offsets(5)+8_8+&
866 (global_index-1_8)*8_8
867 write(writer%unit,pos=position,iostat=io_status) packed(11,ip)
868 if(io_status/=0)
call mpistop(
'could not write hJ debug VTI payload')
869 position=writer%data_pos+writer%offsets(6)+8_8+&
870 (global_index-1_8)*8_8
871 write(writer%unit,pos=position,iostat=io_status) packed(12,ip)
872 if(io_status/=0)
call mpistop(
'could not write hPJ debug VTI payload')
875 end subroutine mh_debug_vti_write_plane
877 subroutine mh_debug_vti_end(writer)
879 type(mh_debug_vti_state),
intent(inout) :: writer
880 integer(kind=8) :: footer_pos
882 if(.not.writer%enabled)
return
884 footer_pos=writer%data_pos+writer%offsets(mh_debug_narray)+8_8+&
885 writer%nbytes(mh_debug_narray)
886 write(writer%unit,pos=footer_pos) new_line(
'a')//&
887 '</AppendedData>'//new_line(
'a')//
'</VTKFile>'//new_line(
'a')
891 end subroutine mh_debug_vti_end
subroutine, public mpistop(message)
Exit MPI-AMRVAC with an error message.
Module with geometry-related routines (e.g., divergence, curl)
integer, parameter cartesian
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 snapshotini
Resume from the snapshot with this index.
double precision unit_pressure
Physical scaling factor for pressure.
integer, parameter ndim
Number of spatial dimensions for grid variables.
double precision unit_length
Physical scaling factor for length.
logical stagger_grid
True for using stagger grid.
double precision time_convert_factor
Conversion factor for time unit.
character(len=std_len), dimension(:), allocatable par_files
Which par files are used as input.
integer icomm
The MPI communicator.
integer mype
The rank of the current MPI task.
integer, parameter plevel_
integer ierrmpi
A global MPI error return code.
double precision, dimension(:), allocatable, parameter d
double precision unit_magneticfield
Physical scaling factor for magnetic field.
logical, dimension(ndim) stretched_dim
True if a dimension is stretched.
integer npe
The number of MPI tasks.
logical b0field
split magnetic field as background B0 field
double precision, dimension(:,:), allocatable rnode
Corner coordinates.
logical si_unit
Use SI units (.true.) or use cgs units (.false.)
logical convert
If true and restart_from_file is given, convert snapshots to other file formats.
character(len=std_len) base_filename
Base file name for simulation output, which will be followed by a number.
integer, dimension(:,:), allocatable node
Finite-volume relative magnetic helicity on a uniform Cartesian mesh.
type(magnetic_helicity_result), save, public mh_last_result
character(len=mh_name_len), public mh_debug_vti_file
integer, public mh_gauge_axis
subroutine, public mh_params_read(files)
character(len=mh_name_len), public mh_output_file
integer, public mh_mg_max_cycles
logical, public mh_write_debug_vti
logical, public mh_write_mg_timing
double precision, public mh_max_flux_imbalance
subroutine, public mh_run_task()
subroutine, public compute_magnetic_helicity_fv(config, result)
double precision, public mh_mg_tolerance
Finite-volume potential reference field for magnetic diagnostics.
subroutine, public solve_magnetic_reference_fv(config, bp, result)
subroutine, public free_magnetic_reference_field(bp)