Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 2b5b438

Browse files
Hallberg-NOAAmarshallward
authored andcommitted
+Add optional scale argument to time_interp_external
Added a new optional scale argument to time_interp_external that can be used to rescale the values that are set within the infrastructure routines that underlie time_interp_external. This new capability has been fully tested, although it is not being invoked with this commit. All answers are bitwise identical, but there is a new optional argument in a public interface.
1 parent af321d6 commit 2b5b438

1 file changed

Lines changed: 107 additions & 5 deletions

File tree

src/framework/MOM_interpolate.F90

Lines changed: 107 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,19 +26,45 @@ module MOM_interpolate
2626
contains
2727

2828
!> Read a scalar field based on model time.
29-
subroutine time_interp_external_0d(field_id, time, data_in, verbose)
29+
subroutine time_interp_external_0d(field_id, time, data_in, verbose, scale)
3030
integer, intent(in) :: field_id !< The integer index of the external field returned
3131
!! from a previous call to init_external_field()
3232
type(time_type), intent(in) :: time !< The target time for the data
3333
real, intent(inout) :: data_in !< The interpolated value
3434
logical, optional, intent(in) :: verbose !< If true, write verbose output for debugging
35+
real, optional, intent(in) :: scale !< A scaling factor that new values of data_in are
36+
!! multiplied by before it is returned
37+
real :: data_in_pre_scale ! The input data before rescaling
38+
real :: I_scale ! The inverse of scale
39+
40+
! Store the input value in case the scaling factor is perfectly invertable.
41+
data_in_pre_scale = data_in
42+
I_scale = 1.0
43+
if (present(scale)) then ; if ((scale /= 1.0) .and. (scale /= 0.0)) then
44+
! Because time_interp_extern has the ability to only set some values, but no clear
45+
! mechanism to determine which values have been set, the input data has to
46+
! be unscaled so that it will have the right values when it is returned.
47+
I_scale = 1.0 / scale
48+
data_in = data_in * I_scale
49+
endif ; endif
3550

3651
call time_interp_extern(field_id, time, data_in, verbose=verbose)
52+
53+
if (present(scale)) then ; if (scale /= 1.0) then
54+
! Rescale data that has been newly set and restore the scaling of unset data.
55+
if (data_in == I_scale * data_in_pre_scale) then
56+
data_in = data_in_pre_scale
57+
else
58+
data_in = scale * data_in
59+
endif
60+
endif ; endif
61+
3762
end subroutine time_interp_external_0d
3863

