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 | |
| 6 | module MOM_unit_scaling | |
| 7 | ||
| 8 | use MOM_error_handler, only : MOM_error, MOM_mesg, FATAL | |
| 9 | use MOM_file_parser, only : get_param, log_param, log_version, param_file_type | |
| 10 | ||
| 11 | implicit 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 | ||
| 21 | public unit_scaling_init, unit_no_scaling_init, unit_scaling_end, fix_restart_unit_scaling | |
| 22 | ||
| 23 | !> Describes various unit conversion factors | |
| 24 | type, 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. | |
| 68 | end type unit_scale_type | |
| 69 | ||
| 70 | contains | |
| 71 | ||
| 72 | !> Allocates and initializes the ocean model unit scaling type | |
| 73 | 1 | subroutine 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 | ||
| 87 | 1 | if (associated(US)) call MOM_error(FATAL, & |
| 88 | 0 | 'unit_scaling_init: called with an associated US pointer.') |
| 89 | 1 | allocate(US) |
| 90 | ||
| 91 | ! Read all relevant parameters and write them to the model log. | |
| 92 | call log_version(param_file, mdl, version, & | |
| 93 | 1 | "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.", & | |
| 97 | 1 | 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.", & | |
| 101 | 1 | 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.", & | |
| 105 | 1 | 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.", & | |
| 109 | 1 | 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.", & | |
| 113 | 1 | 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.", & | |
| 117 | 1 | 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.", & | |
| 121 | 1 | default=0, debuggingParam=.true.) |
| 122 | ||
| 123 | 1 | if (abs(Z_power) > 300) call MOM_error(FATAL, "unit_scaling_init: "//& |
| 124 | 0 | "Z_RESCALE_POWER is outside of the valid range of -300 to 300.") |
| 125 | 1 | if (abs(L_power) > 300) call MOM_error(FATAL, "unit_scaling_init: "//& |
| 126 | 0 | "L_RESCALE_POWER is outside of the valid range of -300 to 300.") |
| 127 | 1 | if (abs(T_power) > 300) call MOM_error(FATAL, "unit_scaling_init: "//& |
| 128 | 0 | "T_RESCALE_POWER is outside of the valid range of -300 to 300.") |
| 129 | 1 | if (abs(R_power) > 300) call MOM_error(FATAL, "unit_scaling_init: "//& |
| 130 | 0 | "R_RESCALE_POWER is outside of the valid range of -300 to 300.") |
| 131 | 1 | if (abs(Q_power) > 300) call MOM_error(FATAL, "unit_scaling_init: "//& |
| 132 | 0 | "Q_RESCALE_POWER is outside of the valid range of -300 to 300.") |
| 133 | 1 | if (abs(C_power) > 300) call MOM_error(FATAL, "unit_scaling_init: "//& |
| 134 | 0 | "C_RESCALE_POWER is outside of the valid range of -300 to 300.") |
| 135 | 1 | if (abs(S_power) > 300) call MOM_error(FATAL, "unit_scaling_init: "//& |
| 136 | 0 | "S_RESCALE_POWER is outside of the valid range of -300 to 300.") |
| 137 | ||
| 138 | 1 | Z_rescale_factor = 1.0 |
| 139 | 1 | if (Z_power /= 0) Z_rescale_factor = 2.0**Z_power |
| 140 | 1 | US%Z_to_m = 1.0 * Z_rescale_factor |
| 141 | 1 | US%m_to_Z = 1.0 / Z_rescale_factor |
| 142 | ||
| 143 | 1 | L_rescale_factor = 1.0 |
| 144 | 1 | if (L_power /= 0) L_rescale_factor = 2.0**L_power |
| 145 | 1 | US%L_to_m = 1.0 * L_rescale_factor |
| 146 | 1 | US%m_to_L = 1.0 / L_rescale_factor |
| 147 | ||
| 148 | 1 | T_rescale_factor = 1.0 |
| 149 | 1 | if (T_power /= 0) T_rescale_factor = 2.0**T_power |
| 150 | 1 | US%T_to_s = 1.0 * T_rescale_factor |
| 151 | 1 | US%s_to_T = 1.0 / T_rescale_factor |
| 152 | ||
| 153 | 1 | R_rescale_factor = 1.0 |
| 154 | 1 | if (R_power /= 0) R_rescale_factor = 2.0**R_power |
| 155 | 1 | US%R_to_kg_m3 = 1.0 * R_rescale_factor |
| 156 | 1 | US%kg_m3_to_R = 1.0 / R_rescale_factor |
| 157 | ||
| 158 | 1 | Q_Rescale_factor = 1.0 |
| 159 | 1 | if (Q_power /= 0) Q_Rescale_factor = 2.0**Q_power |
| 160 | 1 | US%Q_to_J_kg = 1.0 * Q_Rescale_factor |
| 161 | 1 | US%J_kg_to_Q = 1.0 / Q_Rescale_factor |
| 162 | ||
| 163 | 1 | C_Rescale_factor = 1.0 |
| 164 | 1 | if (C_power /= 0) C_Rescale_factor = 2.0**C_power |
| 165 | 1 | US%C_to_degC = 1.0 * C_Rescale_factor |
| 166 | 1 | US%degC_to_C = 1.0 / C_Rescale_factor |
| 167 | ||
| 168 | 1 | S_Rescale_factor = 1.0 |
| 169 | 1 | if (S_power /= 0) S_Rescale_factor = 2.0**S_power |
| 170 | 1 | US%S_to_ppt = 1.0 * S_Rescale_factor |
| 171 | 1 | US%ppt_to_S = 1.0 / S_Rescale_factor |
| 172 | ||
| 173 | 1 | call set_unit_scaling_combos(US) |
| 174 | 1 | end subroutine unit_scaling_init |
| 175 | ||
| 176 | !> Allocates and initializes the ocean model unit scaling type to unscaled values. | |
| 177 | 0 | subroutine unit_no_scaling_init(US) |
| 178 | type(unit_scale_type), pointer :: US !< A dimensional unit scaling type | |
| 179 | ||
| 180 | 0 | if (associated(US)) call MOM_error(FATAL, & |
| 181 | 0 | 'unit_scaling_init: called with an associated US pointer.') |
| 182 | 0 | allocate(US) |
| 183 | ||
| 184 | 0 | US%Z_to_m = 1.0 ; US%m_to_Z = 1.0 |
| 185 | 0 | US%L_to_m = 1.0 ; US%m_to_L = 1.0 |
| 186 | 0 | US%T_to_s = 1.0 ; US%s_to_T = 1.0 |
| 187 | 0 | US%R_to_kg_m3 = 1.0 ; US%kg_m3_to_R = 1.0 |
| 188 | 0 | US%Q_to_J_kg = 1.0 ; US%J_kg_to_Q = 1.0 |
| 189 | 0 | US%C_to_degC = 1.0 ; US%degC_to_C = 1.0 |
| 190 | 0 | US%S_to_ppt = 1.0 ; US%ppt_to_S = 1.0 |
| 191 | ||
| 192 | 0 | call set_unit_scaling_combos(US) |
| 193 | 0 | end subroutine unit_no_scaling_init |
| 194 | ||
| 195 | !> This subroutine sets useful combinations of the fundamental scale conversion factors | |
| 196 | !! in the unit scaling type. | |
| 197 | 1 | subroutine 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: | |
| 201 | 1 | US%Z_to_L = US%Z_to_m * US%m_to_L |
| 202 | 1 | US%L_to_Z = US%L_to_m * US%m_to_Z |
| 203 | ! Horizontal velocities: | |
| 204 | 1 | US%L_T_to_m_s = US%L_to_m * US%s_to_T |
| 205 | 1 | US%m_s_to_L_T = US%m_to_L * US%T_to_s |
| 206 | ! Horizontal accelerations: | |
| 207 | 1 | 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: | |
| 210 | 1 | US%Z2_T_to_m2_s = US%Z_to_m**2 * US%s_to_T |
| 211 | 1 | US%m2_s_to_Z2_T = US%m_to_Z**2 * US%T_to_s |
| 212 | ! Column mass loads: | |
| 213 | 1 | 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: | |
| 216 | 1 | US%kg_m2s_to_RZ_T = US%kg_m3_to_R * US%m_to_Z * US%T_to_s |
| 217 | 1 | 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: | |
| 219 | 1 | US%RZ3_T3_to_W_m2 = US%R_to_kg_m3 * US%Z_to_m**3 * US%s_to_T**3 |
| 220 | 1 | 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: | |
| 222 | 1 | US%W_m2_to_QRZ_T = US%J_kg_to_Q * US%kg_m3_to_R * US%m_to_Z * US%T_to_s |
| 223 | 1 | 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: | |
| 225 | 1 | US%RL2_T2_to_Pa = US%R_to_kg_m3 * US%L_T_to_m_s**2 |
| 226 | 1 | US%Pa_to_RL2_T2 = US%kg_m3_to_R * US%m_s_to_L_T**2 |
| 227 | ! Wind stresses: | |
| 228 | 1 | US%RLZ_T2_to_Pa = US%R_to_kg_m3 * US%L_T_to_m_s**2 * US%Z_to_L |
| 229 | 1 | US%Pa_to_RLZ_T2 = US%kg_m3_to_R * US%m_s_to_L_T**2 * US%L_to_Z |
| 230 | ! Masses: | |
| 231 | 1 | US%RZL2_to_kg = US%R_to_kg_m3 * US%Z_to_m * US%L_to_m**2 |
| 232 | ||
| 233 | 1 | end 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. | |
| 237 | 0 | subroutine 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 | ||
| 243 | 0 | US%m_to_Z_restart = 1.0 ! US%m_to_Z |
| 244 | 0 | US%m_to_L_restart = 1.0 ! US%m_to_L |
| 245 | 0 | US%s_to_T_restart = 1.0 ! US%s_to_T |
| 246 | 0 | US%kg_m3_to_R_restart = 1.0 ! US%kg_m3_to_R |
| 247 | 0 | US%J_kg_to_Q_restart = 1.0 ! US%J_kg_to_Q |
| 248 | ||
| 249 | 0 | if (present(unscaled)) then ; if (unscaled) then |
| 250 | 0 | US%m_to_Z_restart = 1.0 |
| 251 | 0 | US%m_to_L_restart = 1.0 |
| 252 | 0 | US%s_to_T_restart = 1.0 |
| 253 | 0 | US%kg_m3_to_R_restart = 1.0 |
| 254 | 0 | US%J_kg_to_Q_restart = 1.0 |
| 255 | endif ; endif | |
| 256 | ||
| 257 | 0 | end subroutine fix_restart_unit_scaling |
| 258 | ||
| 259 | !> Deallocates a unit scaling structure. | |
| 260 | 1 | subroutine unit_scaling_end( US ) |
| 261 | type(unit_scale_type), pointer :: US !< A dimensional unit scaling type | |
| 262 | ||
| 263 | 1 | deallocate( US ) |
| 264 | ||
| 265 | 1 | end subroutine unit_scaling_end |
| 266 | ||
| 267 | 0 | end module MOM_unit_scaling |