Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Creating Vertical Diffusion Solver #133

Open
wants to merge 13 commits into
base: development
Choose a base branch
from
Open
152 changes: 152 additions & 0 deletions to-be-ccpp-ized/utilities/coords_1d.F90
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
module coords_1d
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just confirming the directory is to be named to-be-ccpp-ized or to-be-ccppized (https://github.com/cacraigucar/atmospheric_physics/tree/atmos_phys_zmcleanup3/to_be_ccppized) since I've seen two variants around!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch @jimmielin!

@nusbaume, @cacraigucar, @peverwhee, we might have discussed this previously so my apologies for not taking better notes but do we have a preferred layout/naming convention for these non-ccppized files? Particularly with coords1d and linear_1d_operators being helper files (which might be needed by other files later) and the high level interface in the solver file.

I think having them at separate layers might be best for organization but not too sure on the naming conventions.


! This module defines the Coords1D type, which is intended to to cache
! commonly used information derived from a collection of sets of 1-D
! coordinates.

use shr_kind_mod, only: r8 => shr_kind_r8

implicit none
private
save

public :: Coords1D

type :: Coords1D
! Number of sets of coordinates in the object.
integer :: n = 0
! Number of coordinates in each set.
integer :: d = 0

! All fields below will be allocated with first dimension "n".
! The second dimension is d+1 for ifc, d for mid, del, and rdel, and
! d-1 for dst and rdst.

! Cell interface coordinates.
real(r8), allocatable :: ifc(:,:)
! Coordinates at cell mid-points.
real(r8), allocatable :: mid(:,:)
! Width of cells.
real(r8), allocatable :: del(:,:)
! Distance between cell midpoints.
real(r8), allocatable :: dst(:,:)
! Reciprocals: 1/del and 1/dst.
real(r8), allocatable :: rdel(:,:)
real(r8), allocatable :: rdst(:,:)
contains
procedure :: section
procedure :: finalize
end type Coords1D

interface Coords1D
module procedure new_Coords1D_from_fields
module procedure new_Coords1D_from_int
end interface

contains

! Constructor to create an object from existing data.
function new_Coords1D_from_fields(ifc, mid, del, dst, &
rdel, rdst) result(coords)
real(r8), USE_CONTIGUOUS intent(in) :: ifc(:,:)
real(r8), USE_CONTIGUOUS intent(in) :: mid(:,:)
real(r8), USE_CONTIGUOUS intent(in) :: del(:,:)
real(r8), USE_CONTIGUOUS intent(in) :: dst(:,:)
real(r8), USE_CONTIGUOUS intent(in) :: rdel(:,:)
real(r8), USE_CONTIGUOUS intent(in) :: rdst(:,:)
type(Coords1D) :: coords

coords = allocate_coords(size(ifc, 1), size(ifc, 2) - 1)

coords%ifc = ifc
coords%mid = mid
coords%del = del
coords%dst = dst
coords%rdel = rdel
coords%rdst = rdst

end function new_Coords1D_from_fields

! Constructor if you only have interface coordinates; derives all the other
! fields.
function new_Coords1D_from_int(ifc) result(coords)
real(r8), USE_CONTIGUOUS intent(in) :: ifc(:,:)
type(Coords1D) :: coords

coords = allocate_coords(size(ifc, 1), size(ifc, 2) - 1)

coords%ifc = ifc
coords%mid = 0.5_r8 * (ifc(:,:coords%d)+ifc(:,2:))
coords%del = coords%ifc(:,2:) - coords%ifc(:,:coords%d)
coords%dst = coords%mid(:,2:) - coords%mid(:,:coords%d-1)
coords%rdel = 1._r8/coords%del
coords%rdst = 1._r8/coords%dst

end function new_Coords1D_from_int

! Create a new Coords1D object that is a subsection of some other object,
! e.g. if you want only the first m coordinates, use d_bnds=[1, m].
!
! Originally this used pointers, but it was found to actually be cheaper
! in practice just to make a copy, especially since pointers can impede
! optimization.
function section(self, n_bnds, d_bnds)
class(Coords1D), intent(in) :: self
integer, intent(in) :: n_bnds(2), d_bnds(2)
type(Coords1D) :: section

section = allocate_coords(n_bnds(2)-n_bnds(1)+1, d_bnds(2)-d_bnds(1)+1)

section%ifc = self%ifc(n_bnds(1):n_bnds(2),d_bnds(1):d_bnds(2)+1)
section%mid = self%mid(n_bnds(1):n_bnds(2),d_bnds(1):d_bnds(2))
section%del = self%del(n_bnds(1):n_bnds(2),d_bnds(1):d_bnds(2))
section%dst = self%dst(n_bnds(1):n_bnds(2),d_bnds(1):d_bnds(2)-1)
section%rdel = self%rdel(n_bnds(1):n_bnds(2),d_bnds(1):d_bnds(2))
section%rdst = self%rdst(n_bnds(1):n_bnds(2),d_bnds(1):d_bnds(2)-1)

end function section

! Quick utility to get allocate each array with the correct size.
function allocate_coords(n, d) result(coords)
integer, intent(in) :: n, d
type(Coords1D) :: coords

coords%n = n
coords%d = d

allocate(coords%ifc(coords%n,coords%d+1))
allocate(coords%mid(coords%n,coords%d))
allocate(coords%del(coords%n,coords%d))
allocate(coords%dst(coords%n,coords%d-1))
allocate(coords%rdel(coords%n,coords%d))
allocate(coords%rdst(coords%n,coords%d-1))

end function allocate_coords

! Deallocate and reset to initial state.
subroutine finalize(self)
class(Coords1D), intent(inout) :: self

self%n = 0
self%d = 0

call guarded_deallocate(self%ifc)
call guarded_deallocate(self%mid)
call guarded_deallocate(self%del)
call guarded_deallocate(self%dst)
call guarded_deallocate(self%rdel)
call guarded_deallocate(self%rdst)

contains

subroutine guarded_deallocate(array)
real(r8), allocatable :: array(:,:)

if (allocated(array)) deallocate(array)

end subroutine guarded_deallocate

end subroutine finalize

end module coords_1d

Loading