MPI-AMRVAC 3.2
The MPI - Adaptive Mesh Refinement - Versatile Advection Code (development version)
Loading...
Searching...
No Matches
mod_lfff.t
Go to the documentation of this file.
1!> Program to extrapolate linear force-free fields in 3D Cartesian coordinates,
2!> based on exact Green function method (Chiu & Hilton 1977 ApJ 212,873).
3!>
4!> Usage:
5!> 1 In the subroutine usr_set_parameters of mod_usr.t:
6!> To extrapolate a linear force free field from a observed magnetogram
7!> prepared in a data file, e.g., 'hmiM720sxxxx.dat' replace
8!> call init_bc_fff_data('hmiM720sxxxx.dat',unit_length,unit_magneticfield)
9!> 'hmiM720sxxxx.dat' must be a binary file containing nx1,nx2,xc1,xc2,dxm1,
10!> dxm2, Bz0(nx1,nx2). Integers nx1 and nx2 give the resolution of the
11!> uniform-grid magentogram. Others are double-precision floats. xc1 and xc2
12!> are coordinates of the central point of the magnetogram. dxm1 and dxm2
13!> are the cell sizes for each direction, Bz0 is the vertical conponent
14!> of magetic field on the solar surface from observations.
15!>2 In the subroutine usr_init_one_grid of mod_usr.t,
16!> add lines like:
17!>
18!> double precision :: Bf(ixG^S,1:ndir), alpha, zshift
19!>
20!> alpha=0.d0 ! potential field
21!> !alpha=0.08d0 ! non-potential linear force-free field
22!> zshift=0.05d0 ! lift your box zshift heigher to the bottom magnetogram
23!> call calc_lin_fff(ixG^L,ix^L,Bf,x,alpha,zshift)
24!>
25!>3 Notice that the resolution of input magnetogram must be better than the best
26!> resolution of your AMR grid to have a good behavior close to the bottom layer
28 implicit none
29
30 double precision, save :: bzmax,darea
31 double precision, allocatable, save :: bz0(:,:)
32 double precision, allocatable, save :: xa1(:),xa2(:)
33 integer, save :: nx1,nx2
34
35contains
36
37 subroutine init_b_fff_data(magnetogramname,qLunit,qBunit)
39 use mod_comm_lib, only: mpistop
40
41 double precision, intent(in) :: qLunit,qBunit
42 double precision :: xc1,xc2,dxm1,dxm2
43 integer, dimension(MPI_STATUS_SIZE) :: statuss
44 integer :: file_handle,i
45 logical :: aexist
46 character(len=*), intent(in) :: magnetogramname
47 ! nx1,nx2 are numbers of cells for each direction
48 ! xc1,xc2 are coordinates of the central point of the magnetogram
49 ! dxm1,dxm2 are cell sizes for each direction
50 ! Bz0 is the 2D Bz magnetogram
51 inquire(file=magnetogramname,exist=aexist)
52 if(.not. aexist) then
53 if(mype==0) write(*,'(2a)') "can not find file:",magnetogramname
54 call mpistop("no input magnetogram----init_b_fff_data")
55 end if
56 call mpi_file_open(icomm,magnetogramname,mpi_mode_rdonly,mpi_info_null,&
57 file_handle,ierrmpi)
58 call mpi_file_read_all(file_handle,nx1,1,mpi_integer,statuss,ierrmpi)
59 call mpi_file_read_all(file_handle,nx2,1,mpi_integer,statuss,ierrmpi)
60 allocate(bz0(nx1,nx2))
61 call mpi_file_read_all(file_handle,xc1,1,mpi_double_precision,statuss,ierrmpi)
62 call mpi_file_read_all(file_handle,xc2,1,mpi_double_precision,statuss,ierrmpi)
63 call mpi_file_read_all(file_handle,dxm1,1,mpi_double_precision,statuss,ierrmpi)
64 call mpi_file_read_all(file_handle,dxm2,1,mpi_double_precision,statuss,ierrmpi)
65 call mpi_file_read_all(file_handle,bz0,nx1*nx2,mpi_double_precision,&
66 statuss,ierrmpi)
67 call mpi_file_close(file_handle,ierrmpi)
68 allocate(xa1(nx1))
69 allocate(xa2(nx2))
70 do i=1,nx1
71 xa1(i) = xc1 + (dble(i) - dble(nx1)/2.d0 - 0.5d0)*dxm1
72 enddo
73 do i=1,nx2
74 xa2(i) = xc2 + (dble(i) - dble(nx2)/2.d0 - 0.5d0)*dxm2
75 enddo
76 ! declare and define global variables Lunit and Bunit to be your length unit in
77 ! cm and magnetic strength unit in Gauss first
78 dxm1=dxm1/qlunit
79 dxm2=dxm2/qlunit
80 xa1=xa1/qlunit
81 xa2=xa2/qlunit
82 darea=dxm1*dxm2
83 bz0=bz0/qbunit
84 bzmax=maxval(dabs(bz0(:,:)))
85
86 ! normalize b
88 if(mype==0) then
89 print*,'magnetogram xrange:',minval(xa1),maxval(xa1)
90 print*,'magnetogram yrange:',minval(xa2),maxval(xa2)
91 end if
92
93 if(mype==0) then
94 print*,'extrapolating 3D force-free field from an observed Bz '
95 print*,'magnetogram of',nx1,'by',nx2,'pixels. Bzmax=',bzmax
96 endif
97
98 end subroutine init_b_fff_data
99
100{^ifthreed
101 subroutine calc_lin_fff(ixI^L,ixO^L,Bf,x,alpha,zshift,idir)
102 ! PURPOSE:
103 ! Calculation to determine linear FFF from the field on
104 ! the lower boundary (Chiu and Hilton 1977 ApJ 212,873).
105 ! NOTE: Only works for Cartesian coordinates
106 ! INPUT: Bf,x
107 ! OUTPUT: updated b in w
109
110 integer, intent(in) :: ixI^L, ixO^L
111 integer, optional, intent(in) :: idir
112 double precision, intent(in) :: x(ixI^S,1:ndim),alpha,zshift
113 double precision, intent(inout) :: Bf(ixI^S,1:ndir)
114
115 double precision, dimension(ixO^S) :: cos_az,sin_az,zk,bigr,r,r2,r3,cos_ar,sin_ar,g,dgdz
116 double precision :: gx(ixO^S,1:ndim),twopiinv
117 integer :: idim,ixp1,ixp2
118
119 bf=0.d0
120 twopiinv = 0.5d0/dpi*bzmax*darea
121 ! get cos and sin arrays
122 zk(ixo^s)=x(ixo^s,3)-xprobmin3+zshift
123 cos_az(ixo^s)=dcos(alpha*zk(ixo^s))
124 sin_az(ixo^s)=dsin(alpha*zk(ixo^s))
125 ! looping Bz0 pixels
126 do ixp2=1,nx2
127 do ixp1=1,nx1
128 bigr(ixo^s)=dsqrt((x(ixo^s,1)-xa1(ixp1))**2+&
129 (x(ixo^s,2)-xa2(ixp2))**2)
130 r2=bigr**2+zk**2
131 r=dsqrt(r2)
132 r3=r**3
133 cos_ar=dcos(alpha*r)
134 sin_ar=dsin(alpha*r)
135 where(bigr/=0.d0)
136 bigr=1.d0/bigr
137 end where
138 where(r/=0.d0)
139 r=1.d0/r
140 end where
141 where(r2/=0.d0)
142 r2=1.d0/r2
143 end where
144 where(r3/=0.d0)
145 r3=1.d0/r3
146 end where
147 g=(zk*cos_ar*r-cos_az)*bigr
148 dgdz=(cos_ar*(r-zk**2*r3)-alpha*zk**2*sin_ar*r2+alpha*sin_az)*bigr
149 do idim=1,ndim
150 if(present(idir)) then
151 if(idim/=idir) cycle
152 end if
153 select case(idim)
154 case(1)
155 bf(ixo^s,1)=bf(ixo^s,1)+bz0(ixp1,ixp2)*((x(ixo^s,1)-xa1(ixp1))*dgdz(ixo^s)&
156 +alpha*g(ixo^s)*(x(ixo^s,2)-xa2(ixp2)))*bigr(ixo^s)
157 case(2)
158 bf(ixo^s,2)=bf(ixo^s,2)+bz0(ixp1,ixp2)*((x(ixo^s,2)-xa2(ixp2))*dgdz(ixo^s)&
159 -alpha*g(ixo^s)*(x(ixo^s,1)-xa1(ixp1)))*bigr(ixo^s)
160 case(3)
161 bf(ixo^s,3)=bf(ixo^s,3)+bz0(ixp1,ixp2)*(zk(ixo^s)*cos_ar(ixo^s)*r3(ixo^s)+alpha*&
162 zk(ixo^s)*sin_ar(ixo^s)*r2(ixo^s))
163 end select
164 end do
165 end do
166 end do
167 bf(ixo^s,:)=bf(ixo^s,:)*twopiinv
168
169 end subroutine calc_lin_fff
170
171 subroutine get_potential_field_potential(ixI^L,ixO^L,potential,x,zshift)
172 ! PURPOSE:
173 ! Calculation scalar potential of potential field given
174 ! Bz at photosphere (Schmidt 1964 NASSP).
175 ! NOTE: Only works for Cartesian coordinates
176 ! INPUT: x,zshift
177 ! OUTPUT: potential
179
180 integer, intent(in) :: ixI^L, ixO^L
181 double precision, intent(in) :: x(ixI^S,1:ndim),zshift
182 double precision, intent(inout) :: potential(ixI^S)
183
184 double precision :: zk
185 integer :: ixp1,ixp2,ix^D
186
187 potential=0.d0
188 ! looping Bz0 pixels see equation (2)
189 !$OMP PARALLEL DO
190 do ix3=ixomin3,ixomax3
191 zk=x(ixomin1,ixomin2,ix3,3)-xprobmin3+zshift
192 do ix2=ixomin2,ixomax2
193 do ix1=ixomin1,ixomax1
194 do ixp2=1,nx2
195 do ixp1=1,nx1
196 potential(ix^d)=potential(ix^d)+0.5d0*bz0(ixp1,ixp2)*darea/&
197 (dpi*dsqrt((x(ix^d,1)-xa1(ixp1))**2+(x(ix^d,2)-xa2(ixp2))**2+zk**2))
198 end do
199 end do
200 end do
201 end do
202 end do
203 !$OMP END PARALLEL DO
204 end subroutine get_potential_field_potential
205
206 subroutine get_potential_field_potential_sphere(ixI^L,x,potential,nth,nph,magnetogram,theta,phi,r_sphere)
207 ! PURPOSE:
208 ! Calculation scalar potential of potential field given
209 ! Bz at photosphere (Schmidt 1964 NASSP).
210 ! NOTE: Only works for spherical coordinates
211 ! OUTPUT: potential
213 integer, intent(in) :: ixI^L,nth,nph
214 real*8, intent(in) :: x(ixi^s,1:ndim)
215 ! magnetogram Br on photosphere
216 real*8, intent(in) :: magnetogram(nth,nph)
217 ! theta and phi grid of the photospheric magnetogram
218 real*8, intent(in) :: theta(nth),phi(nph)
219 ! radius of photosphere
220 real*8, intent(in) :: r_sphere
221 real*8, intent(out) :: potential(ixi^s)
222
223 real*8 :: area(nth),dtheta_half,dphi,inv2pi
224 integer :: ixp1,ixp2,ix^D
225
226 potential=0.d0
227 ! assume uniformly discretized theta and phi
228 dtheta_half=0.5d0*(theta(2)-theta(1))
229 dphi=phi(2)-phi(1)
230 area(1:nth)=2.d0*r_sphere**2*sin(theta(1:nth))*sin(dtheta_half)*sin(dphi)
231 inv2pi=1.d0/(2.d0*dpi)
232
233 !$OMP PARALLEL DO
234 do ix3=iximin3,iximax3
235 do ix2=iximin2,iximax2
236 do ix1=iximin1,iximax1
237 do ixp2=1,nph
238 do ixp1=1,nth
239 potential(ix^d)=potential(ix^d)+inv2pi*magnetogram(ixp1,ixp2)*area(ixp1)/&
240 dsqrt(x(ix^d,1)**2+r_sphere**2-2.d0*x(ix^d,1)*r_sphere*&
241 (dsin(x(ix^d,2))*dsin(theta(ixp1))*dcos(phi(ixp2)-x(ix^d,3))+dcos(x(ix^d,2))*&
242 dcos(theta(ixp1))))
243 end do
244 end do
245 end do
246 end do
247 end do
248 !$OMP END PARALLEL DO
249
251
252 !> get potential magnetic field energy given normal B on all boundaries
253 subroutine potential_field_energy_mg(benergy)
254 ! NOTE: Solve Poisson equation of scalar potential using multigrid solver
255 ! Only works for 3D Cartesian coordinates
258 use mod_forest
259 use mod_geometry
260 real*8, intent(out) :: benergy
261 real*8 :: block_benergy(ixm^t), mype_benergy
262 real*8, allocatable :: tmp(:,:,:)
263 integer :: iigrid, igrid, idir
264 integer :: id,nc, lvl, ixI^L
265
267 iximin^d=ixmlo^d-1;
268 iximax^d=ixmhi^d+1;
269 allocate(tmp(ixi^s))
270 mype_benergy=0.d0
271 do iigrid=1,igridstail; igrid=igrids(iigrid);
272 block=>ps(igrid)
273 ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
274 id = igrid_to_node(igrid, mype)%node%id
275 lvl= mg%boxes(id)%lvl
276 nc = mg%box_size_lvl(lvl)
277 block_benergy=0.d0
278 do idir=1,ndim
279 call gradient(mg%boxes(id)%cc({0:nc+1},mg_iphi),ixi^l,ixm^ll,idir,tmp)
280 block_benergy(ixm^t)=block_benergy(ixm^t)+tmp(ixm^t)**2
281 end do
282 mype_benergy=mype_benergy+sum(0.5d0*block_benergy(ixm^t)*block%dvolume(ixm^t))
283 end do
284
285 call mpi_allreduce(mype_benergy,benergy,1,mpi_double_precision,mpi_sum,icomm,ierrmpi)
286
287 end subroutine potential_field_energy_mg
288
289 !> Solve Poisson equation of scalar potential using multigrid solver
292 use mod_comm_lib, only: mpistop
294 double precision :: max_residual, res
295 integer :: i, max_its
296
297 mg%operator_type = mg_laplacian
298 max_its=50
299 max_residual=1.d-8
300
301 ! Set boundary conditions
302 mg%bc(:, mg_iphi)%bc_type = mg_bc_neumann
303
304 do i=1,2*ndim
305 mg%bc(i, mg_iphi)%boundary_cond => multigrid_bc
306 end do
307
308 ! Solve laplacian(phi) = 0
309 do i=1,max_its
310 !call mg_fas_vcycle(mg, max_res=res)
311 call mg_fas_fmg(mg,.true.,max_res=res)
312 if(mype==0) write(*,*) 'mg iteration',i,'residual:', res
313 if(res < max_residual) exit
314 end do
315 if(res > max_residual) call mpistop("get potential multigrid: no convergence")
316
318
319 !> To set boundary condition on physical boundaries for mg Poisson solver
320 subroutine multigrid_bc(box, nc, iv, nb, bc_type, bc)
323 type(mg_box_t), intent(in) :: box
324 integer, intent(in) :: nc
325 integer, intent(in) :: iv !< Index of variable
326 integer, intent(in) :: nb !< number of boundary from 1 to 6 for 3D
327 integer, intent(out) :: bc_type !< Type of b.c.
328 ! mg boundary values
329 double precision, intent(out) :: bc(nc, nc)
330 ! mg coordinates of boundary layer
331 double precision :: rr(nc, nc, 3)
332 double precision :: rmina,rminb,rmaxa,rmaxb,xmina,xminb,xmaxa,xmaxb
333 ! store normal magnetic field on the boundary
334 double precision :: wbn(ixG^T)
335 double precision, allocatable :: xcoarse(:,:,:)
336 integer :: iigrid,igrid,ix^D,idir,ixbca,ixbcb,ixbcn,dlvl,wnc
337
338 bc_type = mg_bc_neumann
339
340 call mg_get_face_coords(box, nb, nc, rr)
341
342 idir=(nb+1)/2
343 bc=0.d0
344 ! send normal B on boundaries from AMRVAC to mg Poisson solver
345 ! for Neumann boundary condition
346 select case(idir)
347 case(1)
348 if(mod(nb,2)==0) then
349 ixbcn=ixmhi1
350 else
351 ixbcn=ixmlo1-1
352 end if
353 rmina=rr(1,1,2)-0.5d0*box%dr(2)
354 rmaxa=rr(nc,1,2)+0.5d0*box%dr(2)
355 rminb=rr(1,1,3)-0.5d0*box%dr(3)
356 rmaxb=rr(1,nc,3)+0.5d0*box%dr(3)
357 do iigrid=1,igridstail; igrid=igrids(iigrid);
358 block=>ps(igrid)
359 if(.not.block%is_physical_boundary(nb)) cycle
360 if(stagger_grid) then
361 !wbn(ixbcn^%1ixG^T)=block%ws(ixbcn^%1ixG^T,idir)
362 wbn(ixbcn^%1ixg^t)=block%ws(ixbcn^%1ixg^t,idir)
363 else
364 wbn(ixbcn^%1ixg^t)=half*(block%w(ixbcn^%1ixg^t,iw_mag(idir))+block%w(ixbcn+1^%1ixg^t,iw_mag(idir)))
365 end if
366 xmina=block%x(1,1,1,2)-0.5d0*rnode(rpdx2_,igrid)
367 xmaxa=block%x(1,ixghi2,1,2)+0.5d0*rnode(rpdx2_,igrid)
368 xminb=block%x(1,1,1,3)-0.5d0*rnode(rpdx3_,igrid)
369 xmaxb=block%x(1,1,ixghi3,3)+0.5d0*rnode(rpdx3_,igrid)
370 if(xmina<rr(1,1,2) .and. xmaxa>rr(nc,1,2) .and. &
371 xminb<rr(1,1,3) .and. xmaxb>rr(1,nc,3)) then
372 do ix2=1,nc
373 do ix1=1,nc
374 ixbca=ceiling((rr(ix1,ix2,2)-xmina)/rnode(rpdx2_,igrid))
375 ixbcb=ceiling((rr(ix1,ix2,3)-xminb)/rnode(rpdx3_,igrid))
376 bc(ix1,ix2)=wbn(ixbcn,ixbca,ixbcb)
377 end do
378 end do
379 else if(block%x(1,ixmlo2,1,2)>rmina .and. block%x(1,ixmhi2,1,2)<rmaxa .and. &
380 block%x(1,1,ixmlo3,3)>rminb .and. block%x(1,1,ixmhi3,3)<rmaxb) then
381 dlvl=node(plevel_,igrid)-box%lvl
382 wnc=nc/2**dlvl
383 allocate(xcoarse(wnc,wnc,2))
384 do ix2=1,wnc
385 do ix1=1,wnc
386 xcoarse(ix1,ix2,1)=sum(block%x(1,(ix1-1)*2**dlvl+1+nghostcells:ix1*2**dlvl+nghostcells,1,2))/dble(2**dlvl)
387 xcoarse(ix1,ix2,2)=sum(block%x(1,1,(ix2-1)*2**dlvl+1+nghostcells:ix2*2**dlvl+nghostcells,3))/dble(2**dlvl)
388 ixbca=ceiling((xcoarse(ix1,ix2,1)-rmina)/box%dr(2))
389 ixbcb=ceiling((xcoarse(ix1,ix2,2)-rminb)/box%dr(3))
390 bc(ixbca,ixbcb)=sum(wbn(ixbcn,(ix1-1)*2**dlvl+1+nghostcells:ix1*2**dlvl+nghostcells,&
391 (ix2-1)*2**dlvl+1+nghostcells:ix2*2**dlvl+nghostcells))/dble(2**(2*dlvl))
392 end do
393 end do
394 deallocate(xcoarse)
395 end if
396 end do
397 case(2)
398 if(mod(nb,2)==0) then
399 ixbcn=ixmhi2
400 else
401 ixbcn=ixmlo2-1
402 end if
403 rmina=rr(1,1,1)-0.5d0*box%dr(1)
404 rmaxa=rr(nc,1,1)+0.5d0*box%dr(1)
405 rminb=rr(1,1,3)-0.5d0*box%dr(3)
406 rmaxb=rr(1,nc,3)+0.5d0*box%dr(3)
407 do iigrid=1,igridstail; igrid=igrids(iigrid);
408 block=>ps(igrid)
409 if(.not.block%is_physical_boundary(nb)) cycle
410 if(stagger_grid) then
411 wbn(ixbcn^%2ixg^t)=block%ws(ixbcn^%2ixg^t,idir)
412 else
413 wbn(ixbcn^%2ixg^t)=half*(block%w(ixbcn^%2ixg^t,iw_mag(idir))+block%w(ixbcn+1^%2ixg^t,iw_mag(idir)))
414 end if
415 xmina=block%x(1,1,1,1)-0.5d0*rnode(rpdx1_,igrid)
416 xmaxa=block%x(ixghi1,1,1,1)+0.5d0*rnode(rpdx1_,igrid)
417 xminb=block%x(1,1,1,3)-0.5d0*rnode(rpdx3_,igrid)
418 xmaxb=block%x(1,1,ixghi3,3)+0.5d0*rnode(rpdx3_,igrid)
419 if(xmina<rr(1,1,1) .and. xmaxa>rr(nc,1,1) .and. &
420 xminb<rr(1,1,3) .and. xmaxb>rr(1,nc,3)) then
421 do ix2=1,nc
422 do ix1=1,nc
423 ixbca=ceiling((rr(ix1,ix2,1)-xmina)/rnode(rpdx1_,igrid))
424 ixbcb=ceiling((rr(ix1,ix2,3)-xminb)/rnode(rpdx3_,igrid))
425 bc(ix1,ix2)=wbn(ixbca,ixbcn,ixbcb)
426 end do
427 end do
428 else if(block%x(ixmlo1,1,1,1)>rmina .and. block%x(ixmhi1,1,1,1)<rmaxa .and. &
429 block%x(1,1,ixmlo3,3)>rminb .and. block%x(1,1,ixmhi3,3)<rmaxb) then
430 dlvl=node(plevel_,igrid)-box%lvl
431 wnc=nc/2**dlvl
432 allocate(xcoarse(wnc,wnc,2))
433 do ix2=1,wnc
434 do ix1=1,wnc
435 xcoarse(ix1,ix2,1)=sum(block%x((ix1-1)*2**dlvl+1+nghostcells:ix1*2**dlvl+nghostcells,1,1,1))/dble(2**dlvl)
436 xcoarse(ix1,ix2,2)=sum(block%x(1,1,(ix2-1)*2**dlvl+1+nghostcells:ix2*2**dlvl+nghostcells,3))/dble(2**dlvl)
437 ixbca=ceiling((xcoarse(ix1,ix2,1)-rmina)/box%dr(1))
438 ixbcb=ceiling((xcoarse(ix1,ix2,2)-rminb)/box%dr(3))
439 bc(ixbca,ixbcb)=sum(wbn((ix1-1)*2**dlvl+1+nghostcells:ix1*2**dlvl+nghostcells,ixbcn,&
440 (ix2-1)*2**dlvl+1+nghostcells:ix2*2**dlvl+nghostcells))/dble(2**(2*dlvl))
441 end do
442 end do
443 deallocate(xcoarse)
444 end if
445 end do
446 case(3)
447 if(mod(nb,2)==0) then
448 ixbcn=ixmhi3
449 else
450 ixbcn=ixmlo3-1
451 end if
452 rmina=rr(1,1,1)-0.5d0*box%dr(1)
453 rmaxa=rr(nc,1,1)+0.5d0*box%dr(1)
454 rminb=rr(1,1,2)-0.5d0*box%dr(2)
455 rmaxb=rr(1,nc,2)+0.5d0*box%dr(2)
456 do iigrid=1,igridstail; igrid=igrids(iigrid);
457 block=>ps(igrid)
458 if(.not.block%is_physical_boundary(nb)) cycle
459 if(stagger_grid) then
460 wbn(ixbcn^%3ixg^t)=block%ws(ixbcn^%3ixg^t,idir)
461 else
462 wbn(ixbcn^%3ixg^t)=half*(block%w(ixbcn^%3ixg^t,iw_mag(idir))+block%w(ixbcn+1^%3ixg^t,iw_mag(idir)))
463 end if
464 xmina=block%x(1,1,1,1)-0.5d0*rnode(rpdx1_,igrid)
465 xmaxa=block%x(ixghi1,1,1,1)+0.5d0*rnode(rpdx1_,igrid)
466 xminb=block%x(1,1,1,2)-0.5d0*rnode(rpdx2_,igrid)
467 xmaxb=block%x(1,ixghi2,1,2)+0.5d0*rnode(rpdx2_,igrid)
468 if(xmina<rr(1,1,1) .and. xmaxa>rr(nc,1,1) .and. &
469 xminb<rr(1,1,2) .and. xmaxb>rr(1,nc,2)) then
470 do ix2=1,nc
471 do ix1=1,nc
472 ixbca=ceiling((rr(ix1,ix2,1)-xmina)/rnode(rpdx1_,igrid))
473 ixbcb=ceiling((rr(ix1,ix2,2)-xminb)/rnode(rpdx2_,igrid))
474 bc(ix1,ix2)=wbn(ixbca,ixbcb,ixbcn)
475 end do
476 end do
477 else if(block%x(ixmlo1,1,1,1)>rmina .and. block%x(ixmhi1,1,1,1)<rmaxa .and. &
478 block%x(1,ixmlo2,1,2)>rminb .and. block%x(1,ixmhi2,1,2)<rmaxb) then
479 dlvl=node(plevel_,igrid)-box%lvl
480 wnc=nc/2**dlvl
481 allocate(xcoarse(wnc,wnc,2))
482 do ix2=1,wnc
483 do ix1=1,wnc
484 xcoarse(ix1,ix2,1)=sum(block%x((ix1-1)*2**dlvl+1+nghostcells:ix1*2**dlvl+nghostcells,1,1,1))/dble(2**dlvl)
485 xcoarse(ix1,ix2,2)=sum(block%x(1,(ix2-1)*2**dlvl+1+nghostcells:ix2*2**dlvl+nghostcells,1,2))/dble(2**dlvl)
486 ixbca=ceiling((xcoarse(ix1,ix2,1)-rmina)/box%dr(1))
487 ixbcb=ceiling((xcoarse(ix1,ix2,2)-rminb)/box%dr(2))
488 bc(ixbca,ixbcb)=sum(wbn((ix1-1)*2**dlvl+1+nghostcells:ix1*2**dlvl+nghostcells,&
489 (ix2-1)*2**dlvl+1+nghostcells:ix2*2**dlvl+nghostcells,ixbcn))/dble(2**(2*dlvl))
490 end do
491 end do
492 deallocate(xcoarse)
493 end if
494 end do
495 end select
496
497 end subroutine multigrid_bc
498}
499end module mod_lfff
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
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.
double precision, dimension(:), allocatable, parameter d
integer ixm
the mesh range of a physical block without ghost cells
integer ierrmpi
A global MPI error return code.
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, dimension(:,:), allocatable node
Program to extrapolate linear force-free fields in 3D Cartesian coordinates, based on exact Green fun...
Definition mod_lfff.t:27
double precision, save darea
Definition mod_lfff.t:30
double precision, dimension(:,:), allocatable, save bz0
Definition mod_lfff.t:31
subroutine multigrid_bc(box, nc, iv, nb, bc_type, bc)
To set boundary condition on physical boundaries for mg Poisson solver.
Definition mod_lfff.t:321
integer, save nx1
Definition mod_lfff.t:33
subroutine get_potential_field_potential_sphere(ixil, x, potential, nth, nph, magnetogram, theta, phi, r_sphere)
Definition mod_lfff.t:207
subroutine init_b_fff_data(magnetogramname, qlunit, qbunit)
Definition mod_lfff.t:38
subroutine get_potential_field_potential_mg()
Solve Poisson equation of scalar potential using multigrid solver.
Definition mod_lfff.t:291
subroutine calc_lin_fff(ixil, ixol, bf, x, alpha, zshift, idir)
Definition mod_lfff.t:102
subroutine potential_field_energy_mg(benergy)
get potential magnetic field energy given normal B on all boundaries
Definition mod_lfff.t:254
integer, save nx2
Definition mod_lfff.t:33
double precision, dimension(:), allocatable, save xa2
Definition mod_lfff.t:32
double precision, save bzmax
Definition mod_lfff.t:30
subroutine get_potential_field_potential(ixil, ixol, potential, x, zshift)
Definition mod_lfff.t:172
double precision, dimension(:), allocatable, save xa1
Definition mod_lfff.t:32
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.