SABER
tools_atlas.F90
Go to the documentation of this file.
1 !----------------------------------------------------------------------
2 ! Module: tools_atlas
3 !> Random numbers generator derived type
4 ! Author: Benjamin Menetrier
5 ! Licensing: this code is distributed under the CeCILL-C license
6 ! Copyright © 2015-... UCAR, CERFACS, METEO-FRANCE and IRIT
7 !----------------------------------------------------------------------
8 
9 module tools_atlas
10 
11 use atlas_module, only: atlas_field,atlas_fieldset,atlas_integer,atlas_real,atlas_functionspace,atlas_functionspace_nodecolumns, &
12  & atlas_functionspace_pointcloud,atlas_functionspace_structuredcolumns
13 use tools_const, only: rad2deg
15 use type_mpl, only: mpl_type
16 
17 implicit none
18 
19 interface field_to_array
20  module procedure field_to_array_real
21  module procedure field_to_array_logical
22 end interface
23 
25  module procedure field_from_array_real
26 end interface
27 
28 private
30 
31 contains
32 
33 !----------------------------------------------------------------------
34 ! Subroutine: field_to_array_real
35 !> Convert ATLAS field to field, real
36 !----------------------------------------------------------------------
37 subroutine field_to_array_real(mpl,afield,fld,lev2d)
38 
39 implicit none
40 
41 ! Passed variables
42 type(mpl_type),intent(inout) :: mpl !< MPI data
43 type(atlas_field),intent(in) :: afield !< ATLAS field
44 real(kind_real),intent(out) :: fld(:,:) !< Field
45 character(len=*),intent(in),optional :: lev2d !< Level for 2D variables
46 
47 ! Local variables
48 integer :: nmga,nl0
49 real(kind_real),pointer :: ptr_1(:),ptr_2(:,:)
50 character(len=1024) :: llev2d
51 character(len=1024),parameter :: subr = 'field_to_array_real'
52 type(atlas_functionspace) :: afunctionspace
53 type(atlas_functionspace_nodecolumns) :: afunctionspace_nc
54 type(atlas_functionspace_pointcloud) :: afunctionspace_pc
55 type(atlas_functionspace_structuredcolumns) :: afunctionspace_sc
56 
57 ! Local lev2d
58 llev2d = 'first'
59 if (present(lev2d)) llev2d = lev2d
60 
61 ! Check kind
62 if (afield%kind()/=atlas_real(kind_real)) call mpl%abort(subr,'wrong kind for field '//afield%name())
63 
64 ! Get generic functionspace
65 afunctionspace = afield%functionspace()
66 
67 select case (afunctionspace%name())
68 case ('NodeColumns')
69  ! Get NodeColumns function space
70  afunctionspace_nc = afield%functionspace()
71 
72  ! Get number of nodes
73  nmga = afunctionspace_nc%nb_nodes()
74 case ('PointCloud')
75  ! Get PointCloud function space
76  afunctionspace_pc = afield%functionspace()
77 
78  ! Get number of points
79  nmga = afunctionspace_pc%size()
80 case ('StructuredColumns')
81  ! Get StructuredColumns function space
82  afunctionspace_sc = afield%functionspace()
83 
84  ! Get number of nodes
85  nmga = afunctionspace_sc%size_owned()
86 case default
87  call mpl%abort(subr,'wrong function space for field '//afield%name()//': '//afunctionspace%name())
88 end select
89 
90 ! Check number of nodes
91 if (nmga/=size(fld,1)) call mpl%abort(subr,'wrong number of nodes for field '//afield%name())
92 
93 ! Get number of levels
94 ! - afield%levels() is 0 for 2D ATLAS fields, positive for 3D fields
95 ! - the size of the second dimension of fld is always positive
96 ! - to ensure that sizes are compatible for copying data, we use the minimum between the two
97 nl0 = min(afield%levels(),size(fld,2))
98 
99 ! Initialization
100 fld = 0.0
101 
102 ! Copy data
103 ! For the 2D case (afield%levels()==0), the field is copied:
104 ! - at the first level of fld if (lev2d=='first')
105 ! - at the last level of fld if (lev2d=='last')
106 ! NB: an ATLAS field with 1 level only (afield%levels()==1) is considered as a 3D field, so lev2d does not apply
107 if (nl0==0) then
108  if (size(fld,2)>0) then
109  call afield%data(ptr_1)
110  if (trim(llev2d)=='first') then
111  fld(1:nmga,1) = ptr_1(1:nmga)
112  elseif (trim(llev2d)=='last') then
113  fld(1:nmga,size(fld,2)) = ptr_1(1:nmga)
114  end if
115  end if
116 else
117  call afield%data(ptr_2)
118  fld(1:nmga,1:nl0) = transpose(ptr_2(1:nl0,1:nmga))
119 end if
120 
121 end subroutine field_to_array_real
122 
123 !----------------------------------------------------------------------
124 ! Subroutine: field_to_array_logical
125 !> Convert ATLAS field to field, logical
126 !----------------------------------------------------------------------
127 subroutine field_to_array_logical(mpl,afield,fld,lev2d)
128 
129 implicit none
130 
131 ! Passed variables
132 type(mpl_type),intent(inout) :: mpl !< MPI data
133 type(atlas_field),intent(in) :: afield !< ATLAS field
134 logical,intent(out) :: fld(:,:) !< Field
135 character(len=*),intent(in),optional :: lev2d !< Level for 2D variables
136 
137 ! Local variables
138 integer :: nmga,nl0,imga,il0
139 integer,allocatable :: fld_int(:,:)
140 integer,pointer :: ptr_1(:),ptr_2(:,:)
141 character(len=1024) :: llev2d
142 character(len=1024),parameter :: subr = 'field_to_array_logical'
143 type(atlas_functionspace) :: afunctionspace
144 type(atlas_functionspace_nodecolumns) :: afunctionspace_nc
145 type(atlas_functionspace_pointcloud) :: afunctionspace_pc
146 type(atlas_functionspace_structuredcolumns) :: afunctionspace_sc
147 
148 ! Local lev2d
149 llev2d = 'first'
150 if (present(lev2d)) llev2d = lev2d
151 
152 ! Check kind
153 if (afield%kind()/=atlas_integer(kind_int)) call mpl%abort(subr,'wrong kind for field '//afield%name())
154 
155 ! Get generic FunctionSpace
156 afunctionspace = afield%functionspace()
157 
158 select case (afunctionspace%name())
159 case ('NodeColumns')
160  ! Get NodeColumns function space
161  afunctionspace_nc = afield%functionspace()
162 
163  ! Get number of nodes
164  nmga = afunctionspace_nc%nb_nodes()
165 case ('PointCloud')
166  ! Get PointCloud function space
167  afunctionspace_pc = afield%functionspace()
168 
169  ! Get number of points
170  nmga = afunctionspace_pc%size()
171 case ('StructuredColumns')
172  ! Get StructuredColumns function space
173  afunctionspace_sc = afield%functionspace()
174 
175  ! Get number of nodes
176  nmga = afunctionspace_sc%size_owned()
177 case default
178  call mpl%abort(subr,'wrong function space for field '//afield%name()//': '//afunctionspace%name())
179 end select
180 
181 ! Check number of nodes
182 if (nmga/=size(fld,1)) call mpl%abort(subr,'wrong number of nodes for field '//afield%name())
183 
184 ! Get number of levels
185 ! - afield%levels() is 0 for 2D ATLAS fields, positive for 3D fields
186 ! - the size of the second dimension of fld is always positive
187 ! - to ensure that sizes are compatible for copying data, we use the minimum between the two
188 nl0 = min(afield%levels(),size(fld,2))
189 
190 ! Allocation
191 allocate(fld_int(size(fld,1),size(fld,2)))
192 
193 ! Initialization
194 fld_int = 0
195 
196 ! Copy data
197 ! For the 2D case (afield%levels()==0), the 2D field is copied:
198 ! - at the first level of fld if (lev2d=='first')
199 ! - at the last level of fld if (lev2d=='last')
200 ! NB: an ATLAS field with 1 level only (afield%levels()==1) is considered as a 3D field, so lev2d does not apply
201 if (nl0==0) then
202  if (size(fld,2)>0) then
203  call afield%data(ptr_1)
204  if (trim(llev2d)=='first') then
205  fld_int(1:nmga,1) = ptr_1(1:nmga)
206  elseif (trim(llev2d)=='last') then
207  fld_int(1:nmga,size(fld,2)) = ptr_1(1:nmga)
208  end if
209  end if
210 else
211  call afield%data(ptr_2)
212  fld_int(1:nmga,1:nl0) = transpose(ptr_2(1:nl0,1:nmga))
213 end if
214 
215 ! Integer to logical
216 do il0=1,size(fld,2)
217  do imga=1,size(fld,1)
218  if (fld_int(imga,il0)==0) then
219  fld(imga,il0) = .false.
220  elseif (fld_int(imga,il0)==1) then
221  fld(imga,il0) = .true.
222  else
223  call mpl%abort(subr,'wrong value in 0-1 integer field for field '//afield%name())
224  end if
225  end do
226 end do
227 
228 ! Release memory
229 deallocate(fld_int)
230 
231 end subroutine field_to_array_logical
232 
233 !----------------------------------------------------------------------
234 ! Subroutine: field_from_array_real
235 !> Convert field to ATLAS field, real
236 !----------------------------------------------------------------------
237 subroutine field_from_array_real(mpl,fld,afield,lev2d)
238 
239 implicit none
240 
241 ! Passed variables
242 type(mpl_type),intent(inout) :: mpl !< MPI data
243 real(kind_real),intent(in) :: fld(:,:) !< Field
244 type(atlas_field),intent(inout) :: afield !< ATLAS field
245 character(len=*),intent(in),optional :: lev2d !< Level for 2D variables
246 
247 ! Local variables
248 integer :: nmga,nl0
249 real(kind_real),pointer :: ptr_1(:),ptr_2(:,:)
250 character(len=1024) :: llev2d
251 character(len=1024),parameter :: subr = 'field_from_array_real'
252 type(atlas_functionspace) :: afunctionspace
253 type(atlas_functionspace_nodecolumns) :: afunctionspace_nc
254 type(atlas_functionspace_pointcloud) :: afunctionspace_pc
255 type(atlas_functionspace_structuredcolumns) :: afunctionspace_sc
256 
257 ! Local lev2d
258 llev2d = 'first'
259 if (present(lev2d)) llev2d = lev2d
260 
261 ! Check kind
262 if (afield%kind()/=atlas_real(kind_real)) call mpl%abort(subr,'wrong kind for field '//afield%name())
263 
264 ! Get generic FunctionSpace
265 afunctionspace = afield%functionspace()
266 
267 select case (afunctionspace%name())
268 case ('NodeColumns')
269  ! Get NodeColumns function space
270  afunctionspace_nc = afield%functionspace()
271 
272  ! Get number of nodes
273  nmga = afunctionspace_nc%nb_nodes()
274 case ('PointCloud')
275  ! Get PointCloud function space
276  afunctionspace_pc = afield%functionspace()
277 
278  ! Get number of points
279  nmga = afunctionspace_pc%size()
280 case ('StructuredColumns')
281  ! Get StructuredColumns function space
282  afunctionspace_sc = afield%functionspace()
283 
284  ! Get number of nodes
285  nmga = afunctionspace_sc%size_owned()
286 case default
287  call mpl%abort(subr,'wrong function space for field '//afield%name()//': '//afunctionspace%name())
288 end select
289 
290 ! Get number of levels
291 ! - afield%levels() is 0 for 2D ATLAS fields, positive for 3D fields
292 ! - the size of the second dimension of fld is always positive
293 ! - to ensure that sizes are compatible for copying data, we use the minimum between the two
294 nl0 = min(afield%levels(),size(fld,2))
295 
296 ! Check number of nodes
297 if (nmga/=size(fld,1)) call mpl%abort(subr,'wrong number of nodes for field '//afield%name())
298 
299 ! Copy data
300 ! For the 2D case (afield%levels()==0), the field is copied:
301 ! - at the first level of fld if (lev2d=='first')
302 ! - at the last level of fld if (lev2d=='last')
303 ! NB: an ATLAS field with 1 level only (afield%levels()==1) is considered as a 3D field, so lev2d does not apply
304 if (nl0==0) then
305  if (size(fld,2)>0) then
306  call afield%data(ptr_1)
307  if (trim(llev2d)=='first') then
308  ptr_1(1:nmga) = fld(1:nmga,1)
309  elseif (trim(llev2d)=='last') then
310  ptr_1(1:nmga) = fld(1:nmga,size(fld,2))
311  end if
312  end if
313 else
314  call afield%data(ptr_2)
315  ptr_2(1:nl0,1:nmga) = transpose(fld(1:nmga,1:nl0))
316 end if
317 
318 end subroutine field_from_array_real
319 
320 !----------------------------------------------------------------------
321 ! Subroutine: create_atlas_function_space
322 !> Create ATLAS function space
323 !----------------------------------------------------------------------
324 subroutine create_atlas_function_space(nmga,lon_mga,lat_mga,afunctionspace)
325 
326 implicit none
327 
328 ! Passed variables
329 integer,intent(in) :: nmga !< Number of nodes
330 real(kind_real),intent(in) :: lon_mga(nmga) !< Longitudes
331 real(kind_real),intent(in) :: lat_mga(nmga) !< Latitudes
332 type(atlas_functionspace),intent(out) :: afunctionspace !< ATLAS function space
333 
334 ! Local variables
335 integer :: imga
336 real(kind_real),pointer :: real_ptr(:,:)
337 type(atlas_field) :: afield
338 
339 ! Create lon/lat field
340 afield = atlas_field(name="lonlat",kind=atlas_real(kind_real),shape=(/2,nmga/))
341 call afield%data(real_ptr)
342 do imga=1,nmga
343  real_ptr(1,imga) = lon_mga(imga)*rad2deg
344  real_ptr(2,imga) = lat_mga(imga)*rad2deg
345 end do
346 
347 ! Create function space PointCloud
348 afunctionspace = atlas_functionspace_pointcloud(afield)
349 
350 end subroutine create_atlas_function_space
351 
352 end module tools_atlas
tools_const
Define usual constants and missing values.
Definition: tools_const.F90:8
tools_atlas::create_atlas_function_space
subroutine, public create_atlas_function_space(nmga, lon_mga, lat_mga, afunctionspace)
Create ATLAS function space.
Definition: tools_atlas.F90:325
tools_atlas::field_to_array_real
subroutine field_to_array_real(mpl, afield, fld, lev2d)
Convert ATLAS field to field, real.
Definition: tools_atlas.F90:38
tools_atlas::field_from_array
Definition: tools_atlas.F90:24
tools_atlas
Random numbers generator derived type.
Definition: tools_atlas.F90:9
tools_atlas::field_from_array_real
subroutine field_from_array_real(mpl, fld, afield, lev2d)
Convert field to ATLAS field, real.
Definition: tools_atlas.F90:238
tools_atlas::field_to_array_logical
subroutine field_to_array_logical(mpl, afield, fld, lev2d)
Convert ATLAS field to field, logical.
Definition: tools_atlas.F90:128
tools_atlas::field_to_array
Definition: tools_atlas.F90:19
tools_kinds
Kinds definition.
Definition: tools_kinds.F90:8
tools_const::rad2deg
real(kind_real), parameter, public rad2deg
Definition: tools_const.F90:16
type_mpl
MPI parameters derived type.
Definition: type_mpl.F90:8
type_mpl::mpl_type
Definition: type_mpl.F90:24
tools_kinds::kind_real
integer, parameter, public kind_real
Definition: tools_kinds.F90:18
tools_kinds::kind_int
integer, parameter, public kind_int
Definition: tools_kinds.F90:16