MPI-AMRVAC 3.2
The MPI - Adaptive Mesh Refinement - Versatile Advection Code (development version)
Loading...
Searching...
No Matches
mod_nlfff_diagnostics.t
Go to the documentation of this file.
1!> Common user-facing diagnostics for NLFFF relaxation and extrapolation.
3 implicit none
4 private
5
6 type, public :: nlfff_physical_metrics
7 double precision :: cw_sin_theta=0.d0
8 double precision :: epsilon_force=0.d0
9 double precision :: epsilon_div=0.d0
10 double precision :: magnetic_energy=0.d0
12
13{^ifthreed
18}
19
20contains
21
22{^ifthreed
23 !> Evaluate the common metrics on all active AMRVAC cells. The local cell
24 !> size makes epsilon_force and epsilon_div dimensionless on AMR meshes.
25 subroutine evaluate_nlfff_metrics_amrvac(iw_b,metrics)
26 use mpi
27 use mod_comm_lib, only: mpistop
30 use, intrinsic :: ieee_arithmetic, only: ieee_is_finite
31
32 integer, intent(in) :: iw_b(3)
33 type(nlfff_physical_metrics), intent(out) :: metrics
34
35 double precision :: bvec(ixglo1:ixghi1,ixglo2:ixghi2,&
36 ixglo3:ixghi3,3)
37 double precision :: current(ixglo1:ixghi1,ixglo2:ixghi2,&
38 ixglo3:ixghi3,3)
39 double precision :: divb(ixglo1:ixghi1,ixglo2:ixghi2,ixglo3:ixghi3)
40 double precision :: local(5),global(5),b(3),j(3),jxb(3)
41 double precision :: b2,j2,jxb2,volume,hcell
42 integer :: iigrid,igrid,ix1,ix2,ix3,idirmin
43
44 local=0.d0
45 do iigrid=1,igridstail
46 igrid=igrids(iigrid)
47 block=>ps(igrid)
48 ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
49 bvec=0.d0
50 bvec(:,:,:,1:3)=ps(igrid)%w(:,:,:,iw_b(:))
51 if(b0field) bvec(:,:,:,1:3)=bvec(:,:,:,1:3)+&
52 block%B0(:,:,:,iw_b(:),0)
53 current=0.d0
54 divb=0.d0
55 idirmin=1
56 call curlvector(bvec,ixg^ll,ixm^ll,current,idirmin,1,3)
57 call divvector(bvec,ixg^ll,ixm^ll,divb,1)
58 do ix3=ixmlo3,ixmhi3
59 do ix2=ixmlo2,ixmhi2
60 do ix1=ixmlo1,ixmhi1
61 b=bvec(ix1,ix2,ix3,:)
62 j=current(ix1,ix2,ix3,:)
63 jxb=nlfff_cross3(j,b)
64 b2=dot_product(b,b)
65 j2=dot_product(j,j)
66 jxb2=dot_product(jxb,jxb)
67 volume=block%dvolume(ix1,ix2,ix3)
68 hcell=volume**(1.d0/3.d0)
69 if(b2>0.d0) then
70 local(1)=local(1)+dsqrt(jxb2/b2)*volume
71 local(3)=local(3)+hcell**2*jxb2/b2*volume
72 end if
73 local(2)=local(2)+dsqrt(j2)*volume
74 local(4)=local(4)+hcell**2*divb(ix1,ix2,ix3)**2*volume
75 local(5)=local(5)+b2*volume
76 end do
77 end do
78 end do
79 end do
80 call mpi_allreduce(local,global,5,mpi_double_precision,mpi_sum,&
82 if(.not.all(ieee_is_finite(global))) &
83 call mpistop('non-finite common NLFFF diagnostic')
85 if(global(2)>0.d0) metrics%cw_sin_theta=global(1)/global(2)
86 if(global(5)>0.d0) then
87 metrics%epsilon_force=dsqrt(max(0.d0,global(3))/global(5))
88 metrics%epsilon_div=dsqrt(max(0.d0,global(4))/global(5))
89 end if
90 metrics%magnetic_energy=0.5d0*global(5)
92
93 !> Evaluate the same metrics on a replicated uniform dense field. Plane 1
94 !> is the lower boundary and planes 2:nz are the active-cell centres.
95 subroutine evaluate_nlfff_metrics_dense(b,dx1,dx2,dx3,metrics)
96 use, intrinsic :: ieee_arithmetic, only: ieee_is_finite
97
98 double precision, intent(in) :: b(:,:,:,:),dx1,dx2,dx3
99 type(nlfff_physical_metrics), intent(out) :: metrics
100 double precision :: db(3,3),j(3),bv(3),jxb(3),divb,b2,j2,jxb2
101 double precision :: sum_cross,sum_j,sum_force,sum_div,sum_b2,h,volume
102 integer :: i,jj,k,ic
103
104 sum_cross=0.d0; sum_j=0.d0; sum_force=0.d0
105 sum_div=0.d0; sum_b2=0.d0
106 h=(dx1*dx2*dx3)**(1.d0/3.d0)
107 volume=dx1*dx2*dx3
108 do k=2,size(b,3)
109 do jj=1,size(b,2)
110 do i=1,size(b,1)
111 do ic=1,3
112 db(ic,1)=dense_derivative(b(:,jj,k,ic),i,dx1)
113 db(ic,2)=dense_derivative(b(i,:,k,ic),jj,dx2)
114 db(ic,3)=dense_derivative(b(i,jj,:,ic),k,dx3)
115 end do
116 j=(/db(3,2)-db(2,3),db(1,3)-db(3,1),db(2,1)-db(1,2)/)
117 bv=b(i,jj,k,:)
118 jxb=nlfff_cross3(j,bv)
119 b2=dot_product(bv,bv)
120 j2=dot_product(j,j)
121 jxb2=dot_product(jxb,jxb)
122 if(b2>0.d0) then
123 sum_cross=sum_cross+dsqrt(jxb2/b2)*volume
124 sum_force=sum_force+h**2*jxb2/b2*volume
125 end if
126 sum_j=sum_j+dsqrt(j2)*volume
127 divb=db(1,1)+db(2,2)+db(3,3)
128 sum_div=sum_div+h**2*divb**2*volume
129 sum_b2=sum_b2+b2*volume
130 end do
131 end do
132 end do
133 if(.not.ieee_is_finite(sum_cross+sum_j+sum_force+sum_div+sum_b2)) &
134 error stop 'non-finite common dense NLFFF diagnostic'
136 if(sum_j>0.d0) metrics%cw_sin_theta=sum_cross/sum_j
137 if(sum_b2>0.d0) then
138 metrics%epsilon_force=dsqrt(max(0.d0,sum_force)/sum_b2)
139 metrics%epsilon_div=dsqrt(max(0.d0,sum_div)/sum_b2)
140 end if
141 metrics%magnetic_energy=0.5d0*sum_b2
142 end subroutine evaluate_nlfff_metrics_dense
143
144 pure function nlfff_cross3(a,b) result(c)
145 double precision, intent(in) :: a(3),b(3)
146 double precision :: c(3)
147 c=(/a(2)*b(3)-a(3)*b(2),a(3)*b(1)-a(1)*b(3),&
148 a(1)*b(2)-a(2)*b(1)/)
149 end function nlfff_cross3
150
151 pure double precision function dense_derivative(f,i,h)
152 double precision, intent(in) :: f(:),h
153 integer, intent(in) :: i
154 integer :: n
155
156 n=size(f)
157 if(n<3) then
158 dense_derivative=0.d0
159 else if(i==1) then
160 dense_derivative=(-3.d0*f(1)+4.d0*f(2)-f(3))/(2.d0*h)
161 else if(i==n) then
162 dense_derivative=(3.d0*f(n)-4.d0*f(n-1)+f(n-2))/(2.d0*h)
163 else
164 dense_derivative=(f(i+1)-f(i-1))/(2.d0*h)
165 end if
166 end function dense_derivative
167
169 integer, intent(in) :: unit
170 write(unit,'(a)') &
171 'iteration,CW_sin_theta,epsilon_force,epsilon_div,magnetic_energy'
172 flush(unit)
173 end subroutine write_nlfff_metrics_header
174
175 subroutine write_nlfff_metrics_row(unit,iteration,metrics)
176 integer, intent(in) :: unit,iteration
177 type(nlfff_physical_metrics), intent(in) :: metrics
178 write(unit,'(i0,4(",",es24.16))') iteration,metrics%cw_sin_theta,&
179 metrics%epsilon_force,metrics%epsilon_div,metrics%magnetic_energy
180 flush(unit)
181 end subroutine write_nlfff_metrics_row
182}
183
184end module mod_nlfff_diagnostics
subroutine metrics
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
subroutine divvector(qvec, ixil, ixol, divq, nth_in)
subroutine curlvector(qvec, ixil, ixol, curlvec, idirmin, idirmin0, ndir0, fourthorder)
Calculate curl of a vector qvec within ixL Options to employ standard second order CD evaluations use...
This module contains definitions of global parameters and variables and some generic functions/subrou...
type(state), pointer block
Block pointer for using one block and its previous state.
integer icomm
The MPI communicator.
integer ixm
the mesh range of a physical block without ghost cells
integer ierrmpi
A global MPI error return code.
double precision, dimension(:), allocatable, parameter d
logical b0field
split magnetic field as background B0 field
double precision, dimension(:,:), allocatable rnode
Corner coordinates.
double precision, dimension(^nd) dxlevel
store unstretched cell size of current level
Common user-facing diagnostics for NLFFF relaxation and extrapolation.
subroutine, public write_nlfff_metrics_header(unit)
subroutine, public evaluate_nlfff_metrics_dense(b, dx1, dx2, dx3, metrics)
Evaluate the same metrics on a replicated uniform dense field. Plane 1 is the lower boundary and plan...
subroutine, public write_nlfff_metrics_row(unit, iteration, metrics)
subroutine, public evaluate_nlfff_metrics_amrvac(iw_b, metrics)
Evaluate the common metrics on all active AMRVAC cells. The local cell size makes epsilon_force and e...