3964
!> Read a 2d field from an external based on model time, potentially including horizontal
4065
!! interpolation and rotation of the data
41-
subroutine time_interp_external_2d(field_id, time, data_in, interp, verbose, horz_interp, mask_out, turns)
66+
subroutine time_interp_external_2d(field_id, time, data_in, interp, &
67+
verbose, horz_interp, mask_out, turns, scale)
4268
integer, intent(in) :: field_id !< The integer index of the external field returned
4369
!! from a previous call to init_external_field()
4470
type(time_type), intent(in) :: time !< The target time for the data
@@ -50,14 +76,32 @@ subroutine time_interp_external_2d(field_id, time, data_in, interp, verbose, hor
5076
logical, dimension(:,:), &
5177
optional, intent(out) :: mask_out !< An array that is true where there is valid data
5278
integer, optional, intent(in) :: turns !< Number of quarter turns to rotate the data
79+
real, optional, intent(in) :: scale !< A scaling factor that new values of data_in are
80+
!! multiplied by before it is returned
5381

54-
real, allocatable :: data_pre_rot(:,:) ! The input data before rotation
82+
real, allocatable :: data_in_pre_scale(:,:) ! The input data before rescaling
83+
real, allocatable :: data_pre_rot(:,:) ! The unscaled input data before rotation
84+
real :: I_scale ! The inverse of scale
5585
integer :: qturns ! The number of quarter turns to rotate the data
86+
integer :: i, j
5687

5788
! TODO: Mask rotation requires logical array rotation support
5889
if (present(mask_out)) &
5990
call MOM_error(FATAL, "Rotation of masked output not yet support")
6091

92+
if (present(scale)) then ; if ((scale /= 1.0) .and. (scale /= 0.0)) then
93+
! Because time_interp_extern has the ability to only set some values, but no clear mechanism
94+
! to determine which values have been set, the input data has to be unscaled so that it will
95+
! have the right values when it is returned. It may be a problem for some compiler settings
96+
! if there are NaNs in data_in, but they will not spread.
97+
if (abs(fraction(scale)) /= 1.0) then
98+
! This scaling factor may not be perfectly invertable, so store the input value
99+
allocate(data_in_pre_scale, source=data_in)
100+
endif
101+
I_scale = 1.0 / scale
102+
data_in(:,:) = I_scale * data_in(:,:)
103+
endif ; endif
104+
61105
qturns = 0 ; if (present(turns)) qturns = modulo(turns, 4)
62106

63107
if (qturns == 0) then
@@ -70,12 +114,30 @@ subroutine time_interp_external_2d(field_id, time, data_in, interp, verbose, hor
70114
call rotate_array(data_pre_rot, turns, data_in)
71115
deallocate(data_pre_rot)
72116
endif
117+
118+
if (present(scale)) then ; if (scale /= 1.0) then
119+
! Rescale data that has been newly set and restore the scaling of unset data.
120+
if ((abs(fraction(scale)) /= 1.0) .and. (scale /= 0.0)) then
121+
do j=LBOUND(data_in,2),UBOUND(data_in,2) ; do i=LBOUND(data_in,1),UBOUND(data_in,1)
122+
! This handles the case where scale is not exactly invertable for data
123+
! values that have not been modified by time_interp_extern.
124+
if (data_in(i,j) == I_scale * data_in_pre_scale(i,j)) then
125+
data_in(i,j) = data_in_pre_scale(i,j)
126+
else
127+
data_in(i,j) = scale * data_in(i,j)
128+
endif
129+
enddo ; enddo
130+
else
131+
data_in(:,:) = scale * data_in(:,:)
132+
endif
133+
endif ; endif
134+
73135
end subroutine time_interp_external_2d
74136

75137

76138
!> Read a 3d field based on model time, and rotate to the model grid
77139
subroutine time_interp_external_3d(field_id, time, data_in, interp, &
78-
verbose, horz_interp, mask_out, turns)
140+
verbose, horz_interp, mask_out, turns, scale)
79141
integer, intent(in) :: field_id !< The integer index of the external field returned
80142
!! from a previous call to init_external_field()
81143
type(time_type), intent(in) :: time !< The target time for the data
@@ -87,14 +149,32 @@ subroutine time_interp_external_3d(field_id, time, data_in, interp, &
87149
logical, dimension(:,:,:), &
88150
optional, intent(out) :: mask_out !< An array that is true where there is valid data
89151
integer, optional, intent(in) :: turns !< Number of quarter turns to rotate the data
152+
real, optional, intent(in) :: scale !< A scaling factor that new values of data_in are
153+
!! multiplied by before it is returned
90154

91-
real, allocatable :: data_pre_rot(:,:,:) ! The input data before rotation
155+
real, allocatable :: data_in_pre_scale(:,:,:) ! The input data before rescaling
156+
real, allocatable :: data_pre_rot(:,:,:) ! The unscaled input data before rotation
157+
real :: I_scale ! The inverse of scale
92158
integer :: qturns ! The number of quarter turns to rotate the data
159+
integer :: i, j, k
93160

94161
! TODO: Mask rotation requires logical array rotation support
95162
if (present(mask_out)) &
96163
call MOM_error(FATAL, "Rotation of masked output not yet support")
97164

165+
if (present(scale)) then ; if ((scale /= 1.0) .and. (scale /= 0.0)) then
166+
! Because time_interp_extern has the ability to only set some values, but no clear mechanism
167+
! to determine which values have been set, the input data has to be unscaled so that it will
168+
! have the right values when it is returned. It may be a problem for some compiler settings
169+
! if there are NaNs in data_in, but they will not spread.
170+
if (abs(fraction(scale)) /= 1.0) then
171+
! This scaling factor may not be perfectly invertable, so store the input value
172+
allocate(data_in_pre_scale, source=data_in)
173+
endif
174+
I_scale = 1.0 / scale
175+
data_in(:,:,:) = I_scale * data_in(:,:,:)
176+
endif ; endif
177+
98178
qturns = 0 ; if (present(turns)) qturns = modulo(turns, 4)
99179

100180
if (qturns == 0) then
@@ -107,6 +187,28 @@ subroutine time_interp_external_3d(field_id, time, data_in, interp, &
107187
call rotate_array(data_pre_rot, turns, data_in)
108188
deallocate(data_pre_rot)
109189
endif
190+
191+
if (present(scale)) then ; if (scale /= 1.0) then
192+
! Rescale data that has been newly set and restore the scaling of unset data.
193+
if ((abs(fraction(scale)) /= 1.0) .and. (scale /= 0.0)) then
194+
do k=LBOUND(data_in,3),UBOUND(data_in,3)
195+
do j=LBOUND(data_in,2),UBOUND(data_in,2)
196+
do i=LBOUND(data_in,1),UBOUND(data_in,1)
197+
! This handles the case where scale is not exactly invertable for data
198+
! values that have not been modified by time_interp_extern.
199+
if (data_in(i,j,k) == I_scale * data_in_pre_scale(i,j,k)) then
200+
data_in(i,j,k) = data_in_pre_scale(i,j,k)
201+
else
202+
data_in(i,j,k) = scale * data_in(i,j,k)
203+
endif
204+
enddo
205+
enddo
206+
enddo
207+
else
208+
data_in(:,:,:) = scale * data_in(:,:,:)
209+
endif
210+
endif ; endif
211+
110212
end subroutine time_interp_external_3d
111213

112214
end module MOM_interpolate

0 commit comments

Comments
 (0)