← back to index

src/framework/MOM_unit_scaling.F90

portedportable, not yet portedexecuted, not portableexecutable, not hit by this run

1! This file is part of MOM6, the Modular Ocean Model version 6.
2! See the LICENSE file for licensing information.
3! SPDX-License-Identifier: Apache-2.0
4
5!> Provides a transparent unit rescaling type to facilitate dimensional consistency testing
6module MOM_unit_scaling
7
8use MOM_error_handler, only : MOM_error, MOM_mesg, FATAL
9use MOM_file_parser, only : get_param, log_param, log_version, param_file_type
10
11implicit none ; private
12
13! A note on unit descriptions in comments: MOM6 uses units that can be rescaled for dimensional
14! consistency testing. These are noted in comments with units like Z, H, L, T, R and Q, along with
15! their mks counterparts with notation like "a velocity [Z T-1 ~> m s-1]". If the rescaled
16! combination is a nondimensional variable, the notation would be "a slope [Z L-1 ~> nondim]",
17! but if (as the case for the variables here), the rescaled combination is exactly 1, the right
18! notation would be something like "a dimensional scaling factor [Z m-1 ~> 1]". If the units
19! vary with the Boussinesq approximation, the Boussinesq variant is given first.
20
21public unit_scaling_init, unit_no_scaling_init, unit_scaling_end, fix_restart_unit_scaling
22
23!> Describes various unit conversion factors
24type, public :: unit_scale_type
25 real :: m_to_Z !< A constant that translates distances in meters to the units of depth [Z m-1 ~> 1]
26 real :: Z_to_m !< A constant that translates distances in the units of depth to meters [m Z-1 ~> 1]
27 real :: m_to_L !< A constant that translates lengths in meters to the units of horizontal lengths [L m-1 ~> 1]
28 real :: L_to_m !< A constant that translates lengths in the units of horizontal lengths to meters [m L-1 ~> 1]
29 real :: s_to_T !< A constant that translates time intervals in seconds to the units of time [T s-1 ~> 1]
30 real :: T_to_s !< A constant that translates the units of time to seconds [s T-1 ~> 1]
31 real :: R_to_kg_m3 !< A constant that translates the units of density to kilograms per meter cubed [kg m-3 R-1 ~> 1]
32 real :: kg_m3_to_R !< A constant that translates kilograms per meter cubed to the units of density [R m3 kg-1 ~> 1]
33 real :: Q_to_J_kg !< A constant that translates the units of enthalpy to Joules per kilogram [J kg-1 Q-1 ~> 1]
34 real :: J_kg_to_Q !< A constant that translates Joules per kilogram to the units of enthalpy [Q kg J-1 ~> 1]
35 real :: C_to_degC !< A constant that translates the units of temperature to degrees Celsius [degC C-1 ~> 1]
36 real :: degC_to_C !< A constant that translates degrees Celsius to the units of temperature [C degC-1 ~> 1]
37 real :: S_to_ppt !< A constant that translates the units of salinity to parts per thousand [ppt S-1 ~> 1]
38 real :: ppt_to_S !< A constant that translates parts per thousand to the units of salinity [S ppt-1 ~> 1]
39
40 ! These are useful combinations of the fundamental scale conversion factors above.
41 real :: Z_to_L !< Convert vertical distances to lateral lengths [L Z-1 ~> 1]
42 real :: L_to_Z !< Convert lateral lengths to vertical distances [Z L-1 ~> 1]
43 real :: L_T_to_m_s !< Convert lateral velocities from L T-1 to m s-1 [T m L-1 s-1 ~> 1]
44 real :: m_s_to_L_T !< Convert lateral velocities from m s-1 to L T-1 [L s T-1 m-1 ~> 1]
45 real :: L_T2_to_m_s2 !< Convert lateral accelerations from L T-2 to m s-2 [L s2 T-2 m-1 ~> 1]
46 real :: Z2_T_to_m2_s !< Convert vertical diffusivities from Z2 T-1 to m2 s-1 [T m2 Z-2 s-1 ~> 1]
47 real :: m2_s_to_Z2_T !< Convert vertical diffusivities from m2 s-1 to Z2 T-1 [Z2 s T-1 m-2 ~> 1]
48 real :: W_m2_to_QRZ_T !< Convert heat fluxes from W m-2 to Q R Z T-1 [Q R Z m2 T-1 W-1 ~> 1]
49 real :: QRZ_T_to_W_m2 !< Convert heat fluxes from Q R Z T-1 to W m-2 [W T Q-1 R-1 Z-1 m-2 ~> 1]
50 ! Not used enough: real :: kg_m2_to_RZ !< Convert mass loads from kg m-2 to R Z [R Z m2 kg-1 ~> 1]
51 real :: RZ_to_kg_m2 !< Convert mass loads from R Z to kg m-2 [kg R-1 Z-1 m-2 ~> 1]
52 real :: RZL2_to_kg !< Convert masses from R Z L2 to kg [kg R-1 Z-1 L-2 ~> 1]
53 real :: kg_m2s_to_RZ_T !< Convert mass fluxes from kg m-2 s-1 to R Z T-1 [R Z m2 s T-1 kg-1 ~> 1]
54 real :: RZ_T_to_kg_m2s !< Convert mass fluxes from R Z T-1 to kg m-2 s-1 [T kg R-1 Z-1 m-2 s-1 ~> 1]
55 real :: RZ3_T3_to_W_m2 !< Convert turbulent kinetic energy fluxes from R Z3 T-3 to W m-2 [W T3 R-1 Z-3 m-2 ~> 1]
56 real :: W_m2_to_RZ3_T3 !< Convert turbulent kinetic energy fluxes from W m-2 to R Z3 T-3 [R Z3 m2 T-3 W-1 ~> 1]
57 real :: RL2_T2_to_Pa !< Convert pressures from R L2 T-2 to Pa [Pa T2 R-1 L-2 ~> 1]
58 real :: RLZ_T2_to_Pa !< Convert wind stresses from R L Z T-2 to Pa [Pa T2 R-1 L-1 Z-1 ~> 1]
59 real :: Pa_to_RL2_T2 !< Convert pressures from Pa to R L2 T-2 [R L2 T-2 Pa-1 ~> 1]
60 real :: Pa_to_RLZ_T2 !< Convert wind stresses from Pa to R L Z T-2 [R L Z T-2 Pa-1 ~> 1]
61
62 ! These are no longer used for changing scaling across restarts.
63 real :: m_to_Z_restart = 1.0 !< A copy of the m_to_Z that is used in restart files.
64 real :: m_to_L_restart = 1.0 !< A copy of the m_to_L that is used in restart files.
65 real :: s_to_T_restart = 1.0 !< A copy of the s_to_T that is used in restart files.
66 real :: kg_m3_to_R_restart = 1.0 !< A copy of the kg_m3_to_R that is used in restart files.
67 real :: J_kg_to_Q_restart = 1.0 !< A copy of the J_kg_to_Q that is used in restart files.
68end type unit_scale_type
69
70contains
71
72!> Allocates and initializes the ocean model unit scaling type
731subroutine unit_scaling_init( param_file, US )
74 type(param_file_type), intent(in) :: param_file !< Parameter file handle/type
75 type(unit_scale_type), pointer :: US !< A dimensional unit scaling type
76
77 ! This routine initializes a unit_scale_type structure (US).
78
79 ! Local variables
80 integer :: Z_power, L_power, T_power, R_power, Q_power, C_power, S_power
81 real :: Z_rescale_factor, L_rescale_factor, T_rescale_factor, R_rescale_factor, Q_rescale_factor
82 real :: C_rescale_factor, S_rescale_factor
83 ! This include declares and sets the variable "version".
84# include "version_variable.h"
85 character(len=16) :: mdl = "MOM_unit_scaling"
86
871 if (associated(US)) call MOM_error(FATAL, &
880 'unit_scaling_init: called with an associated US pointer.')
891 allocate(US)
90
91 ! Read all relevant parameters and write them to the model log.
92 call log_version(param_file, mdl, version, &
931 "Parameters for doing unit scaling of variables.", debugging=.true.)
94 call get_param(param_file, mdl, "Z_RESCALE_POWER", Z_power, &
95 "An integer power of 2 that is used to rescale the model's "//&
96 "internal units of depths and heights. Valid values range from -300 to 300.", &
971 default=0, debuggingParam=.true.)
98 call get_param(param_file, mdl, "L_RESCALE_POWER", L_power, &
99 "An integer power of 2 that is used to rescale the model's "//&
100 "internal units of lateral distances. Valid values range from -300 to 300.", &
1011 default=0, debuggingParam=.true.)
102 call get_param(param_file, mdl, "T_RESCALE_POWER", T_power, &
103 "An integer power of 2 that is used to rescale the model's "//&
104 "internal units of time. Valid values range from -300 to 300.", &
1051 default=0, debuggingParam=.true.)
106 call get_param(param_file, mdl, "R_RESCALE_POWER", R_power, &
107 "An integer power of 2 that is used to rescale the model's "//&
108 "internal units of density. Valid values range from -300 to 300.", &
1091 default=0, debuggingParam=.true.)
110 call get_param(param_file, mdl, "Q_RESCALE_POWER", Q_power, &
111 "An integer power of 2 that is used to rescale the model's "//&
112 "internal units of heat content. Valid values range from -300 to 300.", &
1131 default=0, debuggingParam=.true.)
114 call get_param(param_file, mdl, "C_RESCALE_POWER", C_power, &
115 "An integer power of 2 that is used to rescale the model's "//&
116 "internal units of temperature. Valid values range from -300 to 300.", &
1171 default=0, debuggingParam=.true.)
118 call get_param(param_file, mdl, "S_RESCALE_POWER", S_power, &
119 "An integer power of 2 that is used to rescale the model's "//&
120 "internal units of salinity. Valid values range from -300 to 300.", &
1211 default=0, debuggingParam=.true.)
122
1231 if (abs(Z_power) > 300) call MOM_error(FATAL, "unit_scaling_init: "//&
1240 "Z_RESCALE_POWER is outside of the valid range of -300 to 300.")
1251 if (abs(L_power) > 300) call MOM_error(FATAL, "unit_scaling_init: "//&
1260 "L_RESCALE_POWER is outside of the valid range of -300 to 300.")
1271 if (abs(T_power) > 300) call MOM_error(FATAL, "unit_scaling_init: "//&
1280 "T_RESCALE_POWER is outside of the valid range of -300 to 300.")
1291 if (abs(R_power) > 300) call MOM_error(FATAL, "unit_scaling_init: "//&
1300 "R_RESCALE_POWER is outside of the valid range of -300 to 300.")
1311 if (abs(Q_power) > 300) call MOM_error(FATAL, "unit_scaling_init: "//&
1320 "Q_RESCALE_POWER is outside of the valid range of -300 to 300.")
1331 if (abs(C_power) > 300) call MOM_error(FATAL, "unit_scaling_init: "//&
1340 "C_RESCALE_POWER is outside of the valid range of -300 to 300.")
1351 if (abs(S_power) > 300) call MOM_error(FATAL, "unit_scaling_init: "//&
1360 "S_RESCALE_POWER is outside of the valid range of -300 to 300.")
137
1381 Z_rescale_factor = 1.0
1391 if (Z_power /= 0) Z_rescale_factor = 2.0**Z_power
1401 US%Z_to_m = 1.0 * Z_rescale_factor
1411 US%m_to_Z = 1.0 / Z_rescale_factor
142
1431 L_rescale_factor = 1.0
1441 if (L_power /= 0) L_rescale_factor = 2.0**L_power
1451 US%L_to_m = 1.0 * L_rescale_factor
1461 US%m_to_L = 1.0 / L_rescale_factor
147
1481 T_rescale_factor = 1.0
1491 if (T_power /= 0) T_rescale_factor = 2.0**T_power
1501 US%T_to_s = 1.0 * T_rescale_factor
1511 US%s_to_T = 1.0 / T_rescale_factor
152
1531 R_rescale_factor = 1.0
1541 if (R_power /= 0) R_rescale_factor = 2.0**R_power
1551 US%R_to_kg_m3 = 1.0 * R_rescale_factor
1561 US%kg_m3_to_R = 1.0 / R_rescale_factor
157
1581 Q_Rescale_factor = 1.0
1591 if (Q_power /= 0) Q_Rescale_factor = 2.0**Q_power
1601 US%Q_to_J_kg = 1.0 * Q_Rescale_factor
1611 US%J_kg_to_Q = 1.0 / Q_Rescale_factor
162
1631 C_Rescale_factor = 1.0
1641 if (C_power /= 0) C_Rescale_factor = 2.0**C_power
1651 US%C_to_degC = 1.0 * C_Rescale_factor
1661 US%degC_to_C = 1.0 / C_Rescale_factor
167
1681 S_Rescale_factor = 1.0
1691 if (S_power /= 0) S_Rescale_factor = 2.0**S_power
1701 US%S_to_ppt = 1.0 * S_Rescale_factor
1711 US%ppt_to_S = 1.0 / S_Rescale_factor
172
1731 call set_unit_scaling_combos(US)
1741end subroutine unit_scaling_init
175
176!> Allocates and initializes the ocean model unit scaling type to unscaled values.
1770subroutine unit_no_scaling_init(US)
178 type(unit_scale_type), pointer :: US !< A dimensional unit scaling type
179
1800 if (associated(US)) call MOM_error(FATAL, &
1810 'unit_scaling_init: called with an associated US pointer.')
1820 allocate(US)
183
1840 US%Z_to_m = 1.0 ; US%m_to_Z = 1.0
1850 US%L_to_m = 1.0 ; US%m_to_L = 1.0
1860 US%T_to_s = 1.0 ; US%s_to_T = 1.0
1870 US%R_to_kg_m3 = 1.0 ; US%kg_m3_to_R = 1.0
1880 US%Q_to_J_kg = 1.0 ; US%J_kg_to_Q = 1.0
1890 US%C_to_degC = 1.0 ; US%degC_to_C = 1.0
1900 US%S_to_ppt = 1.0 ; US%ppt_to_S = 1.0
191
1920 call set_unit_scaling_combos(US)
1930end subroutine unit_no_scaling_init
194
195!> This subroutine sets useful combinations of the fundamental scale conversion factors
196!! in the unit scaling type.
1971subroutine set_unit_scaling_combos(US)
198 type(unit_scale_type), intent(inout) :: US !< A dimensional unit scaling type
199
200 ! Convert vertical to horizontal length scales and the reverse:
2011 US%Z_to_L = US%Z_to_m * US%m_to_L
2021 US%L_to_Z = US%L_to_m * US%m_to_Z
203 ! Horizontal velocities:
2041 US%L_T_to_m_s = US%L_to_m * US%s_to_T
2051 US%m_s_to_L_T = US%m_to_L * US%T_to_s
206 ! Horizontal accelerations:
2071 US%L_T2_to_m_s2 = US%L_to_m * US%s_to_T**2
208 ! It does not look like US%m_s2_to_L_T2 would be used, so it does not exist.
209 ! Vertical diffusivities and viscosities:
2101 US%Z2_T_to_m2_s = US%Z_to_m**2 * US%s_to_T
2111 US%m2_s_to_Z2_T = US%m_to_Z**2 * US%T_to_s
212 ! Column mass loads:
2131 US%RZ_to_kg_m2 = US%R_to_kg_m3 * US%Z_to_m
214 ! It does not seem like US%kg_m2_to_RZ would be used enough in MOM6 to justify its existence.
215 ! Vertical mass fluxes:
2161 US%kg_m2s_to_RZ_T = US%kg_m3_to_R * US%m_to_Z * US%T_to_s
2171 US%RZ_T_to_kg_m2s = US%R_to_kg_m3 * US%Z_to_m * US%s_to_T
218 ! Turbulent kinetic energy vertical fluxes:
2191 US%RZ3_T3_to_W_m2 = US%R_to_kg_m3 * US%Z_to_m**3 * US%s_to_T**3
2201 US%W_m2_to_RZ3_T3 = US%kg_m3_to_R * US%m_to_Z**3 * US%T_to_s**3
221 ! Vertical heat fluxes:
2221 US%W_m2_to_QRZ_T = US%J_kg_to_Q * US%kg_m3_to_R * US%m_to_Z * US%T_to_s
2231 US%QRZ_T_to_W_m2 = US%Q_to_J_kg * US%R_to_kg_m3 * US%Z_to_m * US%s_to_T
224 ! Pressures:
2251 US%RL2_T2_to_Pa = US%R_to_kg_m3 * US%L_T_to_m_s**2
2261 US%Pa_to_RL2_T2 = US%kg_m3_to_R * US%m_s_to_L_T**2
227 ! Wind stresses:
2281 US%RLZ_T2_to_Pa = US%R_to_kg_m3 * US%L_T_to_m_s**2 * US%Z_to_L
2291 US%Pa_to_RLZ_T2 = US%kg_m3_to_R * US%m_s_to_L_T**2 * US%L_to_Z
230 ! Masses:
2311 US%RZL2_to_kg = US%R_to_kg_m3 * US%Z_to_m * US%L_to_m**2
232
2331end subroutine set_unit_scaling_combos
234
235!> Set the unit scaling factors for output to restart files to the unit scaling
236!! factors for this run.
2370subroutine fix_restart_unit_scaling(US, unscaled)
238 type(unit_scale_type), intent(inout) :: US !< A dimensional unit scaling type
239 logical, optional, intent(in) :: unscaled !< If true, set the restart factors as though the
240 !! model would be unscaled, which is appropriate if the
241 !! scaling is undone when writing a restart file.
242
2430 US%m_to_Z_restart = 1.0 ! US%m_to_Z
2440 US%m_to_L_restart = 1.0 ! US%m_to_L
2450 US%s_to_T_restart = 1.0 ! US%s_to_T
2460 US%kg_m3_to_R_restart = 1.0 ! US%kg_m3_to_R
2470 US%J_kg_to_Q_restart = 1.0 ! US%J_kg_to_Q
248
2490 if (present(unscaled)) then ; if (unscaled) then
2500 US%m_to_Z_restart = 1.0
2510 US%m_to_L_restart = 1.0
2520 US%s_to_T_restart = 1.0
2530 US%kg_m3_to_R_restart = 1.0
2540 US%J_kg_to_Q_restart = 1.0
255 endif ; endif
256
2570end subroutine fix_restart_unit_scaling
258
259!> Deallocates a unit scaling structure.
2601subroutine unit_scaling_end( US )
261 type(unit_scale_type), pointer :: US !< A dimensional unit scaling type
262
2631 deallocate( US )
264
2651end subroutine unit_scaling_end
266
2670end module MOM_unit_scaling