FV3 Bundle
drifters_core.F90
Go to the documentation of this file.
1 !***********************************************************************
2 !* GNU Lesser General Public License
3 !*
4 !* This file is part of the GFDL Flexible Modeling System (FMS).
5 !*
6 !* FMS is free software: you can redistribute it and/or modify it under
7 !* the terms of the GNU Lesser General Public License as published by
8 !* the Free Software Foundation, either version 3 of the License, or (at
9 !* your option) any later version.
10 !*
11 !* FMS is distributed in the hope that it will be useful, but WITHOUT
12 !* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 !* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 !* for more details.
15 !*
16 !* You should have received a copy of the GNU Lesser General Public
17 !* License along with FMS. If not, see <http://www.gnu.org/licenses/>.
18 !***********************************************************************
19 !
20 ! nf95 -r8 -g -I ~/regression/ia64/23-Jun-2005/CM2.1U_Control-1990_E1.k32pe/include/ -D_TEST_DRIFTERS -D_F95 quicksort.F90 drifters_core.F90
21 
22 
24 #include <fms_platform.h>
25  implicit none
26  private
27 
30 #ifdef _TEST_DRIFTERS_CORE
32 #endif
33 
34  ! Globals
35  integer, parameter, private :: max_str_len = 128
36 ! Include variable "version" to be written to log file.
37 #include<file_version.h>
38 
40  ! Be sure to update drifters_core_new, drifters_core_del and drifters_core_copy_new
41  ! when adding members
42  integer*8 :: it ! time index
43  integer :: nd ! number of dimensions
44  integer :: np ! number of particles (drifters)
45  integer :: npdim ! max number of particles (drifters)
46  integer, _allocatable :: ids(:)_null ! particle id number
47  real , _allocatable :: positions(:,:) _null
48  end type drifters_core_type
49 
50  interface assignment(=)
51  module procedure drifters_core_copy_new
52  end interface
53 
54 contains
55 
56 !###############################################################################
57  subroutine drifters_core_new(self, nd, npdim, ermesg)
58  type(drifters_core_type) :: self
59  integer, intent(in) :: nd
60  integer, intent(in) :: npdim
61  character(*), intent(out) :: ermesg
62  integer ier, iflag, i
63  ermesg = ''
64  ier = 0
65 
66  call drifters_core_del(self, ermesg)
67 
68  allocate(self%positions(nd, npdim), stat=iflag)
69  if(iflag/=0) ier = ier + 1
70  self%positions = 0.
71 
72  allocate(self%ids(npdim), stat=iflag)
73  if(iflag/=0) ier = ier + 1
74  self%ids = (/(i, i=1,npdim)/)
75 
76  self%nd = nd
77  self%npdim = npdim
78 
79  if(ier/=0) ermesg = 'drifters::ERROR in drifters_core_new'
80  end subroutine drifters_core_new
81 
82  !###############################################################################
83  subroutine drifters_core_del(self, ermesg)
84  type(drifters_core_type) :: self
85  character(*), intent(out) :: ermesg
86  integer ier, iflag
87  ermesg = ''
88  ier = 0
89  self%it = 0
90  self%nd = 0
91  self%np = 0
92  iflag = 0
93  if(_allocated(self%positions)) deallocate(self%positions, stat=iflag)
94  if(iflag/=0) ier = ier + 1
95  if(_allocated(self%ids)) deallocate(self%ids, stat=iflag)
96  if(iflag/=0) ier = ier + 1
97 
98  if(ier/=0) ermesg = 'drifters::ERROR in drifters_core_del'
99  end subroutine drifters_core_del
100 
101  !###############################################################################
102  subroutine drifters_core_copy_new(new_instance, old_instance)
104  type(drifters_core_type), intent(inout) :: new_instance
105  type(drifters_core_type), intent(in) :: old_instance
106 
107  character(len=MAX_STR_LEN) :: ermesg
108 
109  ermesg = ''
110  call drifters_core_del(new_instance, ermesg)
111  if(ermesg/='') return
112  ! this should provide the right behavior for both pointers and allocatables
113  new_instance%it = old_instance%it
114  new_instance%nd = old_instance%nd
115  new_instance%np = old_instance%np
116  new_instance%npdim = old_instance%npdim
117  allocate(new_instance%ids( size(old_instance%ids) ))
118  new_instance%ids = old_instance%ids
119  allocate(new_instance%positions( size(old_instance%positions,1), &
120  & size(old_instance%positions,2) ))
121  new_instance%positions = old_instance%positions
122 
123  end subroutine drifters_core_copy_new
124  !###############################################################################
125  subroutine drifters_core_resize(self, npdim, ermesg)
126  type(drifters_core_type) :: self
127  integer, intent(in) :: npdim ! new max value
128  character(*), intent(out) :: ermesg
129  integer ier, iflag, i
130 
131  real , allocatable :: positions(:,:)
132  integer, allocatable :: ids(:)
133 
134  ermesg = ''
135  ier = 0
136  if(npdim <= self%npdim) return
137 
138  ! temps
139  allocate(positions(self%nd, self%np), stat=iflag)
140  allocate( ids(self%np), stat=iflag)
141 
142  positions = self%positions(:, 1:self%np)
143  ids = self%ids(1:self%np)
144 
145  deallocate(self%positions, stat=iflag)
146  deallocate(self%ids , stat=iflag)
147 
148  allocate(self%positions(self%nd, npdim), stat=iflag)
149  allocate(self%ids(npdim), stat=iflag)
150  self%positions = 0.0
151  ! default id numbers
152  self%ids = (/ (i, i=1,npdim) /)
153  self%positions(:, 1:self%np) = positions
154  self%npdim = npdim
155 
156  if(ier/=0) ermesg = 'drifters::ERROR in drifters_core_resize'
157  end subroutine drifters_core_resize
158 
159 !###############################################################################
160  subroutine drifters_core_set_positions(self, positions, ermesg)
161  type(drifters_core_type) :: self
162  real, intent(in) :: positions(:,:)
163  character(*), intent(out) :: ermesg
164  integer ier !, iflag
165  ermesg = ''
166  ier = 0
167  self%np = min(self%npdim, size(positions, 2))
168  self%positions(:,1:self%np) = positions(:,1:self%np)
169  self%it = self%it + 1
170  if(ier/=0) ermesg = 'drifters::ERROR in drifters_core_set_positions'
171  end subroutine drifters_core_set_positions
172 
173 !###############################################################################
174  subroutine drifters_core_set_ids(self, ids, ermesg)
175  type(drifters_core_type) :: self
176  integer, intent(in) :: ids(:)
177  character(*), intent(out) :: ermesg
178  integer ier, np !, iflag
179  ermesg = ''
180  ier = 0
181  np = min(self%npdim, size(ids))
182  self%ids(1:np) = ids(1:np)
183  if(ier/=0) ermesg = 'drifters::ERROR in drifters_core_set_ids'
184  end subroutine drifters_core_set_ids
185 
186 !###############################################################################
187 subroutine drifters_core_remove_and_add(self, indices_to_remove_in, &
188  & ids_to_add, positions_to_add, &
189  & ermesg)
190  type(drifters_core_type) :: self
191  integer, intent(in ) :: indices_to_remove_in(:)
192  integer, intent(in ) :: ids_to_add(:)
193  real , intent(in ) :: positions_to_add(:,:)
194  character(*), intent(out) :: ermesg
195  integer ier, np_add, np_remove, i, j, n_diff !, iflag
196  integer indices_to_remove(size(indices_to_remove_in))
197  external qksrt_quicksort
198  ermesg = ''
199  ier = 0
200 
201  ! copy, required so we can have indices_to_remove_in intent(in)
202  indices_to_remove = indices_to_remove_in
203  np_remove = size(indices_to_remove)
204  np_add = size(ids_to_add, 1)
205  n_diff = np_add - np_remove
206 
207  ! cannot remove more than there are elements
208  if(self%np + n_diff < 0) then
209  ermesg = 'drifters::ERROR attempting to remove more elements than there are elements in drifters_core_remove_and_add'
210  return
211  endif
212 
213  ! check for overflow, and resize if necessary
214  if(self%np + n_diff > self%npdim) &
215  & call drifters_core_resize(self, int(1.2*(self%np + n_diff))+1, ermesg)
216 
217  do i = 1, min(np_add, np_remove)
218  j = indices_to_remove(i)
219  self%ids(j) = ids_to_add(i)
220  self%positions(:,j) = positions_to_add(:,i)
221  enddo
222 
223  if(n_diff > 0) then
224  ! all the particles to remove were removed and replaced. Just need to append
225  ! remaining particles to end of list
226  self%ids( self%np+1:self%np+n_diff) = ids_to_add( np_remove+1:np_add)
227  self%positions(:, self%np+1:self%np+n_diff) = positions_to_add(:,np_remove+1:np_add)
228 
229  self%np = self%np + n_diff
230 
231  else if(n_diff < 0) then
232  ! all the particles were added by filling in holes left by particles that
233  ! were previously removed. Now remove remaining particles, starting from the end,
234  ! by replacing the missing particle with a copy from the end.
235 
236  ! sort remaining indices in ascending order
237  call qksrt_quicksort(size(indices_to_remove), indices_to_remove, np_add+1, np_remove)
238 
239  do i = np_remove, np_add+1, -1
240  if(self%np <= 0) exit
241  j = indices_to_remove(i)
242  self%ids ( j) = self%ids ( self%np)
243  self%positions(:,j) = self%positions(:,self%np)
244  self%np = self%np - 1
245  enddo
246  endif
247 
248  if(ier/=0) ermesg = 'drifters::ERROR in drifters_core_remove_and_add'
249  end subroutine drifters_core_remove_and_add
250 
251 !###############################################################################
252  subroutine drifters_core_print(self, ermesg)
253  type(drifters_core_type) :: self
254  character(*), intent(out) :: ermesg
255  integer j
256  ermesg = ''
257 
258  print '(a,i10,a,i6,a,i6,a,i4,a,i4,a,i4)','it=',self%it, &
259  & ' np=', self%np, ' npdim=', self%npdim
260 
261  print *,'ids and positions:'
262  do j = 1, self%np
263  print *,self%ids(j), self%positions(:,j)
264  enddo
265 
266  end subroutine drifters_core_print
267 
268 
269 end module drifters_core_mod
270 !###############################################################################
271 !###############################################################################
272 
273 #ifdef _TEST_DRIFTERS_CORE
274 program test
276  implicit none
277  type(drifters_core_type) :: drf
278  integer :: ier, nd, npdim, i, j, np
279  character(128) :: ermesg
280  integer :: npa
281  real , allocatable :: positions(:,:), positions_to_add(:,:)
282 
283  ! c-tor/d-tor tests
284  nd = 3
285  npdim = 2
286  call drifters_core_new(drf, nd, npdim, ermesg)
287  if(ermesg/='') print *,ermesg
288  call drifters_core_del(drf, ermesg)
289  if(ermesg/='') print *,ermesg
290  call drifters_core_new(drf, nd, npdim, ermesg)
291  if(ermesg/='') print *,ermesg
292 
293  call drifters_core_print(drf, ermesg)
294 
295  npdim = 10
296  call drifters_core_resize(drf, npdim, ermesg)
297  if(ermesg/='') print *,ermesg
298  call drifters_core_print(drf, ermesg)
299 
300  np = 7
301  allocate(positions(nd,np))
302  positions(1,:) = (/0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0/) ! x
303  positions(2,:) = (/0.1, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1/) ! y
304  positions(3,:) = (/0.2, 1.2, 2.2, 3.2, 4.2, 5.2, 6.2/) ! z
305  call drifters_core_set_positions(drf, positions, ermesg)
306  if(ermesg/='') print *,ermesg
307  call drifters_core_print(drf, ermesg)
308 
309  ! remove more particles than are added
310  npa = 2
311  allocate(positions_to_add(nd,npa))
312  positions_to_add(1,:) = (/100.0, 200.0/)
313  positions_to_add(2,:) = (/100.1, 200.1/)
314  positions_to_add(3,:) = (/100.2, 200.2/)
315  call drifters_core_remove_and_add(drf, (/2, 6, 1/), &
316  & (/ 1001, 1002 /), &
317  & positions_to_add, &
318  & ermesg)
319  if(ermesg/='') print *,ermesg
320  call drifters_core_print(drf, ermesg)
321  deallocate(positions_to_add)
322 
323  ! add more particles than are removed
324  npa = 3
325  allocate(positions_to_add(nd,npa))
326  positions_to_add(1,:) = (/1000.0, 2000.0, 3000.0/)
327  positions_to_add(2,:) = (/1000.1, 2000.1, 3000.1/)
328  positions_to_add(3,:) = (/1000.2, 2000.2, 3000.2/)
329  call drifters_core_remove_and_add(drf, (/3,1/), &
330  & (/ 1003, 1004, 1005 /), &
331  & positions_to_add, &
332  & ermesg)
333  if(ermesg/='') print *,ermesg
334  call drifters_core_print(drf, ermesg)
335  deallocate(positions_to_add)
336 
337  ! add particles requiring resizing
338  npa = 10
339  allocate(positions_to_add(nd,npa))
340  positions_to_add(1,:) = (/100.0, 200.0, 300.0, 400.0, 500.0, 600.0, 700.0, 800.0, 900.0, 10000.0/)
341  positions_to_add(2,:) = (/100.1, 200.1, 300.1, 400.1, 500.1, 600.1, 700.1, 800.1, 900.1, 10000.1/)
342  positions_to_add(3,:) = (/100.2, 200.2, 300.2, 400.2, 500.2, 600.2, 700.2, 800.2, 900.2, 10000.2/)
343  call drifters_core_remove_and_add(drf, (/3,1,5,2/), &
344  & (/ (1010+i, i=1,npa) /), &
345  & positions_to_add, &
346  & ermesg)
347  if(ermesg/='') print *,ermesg
348  call drifters_core_print(drf, ermesg)
349  deallocate(positions_to_add)
350 
351 !!$ call test_circle(ier)
352 !!$ !call test_3d(ier)
353 !!$
354 !!$ if(ier/=0) then
355 !!$ print *,'Test unit failed ier=', ier
356 !!$ else
357 !!$ print *,'Sucessful test ier=', ier
358 !!$ end if
359 
360 end program test
361 
362 
363 #endif
subroutine drifters_core_set_ids(self, ids, ermesg)
recursive subroutine qksrt_quicksort(n, list, start, end)
Definition: quicksort.F90:75
subroutine, public drifters_core_set_positions(self, positions, ermesg)
subroutine, public drifters_core_new(self, nd, npdim, ermesg)
subroutine drifters_core_copy_new(new_instance, old_instance)
subroutine, public drifters_core_remove_and_add(self, indices_to_remove_in, ids_to_add, positions_to_add, ermesg)
integer, parameter, private max_str_len
subroutine drifters_core_resize(self, npdim, ermesg)
************************************************************************GNU Lesser General Public License **This file is part of the GFDL Flexible Modeling System(FMS). ! *! *FMS is free software without even the implied warranty of MERCHANTABILITY or *FITNESS FOR A PARTICULAR PURPOSE See the GNU General Public License *for more details **You should have received a copy of the GNU Lesser General Public *License along with FMS If see< http:! ***********************************************************************subroutine READ_RECORD_CORE_(unit, field, nwords, data, start, axsiz) integer, intent(in) ::unit type(fieldtype), intent(in) ::field integer, intent(in) ::nwords MPP_TYPE_, intent(inout) ::data(nwords) integer, intent(in) ::start(:), axsiz(:) integer(SHORT_KIND) ::i2vals(nwords)!rab used in conjunction with transfer intrinsic to determine size of a variable integer(KIND=1) ::one_byte(8) integer ::word_sz!#ifdef __sgi integer(INT_KIND) ::ivals(nwords) real(FLOAT_KIND) ::rvals(nwords)!#else! integer ::ivals(nwords)! real ::rvals(nwords)!#endif real(DOUBLE_KIND) ::r8vals(nwords) pointer(ptr1, i2vals) pointer(ptr2, ivals) pointer(ptr3, rvals) pointer(ptr4, r8vals) if(mpp_io_stack_size< nwords) call mpp_io_set_stack_size(nwords) call mpp_error(FATAL, 'MPP_READ currently requires use_netCDF option') end subroutine READ_RECORD_CORE_ subroutine READ_RECORD_(unit, field, nwords, data, time_level, domain, position, tile_count, start_in, axsiz_in)!routine that is finally called by all mpp_read routines to perform the read!a non-netCDF record contains:! field ID! a set of 4 coordinates(is:ie, js:je) giving the data subdomain! a timelevel and a timestamp(=NULLTIME if field is static)! 3D real data(stored as 1D)!if you are using direct access I/O, the RECL argument to OPEN must be large enough for the above!in a global direct access file, record position on PE is given by %record.!Treatment of timestamp:! We assume that static fields have been passed without a timestamp.! Here that is converted into a timestamp of NULLTIME.! For non-netCDF fields, field is treated no differently, but is written! with a timestamp of NULLTIME. There is no check in the code to prevent! the user from repeatedly writing a static field. integer, intent(in) ::unit, nwords type(fieldtype), intent(in) ::field MPP_TYPE_, intent(inout) ::data(nwords) integer, intent(in), optional ::time_level type(domain2D), intent(in), optional ::domain integer, intent(in), optional ::position, tile_count integer, intent(in), optional ::start_in(:), axsiz_in(:) integer, dimension(size(field%axes(:))) ::start, axsiz integer ::tlevel !, subdomain(4) integer ::i, error, is, ie, js, je, isg, ieg, jsg, jeg type(domain2d), pointer ::io_domain=> tlevel if(PRESENT(start_in) .AND. PRESENT(axsiz_in)) then if(size(start(! the data domain and compute domain must refer to the subdomain being passed ! In this ! since that attempts to gather all data on PE size(field%axes(:)) axsiz(i)
subroutine drifters_core_print(self, ermesg)
#define min(a, b)
Definition: mosaic_util.h:32
subroutine, public drifters_core_del(self, ermesg)