!***********************************************************************
!* GNU Lesser General Public License
!*
!* This file is part of the GFDL Flexible Modeling System (FMS).
!*
!* FMS is free software: you can redistribute it and/or modify it under
!* the terms of the GNU Lesser General Public License as published by
!* the Free Software Foundation, either version 3 of the License, or (at
!* your option) any later version.
!*
!* FMS is distributed in the hope that it will be useful, but WITHOUT
!* ANY WARRANTY; 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 not, see .
!***********************************************************************
!
! 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
module drifters_core_mod
#include
implicit none
private
public :: drifters_core_type, drifters_core_new, drifters_core_del, drifters_core_set_ids
public :: drifters_core_remove_and_add, drifters_core_set_positions, assignment(=)
!#ifdef _TEST_DRIFTERS_CORE
public :: drifters_core_print, drifters_core_resize
!#endif
! Globals
integer, parameter, private :: MAX_STR_LEN = 128
! Include variable "version" to be written to log file.
#include
type drifters_core_type
! Be sure to update drifters_core_new, drifters_core_del and drifters_core_copy_new
! when adding members
integer*8 :: it ! time index
integer :: nd ! number of dimensions
integer :: np ! number of particles (drifters)
integer :: npdim ! max number of particles (drifters)
integer, _ALLOCATABLE :: ids(:)_NULL ! particle id number
real , _ALLOCATABLE :: positions(:,:) _NULL
end type drifters_core_type
interface assignment(=)
module procedure drifters_core_copy_new
end interface
contains
!###############################################################################
subroutine drifters_core_new(self, nd, npdim, ermesg)
type(drifters_core_type) :: self
integer, intent(in) :: nd
integer, intent(in) :: npdim
character(*), intent(out) :: ermesg
integer ier, iflag, i
ermesg = ''
ier = 0
call drifters_core_del(self, ermesg)
allocate(self%positions(nd, npdim), stat=iflag)
if(iflag/=0) ier = ier + 1
self%positions = 0.
allocate(self%ids(npdim), stat=iflag)
if(iflag/=0) ier = ier + 1
self%ids = (/(i, i=1,npdim)/)
self%nd = nd
self%npdim = npdim
if(ier/=0) ermesg = 'drifters::ERROR in drifters_core_new'
end subroutine drifters_core_new
!###############################################################################
subroutine drifters_core_del(self, ermesg)
type(drifters_core_type) :: self
character(*), intent(out) :: ermesg
integer ier, iflag
ermesg = ''
ier = 0
self%it = 0
self%nd = 0
self%np = 0
iflag = 0
if(_ALLOCATED(self%positions)) deallocate(self%positions, stat=iflag)
if(iflag/=0) ier = ier + 1
if(_ALLOCATED(self%ids)) deallocate(self%ids, stat=iflag)
if(iflag/=0) ier = ier + 1
if(ier/=0) ermesg = 'drifters::ERROR in drifters_core_del'
end subroutine drifters_core_del
!###############################################################################
subroutine drifters_core_copy_new(new_instance, old_instance)
type(drifters_core_type), intent(inout) :: new_instance
type(drifters_core_type), intent(in) :: old_instance
character(len=MAX_STR_LEN) :: ermesg
ermesg = ''
call drifters_core_del(new_instance, ermesg)
if(ermesg/='') return
! this should provide the right behavior for both pointers and allocatables
new_instance%it = old_instance%it
new_instance%nd = old_instance%nd
new_instance%np = old_instance%np
new_instance%npdim = old_instance%npdim
allocate(new_instance%ids( size(old_instance%ids) ))
new_instance%ids = old_instance%ids
allocate(new_instance%positions( size(old_instance%positions,1), &
& size(old_instance%positions,2) ))
new_instance%positions = old_instance%positions
end subroutine drifters_core_copy_new
!###############################################################################
subroutine drifters_core_resize(self, npdim, ermesg)
type(drifters_core_type) :: self
integer, intent(in) :: npdim ! new max value
character(*), intent(out) :: ermesg
integer ier, iflag, i
real , allocatable :: positions(:,:)
integer, allocatable :: ids(:)
ermesg = ''
ier = 0
if(npdim <= self%npdim) return
! temps
allocate(positions(self%nd, self%np), stat=iflag)
allocate( ids(self%np), stat=iflag)
positions = self%positions(:, 1:self%np)
ids = self%ids(1:self%np)
deallocate(self%positions, stat=iflag)
deallocate(self%ids , stat=iflag)
allocate(self%positions(self%nd, npdim), stat=iflag)
allocate(self%ids(npdim), stat=iflag)
self%positions = 0.0
! default id numbers
self%ids = (/ (i, i=1,npdim) /)
self%positions(:, 1:self%np) = positions
self%npdim = npdim
if(ier/=0) ermesg = 'drifters::ERROR in drifters_core_resize'
end subroutine drifters_core_resize
!###############################################################################
subroutine drifters_core_set_positions(self, positions, ermesg)
type(drifters_core_type) :: self
real, intent(in) :: positions(:,:)
character(*), intent(out) :: ermesg
integer ier !, iflag
ermesg = ''
ier = 0
self%np = min(self%npdim, size(positions, 2))
self%positions(:,1:self%np) = positions(:,1:self%np)
self%it = self%it + 1
if(ier/=0) ermesg = 'drifters::ERROR in drifters_core_set_positions'
end subroutine drifters_core_set_positions
!###############################################################################
subroutine drifters_core_set_ids(self1, ids1, ermesg1)
type(drifters_core_type) :: self1
integer, intent(in) :: ids1(:)
character(*), intent(out) :: ermesg1
integer ier, np !, iflag
ermesg1 = ''
ier = 0
np = min(self1%npdim, size(ids1))
self1%ids(1:np) = ids1(1:np)
if(ier/=0) ermesg1 = 'drifters::ERROR in drifters_core_set_ids'
end subroutine drifters_core_set_ids
!###############################################################################
subroutine drifters_core_remove_and_add(self, indices_to_remove_in, &
& ids_to_add, positions_to_add, &
& ermesg)
type(drifters_core_type) :: self
integer, intent(in ) :: indices_to_remove_in(:)
integer, intent(in ) :: ids_to_add(:)
real , intent(in ) :: positions_to_add(:,:)
character(*), intent(out) :: ermesg
integer ier, np_add, np_remove, i, j, n_diff !, iflag
integer indices_to_remove(size(indices_to_remove_in))
external qksrt_quicksort
ermesg = ''
ier = 0
! copy, required so we can have indices_to_remove_in intent(in)
indices_to_remove = indices_to_remove_in
np_remove = size(indices_to_remove)
np_add = size(ids_to_add, 1)
n_diff = np_add - np_remove
! cannot remove more than there are elements
if(self%np + n_diff < 0) then
ermesg = 'drifters::ERROR attempting to remove more elements than there are elements in drifters_core_remove_and_add'
return
endif
! check for overflow, and resize if necessary
if(self%np + n_diff > self%npdim) &
& call drifters_core_resize(self, int(1.2*(self%np + n_diff))+1, ermesg)
do i = 1, min(np_add, np_remove)
j = indices_to_remove(i)
self%ids(j) = ids_to_add(i)
self%positions(:,j) = positions_to_add(:,i)
enddo
if(n_diff > 0) then
! all the particles to remove were removed and replaced. Just need to append
! remaining particles to end of list
self%ids( self%np+1:self%np+n_diff) = ids_to_add( np_remove+1:np_add)
self%positions(:, self%np+1:self%np+n_diff) = positions_to_add(:,np_remove+1:np_add)
self%np = self%np + n_diff
else if(n_diff < 0) then
! all the particles were added by filling in holes left by particles that
! were previously removed. Now remove remaining particles, starting from the end,
! by replacing the missing particle with a copy from the end.
! sort remaining indices in ascending order
call qksrt_quicksort(size(indices_to_remove), indices_to_remove, np_add+1, np_remove)
do i = np_remove, np_add+1, -1
if(self%np <= 0) exit
j = indices_to_remove(i)
self%ids ( j) = self%ids ( self%np)
self%positions(:,j) = self%positions(:,self%np)
self%np = self%np - 1
enddo
endif
if(ier/=0) ermesg = 'drifters::ERROR in drifters_core_remove_and_add'
end subroutine drifters_core_remove_and_add
!###############################################################################
subroutine drifters_core_print(self1, ermesg1)
type(drifters_core_type) :: self1
character(*), intent(out) :: ermesg1
integer j
ermesg1 = ''
print '(a,i10,a,i6,a,i6,a,i4,a,i4,a,i4)','it=',self1%it, &
& ' np=', self1%np, ' npdim=', self1%npdim
print *,'ids and positions:'
do j = 1, self1%np
print *,self1%ids(j), self1%positions(:,j)
enddo
end subroutine drifters_core_print
end module drifters_core_mod
!###############################################################################
!###############################################################################