SOCA
soca_state_mod.F90
Go to the documentation of this file.
1 ! (C) Copyright 2020-2021 UCAR
2 !
3 ! This software is licensed under the terms of the Apache Licence Version 2.0
4 ! which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5 
6 !> State fields
8 
9 use fckit_log_module, only: fckit_log
10 use kinds, only: kind_real
11 use oops_variables_mod
12 
13 ! soca modules
14 use soca_geom_mod
18 
19 implicit none
20 private
21 
22 
23 !-------------------------------------------------------------------------------
24 !> State fields.
25 !!
26 !! Any procedures that are shared with soca_increment are implemented
27 !! in the soca_fields base class
28 type, public, extends(soca_fields) :: soca_state
29 
30 contains
31 
32  !> \name interactions with increment
33  !! \{
34 
35  !> \copybrief soca_state_diff_incr \see soca_state_diff_incr
36  procedure :: diff_incr=> soca_state_diff_incr
37 
38  !> \copybrief soca_state_add_incr \see soca_state_add_incr
39  procedure :: add_incr => soca_state_add_incr
40 
41  !> \}
42 
43 
44  !> \name misc
45  !! \{
46 
47  !> \copybrief soca_state_rotate \see soca_state_rotate
48  procedure :: rotate => soca_state_rotate
49 
50  !> \copybrief soca_state_convert \see soca_state_convert
51  procedure :: convert => soca_state_convert
52 
53  !> \copybrief soca_state_logexpon \see soca_state_logexpon
54  procedure :: logexpon => soca_state_logexpon
55 
56  !> \}
57 
58 end type
59 
60 
61 !------------------------------------------------------------------------------
62 contains
63 !------------------------------------------------------------------------------
64 
65 
66 ! ------------------------------------------------------------------------------
67 !> Rotate horizontal vector
68 !!
69 !! One or more sets of vectors, represented by corresponding u and v variables
70 !! in the \p uvars and \p vvars lists are rotated to north (if \p coordinate == "north")
71 !! or rotated back to the grid (if \p coordinate == "grid")
72 !! \relates soca_state_mod::soca_state
73 subroutine soca_state_rotate(self, coordinate, uvars, vvars)
74  class(soca_state), intent(inout) :: self
75  character(len=*), intent(in) :: coordinate !< "north" or "grid"
76  type(oops_variables), intent(in) :: uvars !< list of one or more U variables
77  type(oops_variables), intent(in) :: vvars !< list of one or more V variables
78 
79  integer :: z, i
80  type(soca_field), pointer :: uocn, vocn
81  real(kind=kind_real), allocatable :: un(:,:,:), vn(:,:,:)
82  character(len=64) :: u_names, v_names
83 
84  do i=1, uvars%nvars()
85  ! get (u, v) pair and make a copy
86  u_names = trim(uvars%variable(i))
87  v_names = trim(vvars%variable(i))
88  if (self%has(u_names).and.self%has(v_names)) then
89  call fckit_log%info("rotating "//trim(u_names)//" "//trim(v_names))
90  call self%get(u_names, uocn)
91  call self%get(v_names, vocn)
92  else
93  ! Skip if no pair found.
94  call fckit_log%info("not rotating "//trim(u_names)//" "//trim(v_names))
95  cycle
96  end if
97  allocate(un(size(uocn%val,1),size(uocn%val,2),size(uocn%val,3)))
98  allocate(vn(size(uocn%val,1),size(uocn%val,2),size(uocn%val,3)))
99  un = uocn%val
100  vn = vocn%val
101 
102  select case(trim(coordinate))
103  case("north") ! rotate (uocn, vocn) to geo north
104  do z=1,uocn%nz
105  uocn%val(:,:,z) = &
106  (self%geom%cos_rot(:,:)*un(:,:,z) + self%geom%sin_rot(:,:)*vn(:,:,z)) * uocn%mask(:,:)
107  vocn%val(:,:,z) = &
108  (- self%geom%sin_rot(:,:)*un(:,:,z) + self%geom%cos_rot(:,:)*vn(:,:,z)) * vocn%mask(:,:)
109  end do
110  case("grid")
111  do z=1,uocn%nz
112  uocn%val(:,:,z) = &
113  (self%geom%cos_rot(:,:)*un(:,:,z) - self%geom%sin_rot(:,:)*vn(:,:,z)) * uocn%mask(:,:)
114  vocn%val(:,:,z) = &
115  (self%geom%sin_rot(:,:)*un(:,:,z) + self%geom%cos_rot(:,:)*vn(:,:,z)) * vocn%mask(:,:)
116  end do
117  end select
118  deallocate(un, vn)
119 
120  ! update halos
121  call uocn%update_halo(self%geom)
122  call vocn%update_halo(self%geom)
123  end do
124 end subroutine soca_state_rotate
125 
126 
127 ! ------------------------------------------------------------------------------
128 !> add a set of increments to the set of fields
129 !!
130 !! \throws abor1_ftn aborts if \p rhs is not a subset of \p self
131 !! \relates soca_state_mod::soca_state
132 subroutine soca_state_add_incr(self, rhs)
133  class(soca_state), intent(inout) :: self
134  class(soca_increment), intent(in) :: rhs !< increment to add to \p self
135 
136  type(soca_field), pointer :: fld, fld_r
137  integer :: i, k
138 
139  real(kind=kind_real) :: min_ice = 1e-6_kind_real
140  real(kind=kind_real) :: amin = 1e-6_kind_real
141  real(kind=kind_real) :: amax = 10.0_kind_real
142  real(kind=kind_real), allocatable :: alpha(:,:), aice_bkg(:,:), aice_ana(:,:)
143  type(soca_fields) :: incr
144 
145  ! make sure rhs is a subset of self
146  call rhs%check_subset(self)
147 
148  ! Make a copy of the increment
149  call incr%copy(rhs)
150 
151 
152  ! for each field that exists in incr, add to self
153  do i=1,size(incr%fields)
154  fld_r => incr%fields(i)
155  call self%get(fld_r%name, fld)
156  fld%val = fld%val + fld_r%val
157  end do
158 
159 end subroutine soca_state_add_incr
160 
161 
162 ! ------------------------------------------------------------------------------
163 !> subtract two sets of fields, saving the results in \p inc
164 !!
165 !! \f$ inc = x1 - x2 \f$
166 !! \throws abor1_ftn aborts if \p inc and \p x2 are not subsets of \p x1
167 !! \relates soca_state_mod::soca_state
168 subroutine soca_state_diff_incr(x1, x2, inc)
169  class(soca_state), intent(in) :: x1
170  class(soca_state), intent(in) :: x2
171  class(soca_increment), intent(inout) :: inc
172 
173  integer :: i
174  type(soca_field), pointer :: f1, f2
175 
176  ! make sure fields correct shapes
177  call inc%check_subset(x2)
178  call x2%check_subset(x1)
179 
180  ! subtract
181  do i=1,size(inc%fields)
182  call x1%get(inc%fields(i)%name, f1)
183  call x2%get(inc%fields(i)%name, f2)
184  inc%fields(i)%val = f1%val - f2%val
185  end do
186 end subroutine soca_state_diff_incr
187 
188 
189 ! ------------------------------------------------------------------------------
190 !> Change resolution of \p rhs to \p self
191 !!
192 !! \p self must have valid "layer_depth" and "hocn" fields. The other fields
193 !! are interpolated from \p rhs to \p self. Any variables that are marked as
194 !! "positive definite" in the metadata configuration file are forced to be >= 0.0
195 !! after interpolation.
196 !!
197 !! \relates soca_state_mod::soca_state
198 subroutine soca_state_convert(self, rhs)
199  class(soca_state), intent(inout) :: self
200  class(soca_state), intent(in) :: rhs !< source
201 
202  integer :: n
203  type(soca_convertstate_type) :: convert_state
204  type(soca_field), pointer :: field1, field2, hocn1, hocn2, layer_depth
205 
206  call rhs%get("hocn", hocn1)
207  call self%get("hocn", hocn2)
208  call convert_state%setup(rhs%geom, self%geom, hocn1, hocn2)
209  do n = 1, size(rhs%fields)
210  if (rhs%fields(n)%name=='layer_depth') cycle ! skip layer_depth interpolation
211  field1 => rhs%fields(n)
212  call self%get(trim(field1%name),field2)
213  if (field1%metadata%io_file=="ocn" .or. field1%metadata%io_file=="sfc" .or. field1%metadata%io_file=="ice") &
214  call convert_state%change_resol(field1, field2, rhs%geom, self%geom)
215  ! Insure that positive definite variables are still >0
216  if (rhs%fields(n)%metadata%property=='positive_definite') then
217  where (field2%val<0.0)
218  field2%val=0.0
219  end where
220  end if
221  end do !n
222 
223  ! Set layer depth for new grid
224  call self%get("layer_depth", layer_depth)
225  call self%geom%thickness2depth(hocn2%val, layer_depth%val)
226  call convert_state%clean()
227 end subroutine soca_state_convert
228 
229 
230 ! ------------------------------------------------------------------------------
231 !> Apply logarithmic and exponential transformations
232 !!
233 !! \relates soca_state_mod::soca_state
234 subroutine soca_state_logexpon(self, transfunc, trvars)
235  class(soca_state), intent(inout) :: self
236  character(len=*), intent(in) :: transfunc !< "log" or "expon"
237  type(oops_variables), intent(in) :: trvars !< list of variables to transform
238 
239  integer :: z, i
240  type(soca_field), pointer :: trocn
241  real(kind=kind_real), allocatable :: trn(:,:,:)
242  real(kind=kind_real) :: min_val = 1e-6_kind_real
243  character(len=64) :: tr_names
244 
245  do i=1, trvars%nvars()
246  ! get a list variables to be transformed and make a copy
247  tr_names = trim(trvars%variable(i))
248  if (self%has(tr_names)) then
249  call fckit_log%info("transforming "//trim(tr_names))
250  call self%get(tr_names, trocn)
251  else
252  ! Skip if no variable found.
253  call fckit_log%info("not transforming "//trim(tr_names))
254  cycle
255  end if
256  allocate(trn(size(trocn%val,1),size(trocn%val,2),size(trocn%val,3)))
257  trn = trocn%val
258 
259  select case(trim(transfunc))
260  case("log") ! apply logarithmic transformation
261  trocn%val = log(trn + min_val)
262  case("expon") ! Apply exponential transformation
263  trocn%val = exp(trn) - min_val
264  end select
265 
266  ! update halos
267  call trocn%update_halo(self%geom)
268 
269  ! deallocate trn for next variable
270  deallocate(trn)
271  end do
272 end subroutine soca_state_logexpon
273 ! ------------------------------------------------------------------------------
274 
275 
276 end module
Handle fields for the model.
Geometry module.
Increment fields.
State fields.
Holds all data and metadata related to a single field variable.
A collection of soca_field types representing a collective state or increment.