MPI-AMRVAC 3.2
The MPI - Adaptive Mesh Refinement - Versatile Advection Code (development version)
Loading...
Searching...
No Matches
mod_magnetic_reference_fv.t
Go to the documentation of this file.
1!> Finite-volume potential reference field for magnetic diagnostics.
2!>
3!> The reference field Bp = grad(phi) is obtained from a Laplace solve with
4!> the normal component of the total magnetic field prescribed on all six
5!> physical faces. The multigrid solution is scratch storage only: callers
6!> receive an independently allocated, distributed cell-centred Bp field.
8 implicit none
9 private
10
12 double precision :: residual_tolerance=1.d-8
13 double precision :: max_flux_imbalance=1.d-6
14 integer :: max_cycles=50
15 !> Print the multigrid timer table after a successful solve. This is
16 !> deliberately opt-in so ordinary scientific output is unchanged.
17 logical :: write_timing=.false.
19
21 double precision :: magnetic_energy=0.d0
22 double precision :: residual=0.d0
23 double precision :: flux_imbalance=0.d0
24 double precision :: boundary_normal_error=0.d0
25 integer :: cycles=0
27
29 double precision, allocatable :: b(:^d&,:)
31
33 type(magnetic_reference_block), allocatable :: blocks(:)
35
38 {^ifthreed
39 public :: magnetic_reference_bc
40 }
41
42contains
43
44 subroutine solve_magnetic_reference_fv(config,bp,result)
45 use mod_comm_lib, only: mpistop
49 use, intrinsic :: ieee_arithmetic, only: ieee_is_finite
50
51 type(magnetic_reference_config), intent(in) :: config
52 type(magnetic_reference_field), intent(inout) :: bp
53 type(magnetic_reference_result), intent(out) :: result
54
55 double precision :: net_flux,unsigned_flux,local_energy,global_energy
56 double precision :: face_flux(6)
57 double precision :: res
58 integer :: i
59
62
63 if(ndim/=3) call mpistop('finite-volume magnetic reference requires three dimensions')
65 call mpistop('finite-volume magnetic reference requires Cartesian coordinates')
66 if(any(stretched_dim)) &
67 call mpistop('finite-volume magnetic reference requires an unstretched mesh')
68 if(any(periodb)) &
69 call mpistop('finite-volume magnetic reference requires six physical boundaries')
70 if(.not.allocated(iw_mag) .or. size(iw_mag)<3) &
71 call mpistop('finite-volume magnetic reference requires a three-component magnetic field')
72 if(config%residual_tolerance<=0.d0) &
73 call mpistop('magnetic-reference residual tolerance must be positive')
74 if(config%max_flux_imbalance<0.d0) &
75 call mpistop('magnetic-reference flux tolerance must not be negative')
76 if(config%max_cycles<1) &
77 call mpistop('magnetic-reference max_cycles must be positive')
78
79 {^ifthreed
80 if(.not.mg%is_allocated) call mg_setup_multigrid()
81
82 mg%operator_type=mg_laplacian
83 call mg_set_methods(mg)
84 ! A Laplacian with six Neumann boundaries has an arbitrary constant.
85 ! Removing the mean fixes that null mode without changing grad(phi).
86 mg%subtract_mean=.true.
87 mg%phi_bc_data_stored=.false.
88 mg%bc(:,mg_iphi)%bc_type=mg_bc_neumann
89 do i=1,2*ndim
90 mg%bc(i,mg_iphi)%boundary_cond=>magnetic_reference_bc
91 end do
92
93 call magnetic_reference_flux_metrics(net_flux,unsigned_flux,face_flux)
94 result%flux_imbalance=dabs(net_flux)/max(unsigned_flux,tiny(1.d0))
95 if(result%flux_imbalance>config%max_flux_imbalance) then
96 if(mype==0) then
97 write(*,'(a,es14.6)') 'magnetic-reference net boundary flux=',net_flux
98 write(*,'(a,es14.6)') 'magnetic-reference unsigned boundary flux=',unsigned_flux
99 write(*,'(a,es14.6)') 'magnetic-reference relative imbalance=',&
100 result%flux_imbalance
101 write(*,'(a,6(1x,es14.6))') 'magnetic-reference coordinate face fluxes=',&
102 face_flux
103 end if
104 call mpistop('finite-volume magnetic reference has incompatible Neumann flux')
105 end if
106
107 call magnetic_reference_initialize_mg()
108 res=huge(1.d0)
109 do i=1,config%max_cycles
110 if(i==1) then
111 ! Build the initial full-multigrid approximation once. Re-entering
112 ! FMG with have_guess=.true. repeats coarse restriction and correction
113 ! work that is unnecessary for subsequent residual reduction.
114 call mg_fas_fmg(mg,.false.,max_res=res)
115 else
116 ! Continue from the previous solution with the cheaper standalone
117 ! V-cycle. This is local to the reference-potential solve; other
118 ! AMRVAC multigrid users retain their existing schedules.
119 call mg_fas_vcycle(mg,max_res=res)
120 end if
121 if(mype==0) write(*,'(a,i0,a,es14.6)') &
122 'magnetic-reference MG cycle ',i,' residual=',res
123 if(res<=config%residual_tolerance) exit
124 end do
125 result%cycles=min(i,config%max_cycles)
126 result%residual=res
127 if(.not.ieee_is_finite(res)) &
128 call mpistop('finite-volume magnetic reference produced a non-finite residual')
129 if(res>config%residual_tolerance) &
130 call mpistop('finite-volume magnetic reference did not converge')
131
132 call mg_fill_ghost_cells(mg,mg_iphi)
133 call magnetic_reference_copy_gradient(bp,local_energy)
134 call mpi_allreduce(local_energy,global_energy,1,mpi_double_precision,&
135 mpi_sum,icomm,ierrmpi)
136 result%magnetic_energy=global_energy
137 call magnetic_reference_boundary_error(result%boundary_normal_error)
138 if(config%write_timing) call mg_timers_show(mg)
139 }
140 end subroutine solve_magnetic_reference_fv
141
143 type(magnetic_reference_field), intent(inout) :: bp
144 integer :: igrid
145
146 if(.not.allocated(bp%blocks)) return
147 do igrid=1,size(bp%blocks)
148 if(allocated(bp%blocks(igrid)%b)) deallocate(bp%blocks(igrid)%b)
149 end do
150 deallocate(bp%blocks)
151 end subroutine free_magnetic_reference_field
152
153{^ifthreed
154 subroutine magnetic_reference_initialize_mg()
156 use mod_forest, only: igrid_to_node
158
159 integer :: iigrid,igrid,id,nc,lvl
160
161 do iigrid=1,igridstail
162 igrid=igrids(iigrid)
163 id=igrid_to_node(igrid,mype)%node%id
164 lvl=mg%boxes(id)%lvl
165 nc=mg%box_size_lvl(lvl)
166 mg%boxes(id)%cc({1:nc},mg_iphi)=0.d0
167 mg%boxes(id)%cc({1:nc},mg_irhs)=0.d0
168 end do
169 end subroutine magnetic_reference_initialize_mg
170
171 subroutine magnetic_reference_copy_gradient(bp,local_energy)
173 use mod_forest, only: igrid_to_node
174 use mod_geometry, only: gradient
176
177 type(magnetic_reference_field), intent(inout) :: bp
178 double precision, intent(out) :: local_energy
179
180 double precision, allocatable :: tmp(:,:,:)
181 integer :: iigrid,igrid,idir,id,nc,lvl,ixi^l
182
183 allocate(bp%blocks(max_blocks))
184 iximin^d=ixmlo^d-1;
185 iximax^d=ixmhi^d+1;
186 allocate(tmp(ixi^s))
187 local_energy=0.d0
188 do iigrid=1,igridstail
189 igrid=igrids(iigrid)
190 block=>ps(igrid)
191 ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
192 id=igrid_to_node(igrid,mype)%node%id
193 lvl=mg%boxes(id)%lvl
194 nc=mg%box_size_lvl(lvl)
195 allocate(bp%blocks(igrid)%b(ixmlo1:ixmhi1,ixmlo2:ixmhi2,&
196 ixmlo3:ixmhi3,3))
197 do idir=1,3
198 tmp=0.d0
199 call gradient(mg%boxes(id)%cc({0:nc+1},mg_iphi),ixi^l,&
200 ixm^ll,idir,tmp)
201 bp%blocks(igrid)%b(ixmlo1:ixmhi1,ixmlo2:ixmhi2,&
202 ixmlo3:ixmhi3,idir)=tmp(ixmlo1:ixmhi1,ixmlo2:ixmhi2,&
203 ixmlo3:ixmhi3)
204 end do
205 local_energy=local_energy+sum(0.5d0*&
206 sum(bp%blocks(igrid)%b(ixmlo1:ixmhi1,ixmlo2:ixmhi2,&
207 ixmlo3:ixmhi3,:)**2,dim=4)*block%dvolume(ixmlo1:ixmhi1,&
208 ixmlo2:ixmhi2,ixmlo3:ixmhi3))
209 end do
210 deallocate(tmp)
211 end subroutine magnetic_reference_copy_gradient
212
213 subroutine magnetic_reference_flux_metrics(net_flux,unsigned_flux,face_flux)
215 use mod_forest, only: igrid_to_node
217
218 double precision, intent(out) :: net_flux,unsigned_flux,face_flux(6)
219 double precision :: local_values(2),global_values(2),area
220 double precision :: local_faces(6)
221 double precision, allocatable :: bc(:,:)
222 integer :: iigrid,igrid,id,lvl,nc,nb,idir,bc_type
223
224 local_values=0.d0
225 local_faces=0.d0
226 do iigrid=1,igridstail
227 igrid=igrids(iigrid)
228 block=>ps(igrid)
229 id=igrid_to_node(igrid,mype)%node%id
230 lvl=mg%boxes(id)%lvl
231 nc=mg%box_size_lvl(lvl)
232 allocate(bc(nc,nc))
233 do nb=1,6
234 if(.not.ps(igrid)%is_physical_boundary(nb)) cycle
235 call magnetic_reference_bc(mg%boxes(id),nc,mg_iphi,nb,bc_type,bc)
236 idir=(nb+1)/2
237 select case(idir)
238 case(1)
239 area=mg%boxes(id)%dr(2)*mg%boxes(id)%dr(3)
240 case(2)
241 area=mg%boxes(id)%dr(1)*mg%boxes(id)%dr(3)
242 case(3)
243 area=mg%boxes(id)%dr(1)*mg%boxes(id)%dr(2)
244 end select
245 if(mod(nb,2)==0) then
246 local_values(1)=local_values(1)+sum(bc)*area
247 else
248 local_values(1)=local_values(1)-sum(bc)*area
249 end if
250 local_values(2)=local_values(2)+sum(dabs(bc))*area
251 local_faces(nb)=local_faces(nb)+sum(bc)*area
252 end do
253 deallocate(bc)
254 end do
255 call mpi_allreduce(local_values,global_values,2,mpi_double_precision,&
256 mpi_sum,icomm,ierrmpi)
257 call mpi_allreduce(local_faces,face_flux,6,mpi_double_precision,&
258 mpi_sum,icomm,ierrmpi)
259 net_flux=global_values(1)
260 unsigned_flux=global_values(2)
261 end subroutine magnetic_reference_flux_metrics
262
263 subroutine magnetic_reference_boundary_error(relative_error)
265 use mod_forest, only: igrid_to_node
267
268 double precision, intent(out) :: relative_error
269 double precision :: local_values(2),global_values(2),area,dr
270 double precision, allocatable :: bc(:,:),derivative(:,:)
271 integer :: iigrid,igrid,id,lvl,nc,nb,idir,bc_type
272
273 local_values=0.d0
274 do iigrid=1,igridstail
275 igrid=igrids(iigrid)
276 block=>ps(igrid)
277 id=igrid_to_node(igrid,mype)%node%id
278 lvl=mg%boxes(id)%lvl
279 nc=mg%box_size_lvl(lvl)
280 allocate(bc(nc,nc),derivative(nc,nc))
281 do nb=1,6
282 if(.not.ps(igrid)%is_physical_boundary(nb)) cycle
283 call magnetic_reference_bc(mg%boxes(id),nc,mg_iphi,nb,bc_type,bc)
284 idir=(nb+1)/2
285 dr=mg%boxes(id)%dr(idir)
286 select case(nb)
287 case(1)
288 derivative=(mg%boxes(id)%cc(1,1:nc,1:nc,mg_iphi)-&
289 mg%boxes(id)%cc(0,1:nc,1:nc,mg_iphi))/dr
290 area=mg%boxes(id)%dr(2)*mg%boxes(id)%dr(3)
291 case(2)
292 derivative=(mg%boxes(id)%cc(nc+1,1:nc,1:nc,mg_iphi)-&
293 mg%boxes(id)%cc(nc,1:nc,1:nc,mg_iphi))/dr
294 area=mg%boxes(id)%dr(2)*mg%boxes(id)%dr(3)
295 case(3)
296 derivative=(mg%boxes(id)%cc(1:nc,1,1:nc,mg_iphi)-&
297 mg%boxes(id)%cc(1:nc,0,1:nc,mg_iphi))/dr
298 area=mg%boxes(id)%dr(1)*mg%boxes(id)%dr(3)
299 case(4)
300 derivative=(mg%boxes(id)%cc(1:nc,nc+1,1:nc,mg_iphi)-&
301 mg%boxes(id)%cc(1:nc,nc,1:nc,mg_iphi))/dr
302 area=mg%boxes(id)%dr(1)*mg%boxes(id)%dr(3)
303 case(5)
304 derivative=(mg%boxes(id)%cc(1:nc,1:nc,1,mg_iphi)-&
305 mg%boxes(id)%cc(1:nc,1:nc,0,mg_iphi))/dr
306 area=mg%boxes(id)%dr(1)*mg%boxes(id)%dr(2)
307 case(6)
308 derivative=(mg%boxes(id)%cc(1:nc,1:nc,nc+1,mg_iphi)-&
309 mg%boxes(id)%cc(1:nc,1:nc,nc,mg_iphi))/dr
310 area=mg%boxes(id)%dr(1)*mg%boxes(id)%dr(2)
311 end select
312 local_values(1)=local_values(1)+sum((derivative-bc)**2)*area
313 local_values(2)=local_values(2)+sum(bc**2)*area
314 end do
315 deallocate(bc,derivative)
316 end do
317 call mpi_allreduce(local_values,global_values,2,mpi_double_precision,&
318 mpi_sum,icomm,ierrmpi)
319 relative_error=dsqrt(global_values(1)/max(global_values(2),tiny(1.d0)))
320 end subroutine magnetic_reference_boundary_error
321}
322
323{^ifthreed
324 !> Supply d(phi)/dx_i = B_i on a physical multigrid boundary.
325 subroutine magnetic_reference_bc(box,nc,iv,nb,bc_type,bc)
328 type(mg_box_t), intent(in) :: box
329 integer, intent(in) :: nc,iv,nb
330 integer, intent(out) :: bc_type
331 double precision, intent(out) :: bc(nc,nc)
332
333 double precision :: rr(nc,nc,3)
334 double precision :: rmina,rminb,rmaxa,rmaxb,xmina,xminb,xmaxa,xmaxb
335 double precision :: wbn(ixg^t)
336 double precision, allocatable :: xcoarse(:,:,:)
337 integer :: iigrid,igrid,ix^d,idir,ixbca,ixbcb,ixbcn,dlvl,wnc
338
339 bc_type=mg_bc_neumann
340 bc=0.d0
341
342 call mg_get_face_coords(box,nb,nc,rr)
343 idir=(nb+1)/2
344 select case(idir)
345 case(1)
346 if(mod(nb,2)==0) then
347 ixbcn=ixmhi1
348 else
349 ixbcn=ixmlo1-1
350 end if
351 rmina=rr(1,1,2)-0.5d0*box%dr(2)
352 rmaxa=rr(nc,1,2)+0.5d0*box%dr(2)
353 rminb=rr(1,1,3)-0.5d0*box%dr(3)
354 rmaxb=rr(1,nc,3)+0.5d0*box%dr(3)
355 do iigrid=1,igridstail
356 igrid=igrids(iigrid)
357 block=>ps(igrid)
358 if(.not.block%is_physical_boundary(nb)) cycle
359 if(stagger_grid) then
360 wbn(ixbcn,ixglo2:ixghi2,ixglo3:ixghi3)=&
361 block%ws(ixbcn,ixglo2:ixghi2,ixglo3:ixghi3,idir)
362 if(b0field) wbn(ixbcn,ixglo2:ixghi2,ixglo3:ixghi3)=&
363 wbn(ixbcn,ixglo2:ixghi2,ixglo3:ixghi3)+&
364 block%B0(ixbcn,ixglo2:ixghi2,ixglo3:ixghi3,idir,idir)
365 else
366 wbn(ixbcn,ixglo2:ixghi2,ixglo3:ixghi3)=half*(&
367 block%w(ixbcn,ixglo2:ixghi2,ixglo3:ixghi3,iw_mag(idir))+&
368 block%w(ixbcn+1,ixglo2:ixghi2,ixglo3:ixghi3,iw_mag(idir)))
369 if(b0field) wbn(ixbcn,ixglo2:ixghi2,ixglo3:ixghi3)=&
370 wbn(ixbcn,ixglo2:ixghi2,ixglo3:ixghi3)+half*(&
371 block%B0(ixbcn,ixglo2:ixghi2,ixglo3:ixghi3,idir,0)+&
372 block%B0(ixbcn+1,ixglo2:ixghi2,ixglo3:ixghi3,idir,0))
373 end if
374 xmina=block%x(1,1,1,2)-0.5d0*rnode(rpdx2_,igrid)
375 xmaxa=block%x(1,ixghi2,1,2)+0.5d0*rnode(rpdx2_,igrid)
376 xminb=block%x(1,1,1,3)-0.5d0*rnode(rpdx3_,igrid)
377 xmaxb=block%x(1,1,ixghi3,3)+0.5d0*rnode(rpdx3_,igrid)
378 if(xmina<rr(1,1,2) .and. xmaxa>rr(nc,1,2) .and.&
379 xminb<rr(1,1,3) .and. xmaxb>rr(1,nc,3)) then
380 do ix2=1,nc
381 do ix1=1,nc
382 ixbca=ceiling((rr(ix1,ix2,2)-xmina)/rnode(rpdx2_,igrid))
383 ixbcb=ceiling((rr(ix1,ix2,3)-xminb)/rnode(rpdx3_,igrid))
384 bc(ix1,ix2)=wbn(ixbcn,ixbca,ixbcb)
385 end do
386 end do
387 else if(block%x(1,ixmlo2,1,2)>rmina .and.&
388 block%x(1,ixmhi2,1,2)<rmaxa .and.&
389 block%x(1,1,ixmlo3,3)>rminb .and.&
390 block%x(1,1,ixmhi3,3)<rmaxb) then
391 dlvl=node(plevel_,igrid)-box%lvl
392 wnc=nc/2**dlvl
393 allocate(xcoarse(wnc,wnc,2))
394 do ix2=1,wnc
395 do ix1=1,wnc
396 xcoarse(ix1,ix2,1)=sum(block%x(1,&
397 (ix1-1)*2**dlvl+1+nghostcells:ix1*2**dlvl+nghostcells,&
398 1,2))/dble(2**dlvl)
399 xcoarse(ix1,ix2,2)=sum(block%x(1,1,&
400 (ix2-1)*2**dlvl+1+nghostcells:ix2*2**dlvl+nghostcells,&
401 3))/dble(2**dlvl)
402 ixbca=ceiling((xcoarse(ix1,ix2,1)-rmina)/box%dr(2))
403 ixbcb=ceiling((xcoarse(ix1,ix2,2)-rminb)/box%dr(3))
404 bc(ixbca,ixbcb)=sum(wbn(ixbcn,&
405 (ix1-1)*2**dlvl+1+nghostcells:ix1*2**dlvl+nghostcells,&
406 (ix2-1)*2**dlvl+1+nghostcells:ix2*2**dlvl+nghostcells))/&
407 dble(2**(2*dlvl))
408 end do
409 end do
410 deallocate(xcoarse)
411 end if
412 end do
413 case(2)
414 if(mod(nb,2)==0) then
415 ixbcn=ixmhi2
416 else
417 ixbcn=ixmlo2-1
418 end if
419 rmina=rr(1,1,1)-0.5d0*box%dr(1)
420 rmaxa=rr(nc,1,1)+0.5d0*box%dr(1)
421 rminb=rr(1,1,3)-0.5d0*box%dr(3)
422 rmaxb=rr(1,nc,3)+0.5d0*box%dr(3)
423 do iigrid=1,igridstail
424 igrid=igrids(iigrid)
425 block=>ps(igrid)
426 if(.not.block%is_physical_boundary(nb)) cycle
427 if(stagger_grid) then
428 wbn(ixglo1:ixghi1,ixbcn,ixglo3:ixghi3)=&
429 block%ws(ixglo1:ixghi1,ixbcn,ixglo3:ixghi3,idir)
430 if(b0field) wbn(ixglo1:ixghi1,ixbcn,ixglo3:ixghi3)=&
431 wbn(ixglo1:ixghi1,ixbcn,ixglo3:ixghi3)+&
432 block%B0(ixglo1:ixghi1,ixbcn,ixglo3:ixghi3,idir,idir)
433 else
434 wbn(ixglo1:ixghi1,ixbcn,ixglo3:ixghi3)=half*(&
435 block%w(ixglo1:ixghi1,ixbcn,ixglo3:ixghi3,iw_mag(idir))+&
436 block%w(ixglo1:ixghi1,ixbcn+1,ixglo3:ixghi3,iw_mag(idir)))
437 if(b0field) wbn(ixglo1:ixghi1,ixbcn,ixglo3:ixghi3)=&
438 wbn(ixglo1:ixghi1,ixbcn,ixglo3:ixghi3)+half*(&
439 block%B0(ixglo1:ixghi1,ixbcn,ixglo3:ixghi3,idir,0)+&
440 block%B0(ixglo1:ixghi1,ixbcn+1,ixglo3:ixghi3,idir,0))
441 end if
442 xmina=block%x(1,1,1,1)-0.5d0*rnode(rpdx1_,igrid)
443 xmaxa=block%x(ixghi1,1,1,1)+0.5d0*rnode(rpdx1_,igrid)
444 xminb=block%x(1,1,1,3)-0.5d0*rnode(rpdx3_,igrid)
445 xmaxb=block%x(1,1,ixghi3,3)+0.5d0*rnode(rpdx3_,igrid)
446 if(xmina<rr(1,1,1) .and. xmaxa>rr(nc,1,1) .and.&
447 xminb<rr(1,1,3) .and. xmaxb>rr(1,nc,3)) then
448 do ix2=1,nc
449 do ix1=1,nc
450 ixbca=ceiling((rr(ix1,ix2,1)-xmina)/rnode(rpdx1_,igrid))
451 ixbcb=ceiling((rr(ix1,ix2,3)-xminb)/rnode(rpdx3_,igrid))
452 bc(ix1,ix2)=wbn(ixbca,ixbcn,ixbcb)
453 end do
454 end do
455 else if(block%x(ixmlo1,1,1,1)>rmina .and.&
456 block%x(ixmhi1,1,1,1)<rmaxa .and.&
457 block%x(1,1,ixmlo3,3)>rminb .and.&
458 block%x(1,1,ixmhi3,3)<rmaxb) then
459 dlvl=node(plevel_,igrid)-box%lvl
460 wnc=nc/2**dlvl
461 allocate(xcoarse(wnc,wnc,2))
462 do ix2=1,wnc
463 do ix1=1,wnc
464 xcoarse(ix1,ix2,1)=sum(block%x(&
465 (ix1-1)*2**dlvl+1+nghostcells:ix1*2**dlvl+nghostcells,&
466 1,1,1))/dble(2**dlvl)
467 xcoarse(ix1,ix2,2)=sum(block%x(1,1,&
468 (ix2-1)*2**dlvl+1+nghostcells:ix2*2**dlvl+nghostcells,&
469 3))/dble(2**dlvl)
470 ixbca=ceiling((xcoarse(ix1,ix2,1)-rmina)/box%dr(1))
471 ixbcb=ceiling((xcoarse(ix1,ix2,2)-rminb)/box%dr(3))
472 bc(ixbca,ixbcb)=sum(wbn(&
473 (ix1-1)*2**dlvl+1+nghostcells:ix1*2**dlvl+nghostcells,&
474 ixbcn,&
475 (ix2-1)*2**dlvl+1+nghostcells:ix2*2**dlvl+nghostcells))/&
476 dble(2**(2*dlvl))
477 end do
478 end do
479 deallocate(xcoarse)
480 end if
481 end do
482 case(3)
483 if(mod(nb,2)==0) then
484 ixbcn=ixmhi3
485 else
486 ixbcn=ixmlo3-1
487 end if
488 rmina=rr(1,1,1)-0.5d0*box%dr(1)
489 rmaxa=rr(nc,1,1)+0.5d0*box%dr(1)
490 rminb=rr(1,1,2)-0.5d0*box%dr(2)
491 rmaxb=rr(1,nc,2)+0.5d0*box%dr(2)
492 do iigrid=1,igridstail
493 igrid=igrids(iigrid)
494 block=>ps(igrid)
495 if(.not.block%is_physical_boundary(nb)) cycle
496 if(stagger_grid) then
497 wbn(ixglo1:ixghi1,ixglo2:ixghi2,ixbcn)=&
498 block%ws(ixglo1:ixghi1,ixglo2:ixghi2,ixbcn,idir)
499 if(b0field) wbn(ixglo1:ixghi1,ixglo2:ixghi2,ixbcn)=&
500 wbn(ixglo1:ixghi1,ixglo2:ixghi2,ixbcn)+&
501 block%B0(ixglo1:ixghi1,ixglo2:ixghi2,ixbcn,idir,idir)
502 else
503 wbn(ixglo1:ixghi1,ixglo2:ixghi2,ixbcn)=half*(&
504 block%w(ixglo1:ixghi1,ixglo2:ixghi2,ixbcn,iw_mag(idir))+&
505 block%w(ixglo1:ixghi1,ixglo2:ixghi2,ixbcn+1,iw_mag(idir)))
506 if(b0field) wbn(ixglo1:ixghi1,ixglo2:ixghi2,ixbcn)=&
507 wbn(ixglo1:ixghi1,ixglo2:ixghi2,ixbcn)+half*(&
508 block%B0(ixglo1:ixghi1,ixglo2:ixghi2,ixbcn,idir,0)+&
509 block%B0(ixglo1:ixghi1,ixglo2:ixghi2,ixbcn+1,idir,0))
510 end if
511 xmina=block%x(1,1,1,1)-0.5d0*rnode(rpdx1_,igrid)
512 xmaxa=block%x(ixghi1,1,1,1)+0.5d0*rnode(rpdx1_,igrid)
513 xminb=block%x(1,1,1,2)-0.5d0*rnode(rpdx2_,igrid)
514 xmaxb=block%x(1,ixghi2,1,2)+0.5d0*rnode(rpdx2_,igrid)
515 if(xmina<rr(1,1,1) .and. xmaxa>rr(nc,1,1) .and.&
516 xminb<rr(1,1,2) .and. xmaxb>rr(1,nc,2)) then
517 do ix2=1,nc
518 do ix1=1,nc
519 ixbca=ceiling((rr(ix1,ix2,1)-xmina)/rnode(rpdx1_,igrid))
520 ixbcb=ceiling((rr(ix1,ix2,2)-xminb)/rnode(rpdx2_,igrid))
521 bc(ix1,ix2)=wbn(ixbca,ixbcb,ixbcn)
522 end do
523 end do
524 else if(block%x(ixmlo1,1,1,1)>rmina .and.&
525 block%x(ixmhi1,1,1,1)<rmaxa .and.&
526 block%x(1,ixmlo2,1,2)>rminb .and.&
527 block%x(1,ixmhi2,1,2)<rmaxb) then
528 dlvl=node(plevel_,igrid)-box%lvl
529 wnc=nc/2**dlvl
530 allocate(xcoarse(wnc,wnc,2))
531 do ix2=1,wnc
532 do ix1=1,wnc
533 xcoarse(ix1,ix2,1)=sum(block%x(&
534 (ix1-1)*2**dlvl+1+nghostcells:ix1*2**dlvl+nghostcells,&
535 1,1,1))/dble(2**dlvl)
536 xcoarse(ix1,ix2,2)=sum(block%x(1,&
537 (ix2-1)*2**dlvl+1+nghostcells:ix2*2**dlvl+nghostcells,&
538 1,2))/dble(2**dlvl)
539 ixbca=ceiling((xcoarse(ix1,ix2,1)-rmina)/box%dr(1))
540 ixbcb=ceiling((xcoarse(ix1,ix2,2)-rminb)/box%dr(2))
541 bc(ixbca,ixbcb)=sum(wbn(&
542 (ix1-1)*2**dlvl+1+nghostcells:ix1*2**dlvl+nghostcells,&
543 (ix2-1)*2**dlvl+1+nghostcells:ix2*2**dlvl+nghostcells,&
544 ixbcn))/dble(2**(2*dlvl))
545 end do
546 end do
547 deallocate(xcoarse)
548 end if
549 end do
550 end select
551 end subroutine magnetic_reference_bc
552}
553
subroutine, public mpistop(message)
Exit MPI-AMRVAC with an error message.
Module with basic grid data structures.
Definition mod_forest.t:2
type(tree_node_ptr), dimension(:,:), allocatable, save igrid_to_node
Array to go from an [igrid, ipe] index to a node pointer.
Definition mod_forest.t:32
Module with geometry-related routines (e.g., divergence, curl)
Definition mod_geometry.t:2
integer coordinate
Definition mod_geometry.t:7
integer, parameter cartesian
Definition mod_geometry.t:8
subroutine gradient(q, ixil, ixol, idir, gradq, nth_in)
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, parameter ndim
Number of spatial dimensions for grid variables.
logical stagger_grid
True for using stagger grid.
integer icomm
The MPI communicator.
integer mype
The rank of the current MPI task.
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, dimension(ndim) stretched_dim
True if a dimension is stretched.
logical, dimension(ndim) periodb
True for dimensions with periodic boundaries.
logical b0field
split magnetic field as background B0 field
double precision, dimension(:,:), allocatable rnode
Corner coordinates.
integer nghostcells
Number of ghost cells surrounding a grid.
double precision, dimension(^nd) dxlevel
store unstretched cell size of current level
integer max_blocks
The maximum number of grid blocks in a processor.
integer, dimension(:,:), allocatable node
Finite-volume potential reference field for magnetic diagnostics.
subroutine, public magnetic_reference_bc(box, nc, iv, nb, bc_type, bc)
Supply d(phi)/dx_i = B_i on a physical multigrid boundary.
subroutine, public solve_magnetic_reference_fv(config, bp, result)
subroutine, public free_magnetic_reference_field(bp)
Module to couple the octree-mg library to AMRVAC. This file uses the VACPP preprocessor,...
type(mg_t) mg
Data structure containing the multigrid tree.
subroutine mg_setup_multigrid()
Setup multigrid for usage.