Skip to content

Commit 4d80987

Browse files
Changes to reduce potential memory leaks (ESCOMP#268)
Originator(s): johnmauff, cacraigucar Description (include issue title and the keyword ['closes', 'fixes', 'resolves'] and issue number): - Part of changes coming in with ESCOMP/CAM#1356 List all namelist files that were added or changed: N/A List all files eliminated and why: N/A List all files added and what they do: N/A List all existing files that have been modified, and describe the changes: (Helpful git command: `git diff --name-status development...<your_branch_name>`) M to_be_ccppized/coords_1d.F90 - Add "finalize" subroutine to coords1d type to ensure that it is deallocated at the correct time/scope, which helps prevent/reduce memory leaks. Also perform some white-space cleanup. List all automated tests that failed, as well as an explanation for why they weren't fixed: All automated tests pass. Is this an answer-changing PR? If so, is it a new physics package, algorithm change, tuning change, etc? No, this is a non-answer-changing PR (i.e. bit-for-bit). If yes to the above question, describe how this code was validated with the new/modified features: --------- Co-authored-by: Jesse Nusbaumer <nusbaume@ucar.edu>
1 parent 73fce27 commit 4d80987

1 file changed

Lines changed: 146 additions & 151 deletions

File tree

to_be_ccppized/coords_1d.F90

Lines changed: 146 additions & 151 deletions
Original file line numberDiff line numberDiff line change
@@ -1,154 +1,149 @@
11
module coords_1d
22

3-
! This module defines the Coords1D type, which is intended to to cache
4-
! commonly used information derived from a collection of sets of 1-D
5-
! coordinates.
6-
7-
use shr_kind_mod, only: r8 => shr_kind_r8
8-
9-
implicit none
10-
private
11-
save
12-
13-
public :: coords1d
14-
15-
!! \section arg_table_coords1d
16-
!! \htmlinclude coords1d.html
17-
type :: coords1d
18-
! Number of sets of coordinates in the object.
19-
integer :: n = 0
20-
! Number of coordinates in each set.
21-
integer :: d = 0
22-
23-
! All fields below will be allocated with first dimension "n".
24-
! The second dimension is d+1 for ifc, d for mid, del, and rdel, and
25-
! d-1 for dst and rdst.
26-
27-
! Cell interface coordinates.
28-
real(r8), allocatable :: ifc(:,:)
29-
! Coordinates at cell mid-points.
30-
real(r8), allocatable :: mid(:,:)
31-
! Width of cells.
32-
real(r8), allocatable :: del(:,:)
33-
! Distance between cell midpoints.
34-
real(r8), allocatable :: dst(:,:)
35-
! Reciprocals: 1/del and 1/dst.
36-
real(r8), allocatable :: rdel(:,:)
37-
real(r8), allocatable :: rdst(:,:)
38-
contains
39-
procedure :: section
40-
procedure :: finalize
41-
end type coords1d
42-
43-
interface Coords1D
44-
module procedure new_Coords1D_from_fields
45-
module procedure new_Coords1D_from_int
46-
end interface
47-
48-
contains
49-
50-
! Constructor to create an object from existing data.
51-
function new_Coords1D_from_fields(ifc, mid, del, dst, &
52-
rdel, rdst) result(coords)
53-
real(r8), USE_CONTIGUOUS intent(in) :: ifc(:,:)
54-
real(r8), USE_CONTIGUOUS intent(in) :: mid(:,:)
55-
real(r8), USE_CONTIGUOUS intent(in) :: del(:,:)
56-
real(r8), USE_CONTIGUOUS intent(in) :: dst(:,:)
57-
real(r8), USE_CONTIGUOUS intent(in) :: rdel(:,:)
58-
real(r8), USE_CONTIGUOUS intent(in) :: rdst(:,:)
59-
type(Coords1D) :: coords
60-
61-
coords = allocate_coords(size(ifc, 1), size(ifc, 2) - 1)
62-
63-
coords%ifc(:,:) = ifc(:,:)
64-
coords%mid(:,:) = mid(:,:)
65-
coords%del(:,:) = del(:,:)
66-
coords%dst(:,:) = dst(:,:)
67-
coords%rdel(:,:) = rdel(:,:)
68-
coords%rdst(:,:) = rdst(:,:)
69-
70-
end function new_Coords1D_from_fields
71-
72-
! Constructor if you only have interface coordinates; derives all the other
73-
! fields.
74-
function new_Coords1D_from_int(ifc) result(coords)
75-
real(r8), USE_CONTIGUOUS intent(in) :: ifc(:,:)
76-
type(Coords1D) :: coords
77-
78-
coords = allocate_coords(size(ifc, 1), size(ifc, 2) - 1)
79-
80-
coords%ifc(:,:) = ifc(:,:)
81-
coords%mid(:,:) = 0.5_r8 * (ifc(:,:coords%d)+ifc(:,2:))
82-
coords%del(:,:) = coords%ifc(:,2:) - coords%ifc(:,:coords%d)
83-
coords%dst(:,:) = coords%mid(:,2:) - coords%mid(:,:coords%d-1)
84-
coords%rdel(:,:) = 1._r8/coords%del(:,:)
85-
coords%rdst(:,:) = 1._r8/coords%dst(:,:)
86-
87-
end function new_Coords1D_from_int
88-
89-
! Create a new Coords1D object that is a subsection of some other object,
90-
! e.g. if you want only the first m coordinates, use d_bnds=[1, m].
91-
!
92-
! Originally this used pointers, but it was found to actually be cheaper
93-
! in practice just to make a copy, especially since pointers can impede
94-
! optimization.
95-
function section(self, n_bnds, d_bnds)
96-
class(Coords1D), intent(in) :: self
97-
integer, intent(in) :: n_bnds(2), d_bnds(2)
98-
type(Coords1D) :: section
99-
100-
section = allocate_coords(n_bnds(2)-n_bnds(1)+1, d_bnds(2)-d_bnds(1)+1)
101-
102-
section%ifc(:,:) = self%ifc(n_bnds(1):n_bnds(2),d_bnds(1):d_bnds(2)+1)
103-
section%mid(:,:) = self%mid(n_bnds(1):n_bnds(2),d_bnds(1):d_bnds(2))
104-
section%del(:,:) = self%del(n_bnds(1):n_bnds(2),d_bnds(1):d_bnds(2))
105-
section%dst(:,:) = self%dst(n_bnds(1):n_bnds(2),d_bnds(1):d_bnds(2)-1)
106-
section%rdel(:,:) = self%rdel(n_bnds(1):n_bnds(2),d_bnds(1):d_bnds(2))
107-
section%rdst(:,:) = self%rdst(n_bnds(1):n_bnds(2),d_bnds(1):d_bnds(2)-1)
108-
109-
end function section
110-
111-
! Quick utility to get allocate each array with the correct size.
112-
function allocate_coords(n, d) result(coords)
113-
integer, intent(in) :: n, d
114-
type(Coords1D) :: coords
115-
116-
coords%n = n
117-
coords%d = d
118-
119-
allocate(coords%ifc(coords%n,coords%d+1))
120-
allocate(coords%mid(coords%n,coords%d))
121-
allocate(coords%del(coords%n,coords%d))
122-
allocate(coords%dst(coords%n,coords%d-1))
123-
allocate(coords%rdel(coords%n,coords%d))
124-
allocate(coords%rdst(coords%n,coords%d-1))
125-
126-
end function allocate_coords
127-
128-
! Deallocate and reset to initial state.
129-
subroutine finalize(self)
130-
class(Coords1D), intent(inout) :: self
131-
132-
self%n = 0
133-
self%d = 0
134-
135-
call guarded_deallocate(self%ifc)
136-
call guarded_deallocate(self%mid)
137-
call guarded_deallocate(self%del)
138-
call guarded_deallocate(self%dst)
139-
call guarded_deallocate(self%rdel)
140-
call guarded_deallocate(self%rdst)
141-
142-
contains
143-
144-
subroutine guarded_deallocate(array)
145-
real(r8), allocatable :: array(:,:)
146-
147-
if (allocated(array)) deallocate(array)
148-
149-
end subroutine guarded_deallocate
150-
151-
end subroutine finalize
152-
3+
! This module defines the Coords1D type, which is intended to to cache
4+
! commonly used information derived from a collection of sets of 1-D
5+
! coordinates.
6+
7+
use shr_kind_mod, only: r8 => shr_kind_r8
8+
9+
implicit none
10+
private
11+
save
12+
13+
public :: coords1d
14+
15+
!! \section arg_table_coords1d
16+
!! \htmlinclude coords1d.html
17+
type :: coords1d
18+
! Number of sets of coordinates in the object.
19+
integer :: n = 0
20+
! Number of coordinates in each set.
21+
integer :: d = 0
22+
23+
! All fields below will be allocated with first dimension "n".
24+
! The second dimension is d+1 for ifc, d for mid, del, and rdel, and
25+
! d-1 for dst and rdst.
26+
27+
! Cell interface coordinates.
28+
real(r8), allocatable :: ifc(:,:)
29+
! Coordinates at cell mid-points.
30+
real(r8), allocatable :: mid(:,:)
31+
! Width of cells.
32+
real(r8), allocatable :: del(:,:)
33+
! Distance between cell midpoints.
34+
real(r8), allocatable :: dst(:,:)
35+
! Reciprocals: 1/del and 1/dst.
36+
real(r8), allocatable :: rdel(:,:)
37+
real(r8), allocatable :: rdst(:,:)
38+
contains
39+
procedure :: section
40+
procedure :: finalize ! User-callable
41+
final :: finalize_Coords1D ! Auto-finalize
42+
end type coords1d
43+
44+
interface Coords1D
45+
module procedure new_Coords1D_from_fields
46+
module procedure new_Coords1D_from_int
47+
end interface
48+
49+
contains
50+
51+
! Constructor to create an object from existing data.
52+
function new_Coords1D_from_fields(ifc, mid, del, dst, &
53+
rdel, rdst) result(coords)
54+
real(r8), USE_CONTIGUOUS intent(in) :: ifc(:,:)
55+
real(r8), USE_CONTIGUOUS intent(in) :: mid(:,:)
56+
real(r8), USE_CONTIGUOUS intent(in) :: del(:,:)
57+
real(r8), USE_CONTIGUOUS intent(in) :: dst(:,:)
58+
real(r8), USE_CONTIGUOUS intent(in) :: rdel(:,:)
59+
real(r8), USE_CONTIGUOUS intent(in) :: rdst(:,:)
60+
type(Coords1D) :: coords
61+
62+
coords = allocate_coords(size(ifc, 1), size(ifc, 2) - 1)
63+
64+
coords%ifc = ifc
65+
coords%mid = mid
66+
coords%del = del
67+
coords%dst = dst
68+
coords%rdel = rdel
69+
coords%rdst = rdst
70+
71+
end function new_Coords1D_from_fields
72+
73+
! Constructor if you only have interface coordinates; derives all the other
74+
! fields.
75+
function new_Coords1D_from_int(ifc) result(coords)
76+
real(r8), USE_CONTIGUOUS intent(in) :: ifc(:,:)
77+
type(Coords1D) :: coords
78+
79+
coords = allocate_coords(size(ifc, 1), size(ifc, 2) - 1)
80+
81+
coords%ifc = ifc
82+
coords%mid = 0.5_r8 * (ifc(:,:coords%d)+ifc(:,2:))
83+
coords%del = coords%ifc(:,2:) - coords%ifc(:,:coords%d)
84+
coords%dst = coords%mid(:,2:) - coords%mid(:,:coords%d-1)
85+
coords%rdel = 1._r8/coords%del
86+
coords%rdst = 1._r8/coords%dst
87+
88+
end function new_Coords1D_from_int
89+
90+
! Create a new Coords1D object that is a subsection of some other object,
91+
! e.g. if you want only the first m coordinates, use d_bnds=[1, m].
92+
!
93+
! Originally this used pointers, but it was found to actually be cheaper
94+
! in practice just to make a copy, especially since pointers can impede
95+
! optimization.
96+
function section(self, n_bnds, d_bnds)
97+
class(Coords1D), intent(in) :: self
98+
integer, intent(in) :: n_bnds(2), d_bnds(2)
99+
type(Coords1D) :: section
100+
101+
section = allocate_coords(n_bnds(2)-n_bnds(1)+1, d_bnds(2)-d_bnds(1)+1)
102+
103+
section%ifc(:,:) = self%ifc(n_bnds(1):n_bnds(2),d_bnds(1):d_bnds(2)+1)
104+
section%mid(:,:) = self%mid(n_bnds(1):n_bnds(2),d_bnds(1):d_bnds(2))
105+
section%del(:,:) = self%del(n_bnds(1):n_bnds(2),d_bnds(1):d_bnds(2))
106+
section%dst(:,:) = self%dst(n_bnds(1):n_bnds(2),d_bnds(1):d_bnds(2)-1)
107+
section%rdel(:,:) = self%rdel(n_bnds(1):n_bnds(2),d_bnds(1):d_bnds(2))
108+
section%rdst(:,:) = self%rdst(n_bnds(1):n_bnds(2),d_bnds(1):d_bnds(2)-1)
109+
110+
end function section
111+
112+
! Quick utility to get allocate each array with the correct size.
113+
function allocate_coords(n, d) result(coords)
114+
integer, intent(in) :: n, d
115+
type(Coords1D) :: coords
116+
117+
coords%n = n
118+
coords%d = d
119+
120+
allocate(coords%ifc(coords%n,coords%d+1))
121+
allocate(coords%mid(coords%n,coords%d))
122+
allocate(coords%del(coords%n,coords%d))
123+
allocate(coords%dst(coords%n,coords%d-1))
124+
allocate(coords%rdel(coords%n,coords%d))
125+
allocate(coords%rdst(coords%n,coords%d-1))
126+
127+
end function allocate_coords
128+
129+
subroutine finalize(this)
130+
class(Coords1D), intent(inout) :: this
131+
call finalize_Coords1D(this)
132+
end subroutine finalize
133+
134+
! Deallocate and reset to initial state.
135+
subroutine finalize_Coords1D(this)
136+
type(Coords1D) :: this
137+
138+
this%n = 0
139+
this%d = 0
140+
if(allocated(this%ifc)) deallocate(this%ifc)
141+
if(allocated(this%mid)) deallocate(this%mid)
142+
if(allocated(this%del)) deallocate(this%del)
143+
if(allocated(this%dst)) deallocate(this%dst)
144+
if(allocated(this%rdel)) deallocate(this%rdel)
145+
if(allocated(this%rdst)) deallocate(this%rdst)
146+
147+
end subroutine finalize_Coords1D
148+
153149
end module coords_1d
154-

0 commit comments

Comments
 (0)