MPI-AMRVAC  3.1
The MPI - Adaptive Mesh Refinement - Versatile Advection Code (development version)
mod_convert.t
Go to the documentation of this file.
1 module mod_convert
2 
3  use mpi
4  use mod_variables, only: max_nw
5 
6  implicit none
7  public
8 
9  abstract interface
10 
11  function sub_convert_vars(ixI^L, ixO^L, w, x, nwc) result(wnew)
13  integer, intent(in) :: ixi^l,ixo^l, nwc
14  double precision, intent(in) :: w(ixi^s, 1:nw)
15  double precision, intent(in) :: x(ixi^s,1:ndim)
16  double precision :: wnew(ixo^s, 1:nwc)
17  end function sub_convert_vars
18 
19 
20  end interface
22  procedure(sub_convert_vars), pointer, nopass :: phys_convert_vars
23  integer :: nwc
24  character(len=40) :: file_suffix
25  character(len=40) :: dataset_names(max_nw)
26  type(convert_vars_method), pointer :: next
27  end type convert_vars_method
29 contains
30 
31  subroutine init_convert()
32  !initialize the head of the linked list of convert methods
34  end subroutine init_convert
35 
36  ! shortcut
37  subroutine add_convert_method2(phys_convert_vars, nwc, aux_variable_names, file_suffix)
40  integer, intent(in) :: nwc
41  character(len=*),intent(in):: aux_variable_names
42  character(len=*), intent(in) :: file_suffix
43 
44  interface
45  function phys_convert_vars(ixI^L, ixO^L, w, x, nwc) result(wnew)
47  integer, intent(in) :: ixI^L, ixO^L, nwc
48  double precision, intent(in) :: w(ixI^S, 1:nw)
49  double precision, intent(in) :: x(ixI^S,1:ndim)
50  double precision :: wnew(ixO^S, 1:nwc)
51  end function phys_convert_vars
52  end interface
53 
54  call add_convert_method(phys_convert_vars, nwc, get_names_from_string(aux_variable_names,nwc), file_suffix)
55 
56  end subroutine add_convert_method2
57 
58  subroutine add_convert_method(phys_convert_vars, nwc, dataset_names, file_suffix)
59  use mod_comm_lib, only: mpistop
60  integer, intent(in) :: nwc
61  character(len=*), intent(in) :: dataset_names(:)
62  character(len=*), intent(in) :: file_suffix
63 
64  interface
65  function phys_convert_vars(ixI^L, ixO^L, w, x, nwc) result(wnew)
67  integer, intent(in) :: ixI^L, ixO^L, nwc
68  double precision, intent(in) :: w(ixI^S, 1:nw)
69  double precision, intent(in) :: x(ixI^S,1:ndim)
70  double precision :: wnew(ixO^S, 1:nwc)
71  end function phys_convert_vars
72  end interface
73 
74  type(convert_vars_method), pointer :: temp
75 
76  if(nwc .gt. max_nw) then
77  call mpistop("INCREASE max_nw ")
78  endif
79 
80  allocate(temp)
81  temp%phys_convert_vars => phys_convert_vars
82  temp%nwc = nwc
83  temp%file_suffix = file_suffix
84  temp%dataset_names(1:nwc) = dataset_names(1:nwc)
85  temp%next => head_convert_vars_methods
87  end subroutine add_convert_method
88 
89 
90  subroutine convert_all()
91  type(convert_vars_method), pointer :: temp
93  do while(associated(temp))
94  call convert_dat_generic(temp%nwc, temp%dataset_names, temp%file_suffix, temp%phys_convert_vars)
95  temp=>temp%next
96  end do
97  end subroutine convert_all
98 
99  ! Copied from subroutine write_snapshot in amrvacio/mod_input_output
100  ! the staggered values are not saved in this subroutine!
101  subroutine convert_dat_generic(nwc, dataset_names, file_suffix, convert_vars)
102 
103  use mod_forest
107 
108  integer :: file_handle, igrid, Morton_no, iwrite
109  integer :: ipe, ix_buffer(2*ndim+1), n_values
110  integer :: ixI^L, ixO^L, n_ghost(2*ndim)
111  integer :: ixOs^L,n_values_stagger
112  integer :: iorecvstatus(MPI_STATUS_SIZE)
113  integer :: ioastatus(MPI_STATUS_SIZE)
114  integer :: igrecvstatus(MPI_STATUS_SIZE)
115  integer :: istatus(MPI_STATUS_SIZE)
116  type(tree_node), pointer :: pnode
117  integer(kind=MPI_OFFSET_KIND) :: offset_tree_info
118  integer(kind=MPI_OFFSET_KIND) :: offset_block_data
119  integer(kind=MPI_OFFSET_KIND) :: offset_offsets
120  double precision, allocatable :: w_buffer(:)
121  double precision, allocatable:: converted_vars(:^D&,:)
122 
123  integer :: idim, itag
124  integer, allocatable :: block_ig(:, :)
125  integer, allocatable :: block_lvl(:)
126  integer(kind=MPI_OFFSET_KIND), allocatable :: block_offset(:)
127 
128  integer, intent(in) :: nwc
129  character(len=*), intent(in) :: dataset_names(:)
130  character(len=*), intent(in) :: file_suffix
131  interface
132 
133  function convert_vars(ixI^L, ixO^L,w,x,nwc) result(wres)
135  integer, intent(in) :: ixI^L, ixO^L, nwc
136  double precision, intent(in) :: x(ixI^S,1:ndim)
137  double precision, intent(in) :: w(ixI^S,1:nw)
138  double precision :: wres(ixO^S,1:nwc)
139  end function convert_vars
140 
141  end interface
142 
143 
144  call mpi_barrier(icomm, ierrmpi)
145 
146  ! Allocate send/receive buffer
147  n_values = count_ix(ixg^ll) * nw
148  allocate(w_buffer(n_values))
149 
150  ! Allocate arrays with information about grid blocks
151  allocate(block_ig(ndim, nleafs))
152  allocate(block_lvl(nleafs))
153  allocate(block_offset(nleafs+1))
154 
155  ! master processor
156  if (mype==0) then
157  call create_output_file(file_handle, snapshotnext, ".dat", file_suffix)
158 
159  ! Don't know offsets yet, we will write header again later
160  offset_tree_info = -1
161  offset_block_data = -1
162  call snapshot_write_header1(file_handle, offset_tree_info, &
163  offset_block_data, dataset_names, nwc)
164 
165  call mpi_file_get_position(file_handle, offset_tree_info, ierrmpi)
166 
167  call write_forest(file_handle)
168 
169  ! Collect information about the spatial index (ig^D) and refinement level
170  ! of leaves
171  do morton_no = morton_start(0), morton_stop(npe-1)
172  igrid = sfc(1, morton_no)
173  ipe = sfc(2, morton_no)
174  pnode => igrid_to_node(igrid, ipe)%node
175 
176  block_ig(:, morton_no) = [ pnode%ig^d ]
177  block_lvl(morton_no) = pnode%level
178  block_offset(morton_no) = 0 ! Will be determined later
179  end do
180 
181  call mpi_file_write(file_handle, block_lvl, size(block_lvl), &
182  mpi_integer, istatus, ierrmpi)
183 
184  call mpi_file_write(file_handle, block_ig, size(block_ig), &
185  mpi_integer, istatus, ierrmpi)
186 
187  ! Block offsets are currently unknown, but will be overwritten later
188  call mpi_file_get_position(file_handle, offset_offsets, ierrmpi)
189  call mpi_file_write(file_handle, block_offset(1:nleafs), nleafs, &
190  mpi_offset, istatus, ierrmpi)
191 
192  call mpi_file_get_position(file_handle, offset_block_data, ierrmpi)
193 
194  ! Check whether data was written as expected
195  if (offset_block_data - offset_tree_info /= &
196  (nleafs + nparents) * size_logical + &
197  nleafs * ((1+ndim) * size_int + 2 * size_int)) then
198  if (mype == 0) then
199  print *, "Warning: MPI_OFFSET type /= 8 bytes"
200  print *, "This *could* cause problems when reading .dat files"
201  end if
202  end if
203 
204  block_offset(1) = offset_block_data
205  iwrite = 0
206  end if
207 
208  do morton_no=morton_start(mype), morton_stop(mype)
209  igrid = sfc_to_igrid(morton_no)
210  itag = morton_no
211  block=>ps(igrid)
212  ! this might be used in convert function,
213  ! it was not used when the output is already computed vars (write_snapshot)
214  ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
215 
216  ! start copied from block_shape_io,
217  ! because nwc is needed as parameter
218  ! TODO check if this will be used elsewehere and put it in separate subroutine
219  n_ghost(:) = 0
220 
221  if(save_physical_boundary) then
222  do idim=1,ndim
223  ! Include ghost cells on lower boundary
224  if(ps(igrid)%is_physical_boundary(2*idim-1)) n_ghost(idim)=nghostcells
225  ! Include ghost cells on upper boundary
226  if(ps(igrid)%is_physical_boundary(2*idim)) n_ghost(ndim+idim)=nghostcells
227  end do
228  end if
229 
230  {ixomin^d = ixmlo^d - n_ghost(^d)\}
231  {ixomax^d = ixmhi^d + n_ghost(ndim+^d)\}
232 
233  n_values = count_ix(ixo^l) * nwc
234  ! end copied from block_shape_io
235 
236  {iximin^d = ixglo^d\}
237  {iximax^d = ixghi^d\}
238 
239  w_buffer(1:n_values) = pack(convert_vars(ixi^l, ixo^l,ps(igrid)%w(ixi^s, 1:nw), ps(igrid)%x(ixi^s, 1:ndim),nwc), .true.)
240 
241  ix_buffer(1) = n_values
242  ix_buffer(2:) = n_ghost
243 
244  if (mype /= 0) then
245  call mpi_send(ix_buffer, 2*ndim+1, &
246  mpi_integer, 0, itag, icomm, ierrmpi)
247  call mpi_send(w_buffer, n_values, &
248  mpi_double_precision, 0, itag, icomm, ierrmpi)
249  else
250  iwrite = iwrite+1
251  call mpi_file_write(file_handle, ix_buffer(2:), &
252  2*ndim, mpi_integer, istatus, ierrmpi)
253  call mpi_file_write(file_handle, w_buffer, &
254  n_values, mpi_double_precision, istatus, ierrmpi)
255 
256  ! Set offset of next block
257  block_offset(iwrite+1) = block_offset(iwrite) + &
258  int(n_values, mpi_offset_kind) * size_double + &
259  2 * ndim * size_int
260  end if
261  end do
262 
263  ! Write data communicated from other processors
264  if (mype == 0) then
265  do ipe = 1, npe-1
266  do morton_no=morton_start(ipe), morton_stop(ipe)
267  iwrite=iwrite+1
268  itag=morton_no
269 
270  call mpi_recv(ix_buffer, 2*ndim+1, mpi_integer, ipe, itag, icomm,&
271  igrecvstatus, ierrmpi)
272  n_values = ix_buffer(1)
273 
274  call mpi_recv(w_buffer, n_values, mpi_double_precision,&
275  ipe, itag, icomm, iorecvstatus, ierrmpi)
276 
277  call mpi_file_write(file_handle, ix_buffer(2:), &
278  2*ndim, mpi_integer, istatus, ierrmpi)
279  call mpi_file_write(file_handle, w_buffer, &
280  n_values, mpi_double_precision, istatus, ierrmpi)
281 
282  ! Set offset of next block
283  block_offset(iwrite+1) = block_offset(iwrite) + &
284  int(n_values, mpi_offset_kind) * size_double + &
285  2 * ndim * size_int
286  end do
287  end do
288 
289  ! Write block offsets (now we know them)
290  call mpi_file_seek(file_handle, offset_offsets, mpi_seek_set, ierrmpi)
291  call mpi_file_write(file_handle, block_offset(1:nleafs), nleafs, &
292  mpi_offset, istatus, ierrmpi)
293 
294  ! Write header again, now with correct offsets
295  call mpi_file_seek(file_handle, 0_mpi_offset_kind, mpi_seek_set, ierrmpi)
296  call snapshot_write_header1(file_handle, offset_tree_info, &
297  offset_block_data, dataset_names, nwc)
298 
299  call mpi_file_close(file_handle, ierrmpi)
300  end if
301 
302  call mpi_barrier(icomm, ierrmpi)
303 
304  end subroutine convert_dat_generic
305 
306 end module mod_convert
subroutine, public mpistop(message)
Exit MPI-AMRVAC with an error message.
Definition: mod_comm_lib.t:208
subroutine convert_dat_generic(nwc, dataset_names, file_suffix, convert_vars)
Definition: mod_convert.t:102
subroutine add_convert_method2(phys_convert_vars, nwc, aux_variable_names, file_suffix)
Definition: mod_convert.t:38
type(convert_vars_method), pointer head_convert_vars_methods
Definition: mod_convert.t:28
subroutine init_convert()
Definition: mod_convert.t:32
subroutine add_convert_method(phys_convert_vars, nwc, dataset_names, file_suffix)
Definition: mod_convert.t:59
subroutine convert_all()
Definition: mod_convert.t:91
Module with basic grid data structures.
Definition: mod_forest.t:2
integer, dimension(:), allocatable, save sfc_to_igrid
Go from a Morton number to an igrid index (for a single processor)
Definition: mod_forest.t:53
integer, dimension(:), allocatable, save morton_start
First Morton number per processor.
Definition: mod_forest.t:62
integer, save nleafs
Number of leaf block.
Definition: mod_forest.t:76
integer, dimension(:), allocatable, save morton_stop
Last Morton number per processor.
Definition: mod_forest.t:65
integer, dimension(:,:), allocatable, save sfc
Array to go from a Morton number to an igrid and processor index. Sfc(1:3, MN) contains [igrid,...
Definition: mod_forest.t:43
integer, save nparents
Number of parent blocks.
Definition: mod_forest.t:73
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
subroutine, public write_forest(file_handle)
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 ixghi
Upper index of grid block arrays.
integer, parameter ndim
Number of spatial dimensions for grid variables.
logical save_physical_boundary
True for save physical boundary cells in dat files.
integer icomm
The MPI communicator.
integer mype
The rank of the current MPI task.
integer ierrmpi
A global MPI error return code.
integer snapshotnext
IO: snapshot and collapsed views output numbers/labels.
integer npe
The number of MPI tasks.
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, parameter ixglo
Lower index of grid block arrays (always 1)
subroutine, public create_output_file(fh, ix, extension, suffix)
Standard method for creating a new output file.
pure integer function, public count_ix(ixOL)
Compute number of elements in index range.
subroutine, public snapshot_write_header1(fh, offset_tree, offset_block, dataset_names, nw_vars)
Write header for a snapshot, generalize cons_wnames and nw.
character(len=name_len) function, dimension(1:nwc), public get_names_from_string(aux_variable_names, nwc)
subroutine, public block_shape_io(igrid, n_ghost, ixOL, n_values)
Determine the shape of a block for output (whether to include ghost cells, and on which sides)
integer, parameter max_nw
Maximum number of variables.
Definition: mod_variables.t:41
The data structure that contains information about a tree node/grid block.
Definition: mod_forest.t:11