MOM6
mom_sum_output Module Reference

Data Types

type  depth_list
 
type  sum_output_cs
 

Functions/Subroutines

subroutine, public mom_sum_output_init (G, param_file, directory, ntrnc, Input_start_time, CS)
 
subroutine mom_sum_output_end (CS)
 
subroutine, public write_energy (u, v, h, tv, day, n, G, GV, CS, tracer_CSp)
 This subroutine calculates and writes the total model energy, the energy and mass of each layer, and other globally integrated physical quantities. More...
 
subroutine, public accumulate_net_input (fluxes, state, dt, G, CS)
 This subroutine accumates the net input of volume, and perhaps later salt and heat, through the ocean surface for use in diagnosing conservation. More...
 
subroutine depth_list_setup (G, CS)
 This subroutine sets up an ordered list of depths, along with the cross sectional areas at each depth and the volume of fluid deeper than each depth. This might be read from a previously created file or it might be created anew. (For now only new creation occurs. More...
 
subroutine create_depth_list (G, CS)
 create_depth_list makes an ordered list of depths, along with the cross sectional areas at each depth and the volume of fluid deeper than each depth. More...
 
subroutine write_depth_list (G, CS, filename, list_size)
 This subroutine writes out the depth list to the specified file. More...
 
subroutine read_depth_list (G, CS, filename)
 This subroutine reads in the depth list to the specified file and allocates and sets up CSDL and CSlist_size . More...
 

Variables

integer, parameter num_fields = 17
 

Function/Subroutine Documentation

◆ accumulate_net_input()

subroutine, public mom_sum_output::accumulate_net_input ( type(forcing), intent(in)  fluxes,
type(surface), intent(in)  state,
real, intent(in)  dt,
type(ocean_grid_type), intent(in)  G,
type(sum_output_cs), pointer  CS 
)

This subroutine accumates the net input of volume, and perhaps later salt and heat, through the ocean surface for use in diagnosing conservation.

Parameters
[in]fluxesA structure containing pointers to any possible forcing fields. Unused fields are unallocated.
[in]dtThe amount of time over which to average, in s.
[in]gThe ocean's grid structure.
csThe control structure returned by a previous call to MOM_sum_output_init.

Definition at line 890 of file MOM_sum_output.F90.

References mom_error_handler::mom_error().

Referenced by mom_main().

890  type(forcing), intent(in) :: fluxes !< A structure containing pointers to any possible forcing fields. Unused fields are unallocated.
891  type(surface), intent(in) :: state
892  real, intent(in) :: dt !< The amount of time over which to average, in s.
893  type(ocean_grid_type), intent(in) :: g !< The ocean's grid structure.
894  type(sum_output_cs), pointer :: cs !< The control structure returned by a previous call to MOM_sum_output_init.
895 
896 ! This subroutine accumates the net input of volume, and perhaps later salt and
897 ! heat, through the ocean surface for use in diagnosing conservation.
898 ! Arguments: fluxes - A structure containing pointers to any possible
899 ! forcing fields. Unused fields are unallocated.
900 ! (in) dt - The amount of time over which to average.
901 ! (in) G - The ocean's grid structure.
902 ! (in) CS - The control structure returned by a previous call to
903 ! MOM_sum_output_init.
904  real, dimension(SZI_(G),SZJ_(G)) :: &
905  fw_in, & ! The net fresh water input, integrated over a timestep in kg.
906  salt_in, & ! The total salt added by surface fluxes, integrated
907  ! over a time step in ppt*kg.
908  heat_in ! The total heat added by surface fluxes, integrated
909  ! over a time step in Joules.
910  real :: fw_input ! The net fresh water input, integrated over a timestep
911  ! and summed over space, in kg.
912  real :: salt_input ! The total salt added by surface fluxes, integrated
913  ! over a time step and summed over space, in ppt * kg.
914  real :: heat_input ! The total heat added by boundary fluxes, integrated
915  ! over a time step and summed over space, in Joules.
916  real :: c_p ! The heat capacity of seawater, in J K-1 kg-1.
917 
918  type(efp_type) :: &
919  fw_in_efp, & ! Extended fixed point versions of FW_input, salt_input, and
920  salt_in_efp, & ! heat_input, in kg, ppt*kg, and Joules.
921  heat_in_efp
922 
923  real :: inputs(3) ! A mixed array for combining the sums
924  integer :: i, j, is, ie, js, je
925 
926  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec
927  c_p = fluxes%C_p
928 
929  fw_in(:,:) = 0.0 ; fw_input = 0.0
930  if (ASSOCIATED(fluxes%evap)) then
931  if (ASSOCIATED(fluxes%lprec) .and. ASSOCIATED(fluxes%fprec)) then
932  do j=js,je ; do i=is,ie
933  fw_in(i,j) = dt*g%areaT(i,j)*(fluxes%evap(i,j) + &
934  (((fluxes%lprec(i,j) + fluxes%vprec(i,j)) + fluxes%lrunoff(i,j)) + &
935  (fluxes%fprec(i,j) + fluxes%frunoff(i,j))))
936  enddo ; enddo
937  else
938  call mom_error(warning, &
939  "accumulate_net_input called with associated evap field, but no precip field.")
940  endif
941  endif
942 
943  salt_in(:,:) = 0.0 ; heat_in(:,:) = 0.0
944  if (cs%use_temperature) then
945 
946  if (ASSOCIATED(fluxes%sw)) then ; do j=js,je ; do i=is,ie
947  heat_in(i,j) = heat_in(i,j) + dt*g%areaT(i,j) * (fluxes%sw(i,j) + &
948  (fluxes%lw(i,j) + (fluxes%latent(i,j) + fluxes%sens(i,j))))
949  enddo ; enddo ; endif
950 
951  ! smg: new code
952  ! include heat content from water transport across ocean surface
953 ! if (ASSOCIATED(fluxes%heat_content_lprec)) then ; do j=js,je ; do i=is,ie
954 ! heat_in(i,j) = heat_in(i,j) + dt*G%areaT(i,j) * &
955 ! (fluxes%heat_content_lprec(i,j) + (fluxes%heat_content_fprec(i,j) &
956 ! + (fluxes%heat_content_lrunoff(i,j) + (fluxes%heat_content_frunoff(i,j) &
957 ! + (fluxes%heat_content_cond(i,j) + (fluxes%heat_content_vprec(i,j) &
958 ! + fluxes%heat_content_massout(i,j)))))))
959 ! enddo ; enddo ; endif
960 
961  ! smg: old code
962  if (ASSOCIATED(state%TempxPmE)) then
963  do j=js,je ; do i=is,ie
964  heat_in(i,j) = heat_in(i,j) + (c_p * g%areaT(i,j)) * state%TempxPmE(i,j)
965  enddo ; enddo
966  elseif (ASSOCIATED(fluxes%evap)) then
967  do j=js,je ; do i=is,ie
968  heat_in(i,j) = heat_in(i,j) + (c_p * state%SST(i,j)) * fw_in(i,j)
969  enddo ; enddo
970  endif
971 
972 
973  ! The following heat sources may or may not be used.
974  if (ASSOCIATED(state%internal_heat)) then
975  do j=js,je ; do i=is,ie
976  heat_in(i,j) = heat_in(i,j) + (c_p * g%areaT(i,j)) * &
977  state%internal_heat(i,j)
978  enddo ; enddo
979  endif
980  if (ASSOCIATED(state%frazil)) then ; do j=js,je ; do i=is,ie
981  heat_in(i,j) = heat_in(i,j) + g%areaT(i,j) * state%frazil(i,j)
982  enddo ; enddo ; endif
983  if (ASSOCIATED(fluxes%heat_added)) then ; do j=js,je ; do i=is,ie
984  heat_in(i,j) = heat_in(i,j) + dt*g%areaT(i,j)*fluxes%heat_added(i,j)
985  enddo ; enddo ; endif
986 ! if (ASSOCIATED(state%sw_lost)) then ; do j=js,je ; do i=is,ie
987 ! heat_in(i,j) = heat_in(i,j) - G%areaT(i,j) * state%sw_lost(i,j)
988 ! enddo ; enddo ; endif
989 
990  if (ASSOCIATED(fluxes%salt_flux)) then ; do j=js,je ; do i=is,ie
991  ! convert salt_flux from kg (salt)/(m^2 s) to ppt * (m/s).
992  salt_in(i,j) = dt*g%areaT(i,j)*(1000.0*fluxes%salt_flux(i,j))
993  enddo ; enddo ; endif
994  endif
995 
996  if ((cs%use_temperature) .or. ASSOCIATED(fluxes%lprec) .or. &
997  ASSOCIATED(fluxes%evap)) then
998  fw_input = reproducing_sum(fw_in, efp_sum=fw_in_efp)
999  heat_input = reproducing_sum(heat_in, efp_sum=heat_in_efp)
1000  salt_input = reproducing_sum(salt_in, efp_sum=salt_in_efp)
1001 
1002  cs%fresh_water_input = cs%fresh_water_input + fw_input
1003  cs%net_salt_input = cs%net_salt_input + salt_input
1004  cs%net_heat_input = cs%net_heat_input + heat_input
1005 
1006  cs%fresh_water_in_EFP = cs%fresh_water_in_EFP + fw_in_efp
1007  cs%net_salt_in_EFP = cs%net_salt_in_EFP + salt_in_efp
1008  cs%net_heat_in_EFP = cs%net_heat_in_EFP + heat_in_efp
1009  endif
1010 
Ocean grid type. See mom_grid for details.
Definition: MOM_grid.F90:19
Here is the call graph for this function:
Here is the caller graph for this function:

◆ create_depth_list()

subroutine mom_sum_output::create_depth_list ( type(ocean_grid_type), intent(in)  G,
type(sum_output_cs), pointer  CS 
)
private

create_depth_list makes an ordered list of depths, along with the cross sectional areas at each depth and the volume of fluid deeper than each depth.

Parameters
[in]gThe ocean's grid structure.
csThe control structure set up in MOM_sum_output_init, in which the ordered depth list is stored.

Definition at line 1050 of file MOM_sum_output.F90.

Referenced by depth_list_setup().

1050  type(ocean_grid_type), intent(in) :: g !< The ocean's grid structure.
1051  type(sum_output_cs), pointer :: cs !< The control structure set up in MOM_sum_output_init,
1052  !! in which the ordered depth list is stored.
1053 
1054  real, dimension(G%Domain%niglobal*G%Domain%njglobal + 1) :: &
1055  dlist, & !< The global list of bottom depths, in m.
1056  arealist !< The global list of cell areas, in m2.
1057  integer, dimension(G%Domain%niglobal*G%Domain%njglobal+1) :: &
1058  indx2 !< The position of an element in the original unsorted list.
1059  real :: dnow !< The depth now being considered for sorting, in m.
1060  real :: dprev !< The most recent depth that was considered, in m.
1061  real :: vol !< The running sum of open volume below a deptn, in m3.
1062  real :: area !< The open area at the current depth, in m2.
1063  real :: d_list_prev !< The most recent depth added to the list, in m.
1064  logical :: add_to_list !< This depth should be included as an entry on the list.
1065 
1066  integer :: ir, indxt
1067  integer :: mls, list_size
1068  integer :: list_pos, i_global, j_global
1069  integer :: i, j, k, kl
1070 
1071  mls = g%Domain%niglobal*g%Domain%njglobal
1072 
1073 ! Need to collect the global data from compute domains to a 1D array for sorting.
1074  dlist(:) = 0.0
1075  arealist(:) = 0.0
1076  do j=g%jsc,g%jec ; do i=g%isc,g%iec
1077  ! Set global indices that start the global domain at 1 (Fortran convention).
1078  j_global = j + g%jdg_offset - (g%jsg-1)
1079  i_global = i + g%idg_offset - (g%isg-1)
1080 
1081  list_pos = (j_global-1)*g%Domain%niglobal + i_global
1082  dlist(list_pos) = g%bathyT(i,j)
1083  arealist(list_pos) = g%mask2dT(i,j)*g%areaT(i,j)
1084  enddo ; enddo
1085 
1086  ! These sums reproduce across PEs because the arrays are only nonzero on one PE.
1087  call sum_across_pes(dlist, mls+1)
1088  call sum_across_pes(arealist, mls+1)
1089 
1090  do j=1,mls+1 ; indx2(j) = j ; enddo
1091  k = mls / 2 + 1 ; ir = mls
1092  do
1093  if (k > 1) then
1094  k = k - 1
1095  indxt = indx2(k)
1096  dnow = dlist(indxt)
1097  else
1098  indxt = indx2(ir)
1099  dnow = dlist(indxt)
1100  indx2(ir) = indx2(1)
1101  ir = ir - 1
1102  if (ir == 1) then ; indx2(1) = indxt ; exit ; endif
1103  endif
1104  i=k ; j=k*2
1105  do ; if (j > ir) exit
1106  if (j < ir .AND. dlist(indx2(j)) < dlist(indx2(j+1))) j = j + 1
1107  if (dnow < dlist(indx2(j))) then ; indx2(i) = indx2(j) ; i = j ; j = j + i
1108  else ; j = ir+1 ; endif
1109  enddo
1110  indx2(i) = indxt
1111  enddo
1112 
1113 ! At this point, the lists should perhaps be culled to save memory.
1114 ! Culling: (1) identical depths (e.g. land) - take the last one.
1115 ! (2) the topmost and bottommost depths are always saved.
1116 ! (3) very close depths
1117 ! (4) equal volume changes.
1118 
1119  ! Count the unique elements in the list.
1120  d_list_prev = dlist(indx2(mls))
1121  list_size = 2
1122  do k=mls-1,1,-1
1123  if (dlist(indx2(k)) < d_list_prev-cs%D_list_min_inc) then
1124  list_size = list_size + 1
1125  d_list_prev = dlist(indx2(k))
1126  endif
1127  enddo
1128 
1129  cs%list_size = list_size
1130  allocate(cs%DL(cs%list_size+1))
1131 
1132  vol = 0.0 ; area = 0.0
1133  dprev = dlist(indx2(mls))
1134  d_list_prev = dprev
1135 
1136  kl = 0
1137  do k=mls,1,-1
1138  i = indx2(k)
1139  vol = vol + area * (dprev - dlist(i))
1140  area = area + arealist(i)
1141 
1142  add_to_list = .false.
1143  if ((kl == 0) .or. (k==1)) then
1144  add_to_list = .true.
1145  elseif (dlist(indx2(k-1)) < d_list_prev-cs%D_list_min_inc) then
1146  add_to_list = .true.
1147  d_list_prev = dlist(indx2(k-1))
1148  endif
1149 
1150  if (add_to_list) then
1151  kl = kl+1
1152  cs%DL(kl)%depth = dlist(i)
1153  cs%DL(kl)%area = area
1154  cs%DL(kl)%vol_below = vol
1155  endif
1156  dprev = dlist(i)
1157  enddo
1158 
1159  do while (kl < list_size)
1160  ! I don't understand why this is needed... RWH
1161  kl = kl+1
1162  cs%DL(kl)%vol_below = cs%DL(kl-1)%vol_below * 1.000001
1163  cs%DL(kl)%area = cs%DL(kl-1)%area
1164  cs%DL(kl)%depth = cs%DL(kl-1)%depth
1165  enddo
1166 
1167  cs%DL(cs%list_size+1)%vol_below = cs%DL(cs%list_size)%vol_below * 1000.0
1168  cs%DL(cs%list_size+1)%area = cs%DL(cs%list_size)%area
1169  cs%DL(cs%list_size+1)%depth = cs%DL(cs%list_size)%depth
1170 
Ocean grid type. See mom_grid for details.
Definition: MOM_grid.F90:19
Here is the caller graph for this function:

◆ depth_list_setup()

subroutine mom_sum_output::depth_list_setup ( type(ocean_grid_type), intent(in)  G,
type(sum_output_cs), pointer  CS 
)
private

This subroutine sets up an ordered list of depths, along with the cross sectional areas at each depth and the volume of fluid deeper than each depth. This might be read from a previously created file or it might be created anew. (For now only new creation occurs.

Parameters
[in]gThe ocean's grid structure

Definition at line 1018 of file MOM_sum_output.F90.

References create_depth_list(), mom_error_handler::is_root_pe(), mom_error_handler::mom_error(), read_depth_list(), and write_depth_list().

Referenced by mom_sum_output_init().

1018  type(ocean_grid_type), intent(in) :: g !< The ocean's grid structure
1019  type(sum_output_cs), pointer :: cs
1020 ! This subroutine sets up an ordered list of depths, along with the
1021 ! cross sectional areas at each depth and the volume of fluid deeper
1022 ! than each depth. This might be read from a previously created file
1023 ! or it might be created anew. (For now only new creation occurs.
1024 
1025  integer :: k
1026 
1027  if (cs%read_depth_list) then
1028  if (file_exists(cs%depth_list_file)) then
1029  call read_depth_list(g, cs, cs%depth_list_file)
1030  else
1031  if (is_root_pe()) call mom_error(warning, "depth_list_setup: "// &
1032  trim(cs%depth_list_file)//" does not exist. Creating a new file.")
1033  call create_depth_list(g, cs)
1034 
1035  call write_depth_list(g, cs, cs%depth_list_file, cs%list_size+1)
1036  endif
1037  else
1038  call create_depth_list(g, cs)
1039  endif
1040 
1041  do k=1,g%ke
1042  cs%lH(k) = cs%list_size
1043  enddo
1044 
Ocean grid type. See mom_grid for details.
Definition: MOM_grid.F90:19
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mom_sum_output_end()

subroutine mom_sum_output::mom_sum_output_end ( type(sum_output_cs), pointer  CS)
private

Definition at line 286 of file MOM_sum_output.F90.

286  type(sum_output_cs), pointer :: cs
287 ! This subroutine deallocates the memory owned by this module.
288 ! Argument: CS - The control structure returned by a previous call to
289 ! MOM_sum_output_init.
290 
291  if (associated(cs)) then
292  if (cs%do_APE_calc) then
293  dealloc_(cs%lH)
294  deallocate(cs%DL)
295  endif
296 
297  deallocate(cs)
298  endif

◆ mom_sum_output_init()

subroutine, public mom_sum_output::mom_sum_output_init ( type(ocean_grid_type), intent(in)  G,
type(param_file_type), intent(in)  param_file,
character(len=*), intent(in)  directory,
integer, intent(inout), target  ntrnc,
type(time_type), intent(in)  Input_start_time,
type(sum_output_cs), pointer  CS 
)
Parameters
[in]gThe ocean's grid structure.
[in]param_fileA structure to parse for run-time parameters.
[in]directoryThe directory where the energy file goes.
[in,out]ntrncThe integer that stores the number of times the velocity has been truncated since the last call to write_energy.
[in]input_start_timeThe start time of the simulation.
csA pointer that is set to point to the control structure for this module.

Definition at line 164 of file MOM_sum_output.F90.

References depth_list_setup(), and mom_error_handler::mom_error().

Referenced by mom_main(), and ocean_model_mod::ocean_model_init().

164  type(ocean_grid_type), intent(in) :: g !< The ocean's grid structure.
165  type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time
166  !! parameters.
167  character(len=*), intent(in) :: directory !< The directory where the energy file goes.
168  integer, target, intent(inout) :: ntrnc !< The integer that stores the number of times
169  !! the velocity has been truncated since the
170  !! last call to write_energy.
171  type(time_type), intent(in) :: input_start_time !< The start time of the simulation.
172  type(sum_output_cs), pointer :: cs !< A pointer that is set to point to the
173  !! control structure for this module.
174 ! Arguments: G - The ocean's grid structure.
175 ! (in) param_file - A structure indicating the open file to parse for
176 ! model parameter values.
177 ! (in) directory - The directory where the energy file goes.
178 ! (in/out) ntrnc - The integer that stores the number of times the velocity
179 ! has been truncated since the last call to write_energy.
180 ! (in) Input_start_time - The start time of the simulation.
181 ! (in/out) CS - A pointer that is set to point to the control structure
182 ! for this module
183  real :: rho_0, maxvel
184 ! This include declares and sets the variable "version".
185 #include "version_variable.h"
186  character(len=40) :: mdl = "MOM_sum_output" ! This module's name.
187  character(len=200) :: energyfile ! The name of the energy file.
188  character(len=32) :: filename_appendix = '' !fms appendix to filename for ensemble runs
189 
190  if (associated(cs)) then
191  call mom_error(warning, "MOM_sum_output_init called with associated control structure.")
192  return
193  endif
194  allocate(cs)
195 
196  ! Read all relevant parameters and write them to the model log.
197  call log_version(param_file, mdl, version, "")
198  call get_param(param_file, mdl, "CALCULATE_APE", cs%do_APE_calc, &
199  "If true, calculate the available potential energy of \n"//&
200  "the interfaces. Setting this to false reduces the \n"//&
201  "memory footprint of high-PE-count models dramatically.", &
202  default=.true.)
203  call get_param(param_file, mdl, "WRITE_STOCKS", cs%write_stocks, &
204  "If true, write the integrated tracer amounts to stdout \n"//&
205  "when the energy files are written.", default=.true.)
206  call get_param(param_file, mdl, "ENABLE_THERMODYNAMICS", cs%use_temperature, &
207  "If true, Temperature and salinity are used as state \n"//&
208  "variables.", default=.true.)
209  call get_param(param_file, mdl, "DT", cs%dt, &
210  "The (baroclinic) dynamics time step.", units="s", &
211  fail_if_missing=.true.)
212  call get_param(param_file, mdl, "MAXTRUNC", cs%maxtrunc, &
213  "The run will be stopped, and the day set to a very \n"//&
214  "large value if the velocity is truncated more than \n"//&
215  "MAXTRUNC times between energy saves. Set MAXTRUNC to 0 \n"//&
216  "to stop if there is any truncation of velocities.", &
217  units="truncations save_interval-1", default=0)
218 
219  call get_param(param_file, mdl, "MAX_ENERGY", cs%max_Energy, &
220  "The maximum permitted average energy per unit mass; the \n"//&
221  "model will be stopped if there is more energy than \n"//&
222  "this. If zero or negative, this is set to 10*MAXVEL^2.", &
223  units="m2 s-2", default=0.0)
224  if (cs%max_Energy <= 0.0) then
225  call get_param(param_file, mdl, "MAXVEL", maxvel, &
226  "The maximum velocity allowed before the velocity \n"//&
227  "components are truncated.", units="m s-1", default=3.0e8)
228  cs%max_Energy = 10.0 * maxvel**2
229  call log_param (param_file, mdl, "MAX_ENERGY as used", cs%max_Energy)
230  endif
231 
232  call get_param(param_file, mdl, "ENERGYFILE", energyfile, &
233  "The file to use to write the energies and globally \n"//&
234  "summed diagnostics.", default="ocean.stats")
235 
236  !query fms_io if there is a filename_appendix (for ensemble runs)
237  call get_filename_appendix(filename_appendix)
238  if(len_trim(filename_appendix) > 0) then
239  energyfile = trim(energyfile) //'.'//trim(filename_appendix)
240  end if
241 
242  cs%energyfile = trim(slasher(directory))//trim(energyfile)
243  call log_param(param_file, mdl, "output_path/ENERGYFILE", cs%energyfile)
244 #ifdef STATSLABEL
245  cs%energyfile = trim(cs%energyfile)//"."//trim(adjustl(statslabel))
246 #endif
247 
248  call get_param(param_file, mdl, "DATE_STAMPED_STDOUT", cs%date_stamped_output, &
249  "If true, use dates (not times) in messages to stdout", &
250  default=.true.)
251  call get_param(param_file, mdl, "TIMEUNIT", cs%Timeunit, &
252  "The time unit in seconds a number of input fields", &
253  units="s", default=86400.0)
254  if (cs%Timeunit < 0.0) cs%Timeunit = 86400.0
255 
256 
257 
258  if (cs%do_APE_calc) then
259  call get_param(param_file, mdl, "READ_DEPTH_LIST", cs%read_depth_list, &
260  "Read the depth list from a file if it exists or \n"//&
261  "create that file otherwise.", default=.false.)
262  call get_param(param_file, mdl, "DEPTH_LIST_MIN_INC", cs%D_list_min_inc, &
263  "The minimum increment between the depths of the \n"//&
264  "entries in the depth-list file.", units="m", &
265  default=1.0e-10)
266  if (cs%read_depth_list) then
267  call get_param(param_file, mdl, "DEPTH_LIST_FILE", cs%depth_list_file, &
268  "The name of the depth list file.", default="Depth_list.nc")
269  if (scan(cs%depth_list_file,'/') == 0) &
270  cs%depth_list_file = trim(slasher(directory))//trim(cs%depth_list_file)
271  endif
272 
273  alloc_(cs%lH(g%ke))
274  call depth_list_setup(g, cs)
275  else
276  cs%list_size = 0
277  endif
278 
279  cs%Huge_time = set_time(int(1e9),0)
280  cs%Start_time = input_start_time
281  cs%ntrunc => ntrnc
282 
Ocean grid type. See mom_grid for details.
Definition: MOM_grid.F90:19
Here is the call graph for this function:
Here is the caller graph for this function:

◆ read_depth_list()

subroutine mom_sum_output::read_depth_list ( type(ocean_grid_type), intent(in)  G,
type(sum_output_cs), pointer  CS,
character(len=*), intent(in)  filename 
)
private

This subroutine reads in the depth list to the specified file and allocates and sets up CSDL and CSlist_size .

Parameters
[in]gThe ocean's grid structure

Definition at line 1257 of file MOM_sum_output.F90.

References mom_error_handler::mom_error().

Referenced by depth_list_setup().

1257  type(ocean_grid_type), intent(in) :: g !< The ocean's grid structure
1258  type(sum_output_cs), pointer :: cs
1259  character(len=*), intent(in) :: filename
1260 
1261 ! This subroutine reads in the depth list to the specified file
1262 ! and allocates and sets up CS%DL and CS%list_size .
1263  character(len=32) :: mdl
1264  character(len=240) :: var_name, var_msg
1265  real, allocatable :: tmp(:)
1266  integer :: ncid, status, varid, list_size, k
1267  integer :: ndim, len, var_dim_ids(nf90_max_var_dims)
1268 
1269  mdl = "MOM_sum_output read_depth_list:"
1270 
1271  status = nf90_open(filename, nf90_nowrite, ncid);
1272  if (status /= nf90_noerr) then
1273  call mom_error(fatal,mdl//" Difficulties opening "//trim(filename)// &
1274  " - "//trim(nf90_strerror(status)))
1275  endif
1276 
1277  var_name = "depth"
1278  var_msg = trim(var_name)//" in "//trim(filename)//" - "
1279  status = nf90_inq_varid(ncid, var_name, varid)
1280  if (status /= nf90_noerr) call mom_error(fatal,mdl// &
1281  " Difficulties finding variable "//trim(var_msg)//&
1282  trim(nf90_strerror(status)))
1283 
1284  status = nf90_inquire_variable(ncid, varid, ndims=ndim, dimids=var_dim_ids)
1285  if (status /= nf90_noerr) then
1286  call mom_error(fatal,mdl//" cannot inquire about "//trim(var_msg)//&
1287  trim(nf90_strerror(status)))
1288  elseif (ndim > 1) then
1289  call mom_error(fatal,mdl//" "//trim(var_msg)//&
1290  " has too many or too few dimensions.")
1291  endif
1292 
1293  ! Get the length of the list.
1294  status = nf90_inquire_dimension(ncid, var_dim_ids(1), len=list_size)
1295  if (status /= nf90_noerr) call mom_error(fatal,mdl// &
1296  " cannot inquire about dimension(1) of "//trim(var_msg)//&
1297  trim(nf90_strerror(status)))
1298 
1299  cs%list_size = list_size-1
1300  allocate(cs%DL(list_size))
1301  allocate(tmp(list_size))
1302 
1303  status = nf90_get_var(ncid, varid, tmp)
1304  if (status /= nf90_noerr) call mom_error(fatal,mdl// &
1305  " Difficulties reading variable "//trim(var_msg)//&
1306  trim(nf90_strerror(status)))
1307 
1308  do k=1,list_size ; cs%DL(k)%depth = tmp(k) ; enddo
1309 
1310  var_name = "area"
1311  var_msg = trim(var_name)//" in "//trim(filename)//" - "
1312  status = nf90_inq_varid(ncid, var_name, varid)
1313  if (status /= nf90_noerr) call mom_error(fatal,mdl// &
1314  " Difficulties finding variable "//trim(var_msg)//&
1315  trim(nf90_strerror(status)))
1316  status = nf90_get_var(ncid, varid, tmp)
1317  if (status /= nf90_noerr) call mom_error(fatal,mdl// &
1318  " Difficulties reading variable "//trim(var_msg)//&
1319  trim(nf90_strerror(status)))
1320 
1321  do k=1,list_size ; cs%DL(k)%area = tmp(k) ; enddo
1322 
1323  var_name = "vol_below"
1324  var_msg = trim(var_name)//" in "//trim(filename)
1325  status = nf90_inq_varid(ncid, var_name, varid)
1326  if (status /= nf90_noerr) call mom_error(fatal,mdl// &
1327  " Difficulties finding variable "//trim(var_msg)//&
1328  trim(nf90_strerror(status)))
1329  status = nf90_get_var(ncid, varid, tmp)
1330  if (status /= nf90_noerr) call mom_error(fatal,mdl// &
1331  " Difficulties reading variable "//trim(var_msg)//&
1332  trim(nf90_strerror(status)))
1333 
1334  do k=1,list_size ; cs%DL(k)%vol_below = tmp(k) ; enddo
1335 
1336  status = nf90_close(ncid)
1337  if (status /= nf90_noerr) call mom_error(warning, mdl// &
1338  " Difficulties closing "//trim(filename)//" - "//trim(nf90_strerror(status)))
1339 
1340  deallocate(tmp)
1341 
Ocean grid type. See mom_grid for details.
Definition: MOM_grid.F90:19
Here is the call graph for this function:
Here is the caller graph for this function:

◆ write_depth_list()

subroutine mom_sum_output::write_depth_list ( type(ocean_grid_type), intent(in)  G,
type(sum_output_cs), pointer  CS,
character(len=*), intent(in)  filename,
integer, intent(in)  list_size 
)
private

This subroutine writes out the depth list to the specified file.

Parameters
[in]gThe ocean's grid structure.

Definition at line 1175 of file MOM_sum_output.F90.

References mom_error_handler::is_root_pe(), and mom_error_handler::mom_error().

Referenced by depth_list_setup().

1175  type(ocean_grid_type), intent(in) :: g !< The ocean's grid structure.
1176  type(sum_output_cs), pointer :: cs
1177  character(len=*), intent(in) :: filename
1178  integer, intent(in) :: list_size
1179 
1180 ! This subroutine writes out the depth list to the specified file.
1181 
1182  real, allocatable :: tmp(:)
1183  integer :: ncid, dimid(1), did, aid, vid, status, k
1184 
1185  if (.not.is_root_pe()) return
1186 
1187  allocate(tmp(list_size)) ; tmp(:) = 0.0
1188 
1189  status = nf90_create(filename, 0, ncid)
1190  if (status /= nf90_noerr) then
1191  call mom_error(warning, filename//trim(nf90_strerror(status)))
1192  return
1193  endif
1194 
1195  status = nf90_def_dim(ncid, "list", list_size, dimid(1))
1196  if (status /= nf90_noerr) call mom_error(warning, &
1197  filename//trim(nf90_strerror(status)))
1198 
1199  status = nf90_def_var(ncid, "depth", nf90_double, dimid, did)
1200  if (status /= nf90_noerr) call mom_error(warning, &
1201  filename//" depth "//trim(nf90_strerror(status)))
1202  status = nf90_put_att(ncid, did, "long_name", "Sorted depth")
1203  if (status /= nf90_noerr) call mom_error(warning, &
1204  filename//" depth "//trim(nf90_strerror(status)))
1205  status = nf90_put_att(ncid, did, "units", "m")
1206  if (status /= nf90_noerr) call mom_error(warning, &
1207  filename//" depth "//trim(nf90_strerror(status)))
1208 
1209  status = nf90_def_var(ncid, "area", nf90_double, dimid, aid)
1210  if (status /= nf90_noerr) call mom_error(warning, &
1211  filename//" area "//trim(nf90_strerror(status)))
1212  status = nf90_put_att(ncid, aid, "long_name", "Open area at depth")
1213  if (status /= nf90_noerr) call mom_error(warning, &
1214  filename//" area "//trim(nf90_strerror(status)))
1215  status = nf90_put_att(ncid, aid, "units", "m2")
1216  if (status /= nf90_noerr) call mom_error(warning, &
1217  filename//" area "//trim(nf90_strerror(status)))
1218 
1219  status = nf90_def_var(ncid, "vol_below", nf90_double, dimid, vid)
1220  if (status /= nf90_noerr) call mom_error(warning, &
1221  filename//" vol_below "//trim(nf90_strerror(status)))
1222  status = nf90_put_att(ncid, vid, "long_name", "Open volume below depth")
1223  if (status /= nf90_noerr) call mom_error(warning, &
1224  filename//" vol_below "//trim(nf90_strerror(status)))
1225  status = nf90_put_att(ncid, vid, "units", "m3")
1226  if (status /= nf90_noerr) call mom_error(warning, &
1227  filename//" vol_below "//trim(nf90_strerror(status)))
1228 
1229  status = nf90_enddef(ncid)
1230  if (status /= nf90_noerr) call mom_error(warning, &
1231  filename//trim(nf90_strerror(status)))
1232 
1233  do k=1,list_size ; tmp(k) = cs%DL(k)%depth ; enddo
1234  status = nf90_put_var(ncid, did, tmp)
1235  if (status /= nf90_noerr) call mom_error(warning, &
1236  filename//" depth "//trim(nf90_strerror(status)))
1237 
1238  do k=1,list_size ; tmp(k) = cs%DL(k)%area ; enddo
1239  status = nf90_put_var(ncid, aid, tmp)
1240  if (status /= nf90_noerr) call mom_error(warning, &
1241  filename//" area "//trim(nf90_strerror(status)))
1242 
1243  do k=1,list_size ; tmp(k) = cs%DL(k)%vol_below ; enddo
1244  status = nf90_put_var(ncid, vid, tmp)
1245  if (status /= nf90_noerr) call mom_error(warning, &
1246  filename//" vol_below "//trim(nf90_strerror(status)))
1247 
1248  status = nf90_close(ncid)
1249  if (status /= nf90_noerr) call mom_error(warning, &
1250  filename//trim(nf90_strerror(status)))
1251 
Ocean grid type. See mom_grid for details.
Definition: MOM_grid.F90:19
Here is the call graph for this function:
Here is the caller graph for this function:

◆ write_energy()

subroutine, public mom_sum_output::write_energy ( real, dimension( g %isdb: g %iedb, g %jsd: g %jed, g %ke), intent(in)  u,
real, dimension( g %isd: g %ied, g %jsdb: g %jedb, g %ke), intent(in)  v,
real, dimension( g %isd: g %ied, g %jsd: g %jed, g %ke), intent(in)  h,
type(thermo_var_ptrs), intent(in)  tv,
type(time_type), intent(inout)  day,
integer, intent(in)  n,
type(ocean_grid_type), intent(in)  G,
type(verticalgrid_type), intent(in)  GV,
type(sum_output_cs), pointer  CS,
type(tracer_flow_control_cs), optional, pointer  tracer_CSp 
)

This subroutine calculates and writes the total model energy, the energy and mass of each layer, and other globally integrated physical quantities.

Parameters
[in]gThe ocean's grid structure.
[in]gvThe ocean's vertical grid structure.
[in]uThe zonal velocity, in m s-1.
[in]vThe meridional velocity, in m s-1.
[in]hLayer thicknesses, in H (usually m or kg m-2).
[in]tvA structure pointing to various thermodynamic variables.
[in,out]dayThe current model time.
[in]nThe time step number of the current execution.
csThe control structure returned by a previous call to MOM_sum_output_init.

Definition at line 305 of file MOM_sum_output.F90.

References mom_tracer_flow_control::call_tracer_stocks(), mom_coms::efp_to_real(), mom_error_handler::is_root_pe(), mom_error_handler::mom_error(), and mom_coms::real_to_efp().

Referenced by mom_main().

305  type(ocean_grid_type), intent(in) :: g !< The ocean's grid structure.
306  type(verticalgrid_type), intent(in) :: gv !< The ocean's vertical grid
307  !! structure.
308  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), intent(in) :: u !< The zonal velocity, in m s-1.
309  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), intent(in) :: v !< The meridional velocity,
310  !! in m s-1.
311  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h !< Layer thicknesses, in H
312  !! (usually m or kg m-2).
313  type(thermo_var_ptrs), intent(in) :: tv !< A structure pointing to various
314  !! thermodynamic variables.
315  type(time_type), intent(inout) :: day !< The current model time.
316  integer, intent(in) :: n !< The time step number of the
317  !! current execution.
318  type(sum_output_cs), pointer :: cs !< The control structure returned
319  !! by a previous call to
320  !! MOM_sum_output_init.
321  type(tracer_flow_control_cs), optional, pointer :: tracer_csp
322 
323 
324 ! This subroutine calculates and writes the total model energy, the
325 ! energy and mass of each layer, and other globally integrated
326 ! physical quantities.
327 
328 ! Arguments: u - Zonal velocity, in m s-1.
329 ! (in) v - Meridional velocity, in m s-1.
330 ! (in) h - Layer thickness, in m.
331 ! (in) tv - A structure containing pointers to any available
332 ! thermodynamic fields, including potential temperature and
333 ! salinity or mixed layer density. Absent fields have NULL ptrs.
334 ! (in/out) day - The current model time.
335 ! (in) n - The time step number of the current execution.
336 ! (in) G - The ocean's grid structure.
337 ! (in) GV - The ocean's vertical grid structure.
338 ! (in) CS - The control structure returned by a previous call to
339 ! MOM_sum_output_init.
340 
341  real :: eta(szi_(g),szj_(g),szk_(g)+1) ! The height of interfaces, in m.
342  real :: areatm(szi_(g),szj_(g)) ! A masked version of areaT, in m2.
343  real :: ke(szk_(g)) ! The total kinetic energy of a layer, in J.
344  real :: pe(szk_(g)+1)! The available potential energy of an interface, in J.
345  real :: ke_tot ! The total kinetic energy, in J.
346  real :: pe_tot ! The total available potential energy, in J.
347  real :: h_0ape(szk_(g)+1) ! The uniform depth which overlies the same
348  ! volume as is below an interface, in m.
349  ! H is usually positive.
350  real :: toten ! The total kinetic & potential energies of
351  ! all layers, in Joules (i.e. kg m2 s-2).
352  real :: en_mass ! The total kinetic and potential energies divided by
353  ! the total mass of the ocean, in m2 s-2.
354  real :: vol_lay(szk_(g)) ! The volume of fluid in a layer, in m3.
355  real :: volbelow ! The volume of all layers beneath an interface in m3.
356  real :: mass_lay(szk_(g)) ! The mass of fluid in a layer, in kg.
357  real :: mass_tot ! The total mass of the ocean in kg.
358  real :: vol_tot ! The total ocean volume in m3.
359  real :: mass_chg ! The change in total ocean mass of fresh water since
360  ! the last call to this subroutine, in kg.
361  real :: mass_anom ! The change in fresh water that cannot be accounted for
362  ! by the surface fluxes, in kg.
363  real :: salt ! The total amount of salt in the ocean, in PSU kg.
364  real :: salt_chg ! The change in total ocean salt since the last call
365  ! to this subroutine, in PSU kg.
366  real :: salt_anom ! The change in salt that cannot be accounted for by
367  ! the surface fluxes, in PSU kg.
368  real :: salin ! The mean salinity of the ocean, in PSU.
369  real :: salin_chg ! The change in total salt since the last call
370  ! to this subroutine divided by total mass, in PSU.
371  real :: salin_anom ! The change in total salt that cannot be accounted for by
372  ! the surface fluxes divided by total mass in PSU.
373  real :: salin_mass_in ! The mass of salt input since the last call, kg.
374  real :: heat ! The total amount of Heat in the ocean, in Joules.
375  real :: heat_chg ! The change in total ocean heat since the last call
376  ! to this subroutine, in Joules.
377  real :: heat_anom ! The change in heat that cannot be accounted for by
378  ! the surface fluxes, in Joules.
379  real :: temp ! The mean potential temperature of the ocean, in C.
380  real :: temp_chg ! The change in total heat divided by total heat capacity
381  ! of the ocean since the last call to this subroutine, C.
382  real :: temp_anom ! The change in total heat that cannot be accounted for
383  ! by the surface fluxes, divided by the total heat
384  ! capacity of the ocean, in C.
385  real :: hint ! The deviation of an interface from H, in m.
386  real :: hbot ! 0 if the basin is deeper than H, or the
387  ! height of the basin depth over H otherwise,
388  ! in m. This makes PE only include real fluid.
389  real :: hbelow ! The depth of fluid in all layers beneath
390  ! an interface, in m.
391  type(efp_type) :: &
392  mass_efp, & ! Extended fixed point sums of total mass, etc.
393  salt_efp, heat_efp, salt_chg_efp, heat_chg_efp, mass_chg_efp, &
394  mass_anom_efp, salt_anom_efp, heat_anom_efp
395  real :: cfl_trans ! A transport-based definition of the CFL number, nondim.
396  real :: cfl_lin ! A simpler definition of the CFL number, nondim.
397  real :: max_cfl(2) ! The maxima of the CFL numbers, nondim.
398  real :: irho0
399  real, dimension(SZI_(G),SZJ_(G),SZK_(G)) :: &
400  tmp1
401  real, dimension(SZI_(G),SZJ_(G),SZK_(G)+1) :: &
402  pe_pt
403  real, dimension(SZI_(G),SZJ_(G)) :: &
404  temp_int, salt_int
405  real :: h_to_m, h_to_kg_m2 ! Local copies of unit conversion factors.
406  integer :: num_nc_fields ! The number of fields that will actually go into
407  ! the NetCDF file.
408  integer :: i, j, k, is, ie, js, je, nz, m, isq, ieq, jsq, jeq
409  integer :: l, lbelow, labove ! indices of deep_area_vol, used to find
410  ! H. lbelow & labove are lower & upper
411  ! limits for l in the search for lH.
412  integer :: start_of_day, num_days
413  real :: reday, var
414  character(len=240) :: energypath_nc
415  character(len=200) :: mesg
416  character(len=32) :: mesg_intro, time_units, day_str, n_str, date_str
417  logical :: date_stamped
418  real :: tr_stocks(max_fields_)
419  real :: tr_min(max_fields_),tr_max(max_fields_)
420  real :: tr_min_x(max_fields_), tr_min_y(max_fields_), tr_min_z(max_fields_)
421  real :: tr_max_x(max_fields_), tr_max_y(max_fields_), tr_max_z(max_fields_)
422  logical :: tr_minmax_got(max_fields_) = .false.
423  character(len=40), dimension(MAX_FIELDS_) :: &
424  tr_names, tr_units
425  integer :: ntr_stocks
426  real, allocatable :: toten_pe(:)
427  integer :: pe_num
428  integer :: iyear, imonth, iday, ihour, iminute, isecond, itick ! For call to get_date()
429 
430  ! A description for output of each of the fields.
431  type(vardesc) :: vars(num_fields+max_fields_)
432 
433  num_nc_fields = 17
434  if (.not.cs%use_temperature) num_nc_fields = 11
435  vars(1) = var_desc("Ntrunc","Nondim","Number of Velocity Truncations",'1','1')
436  vars(2) = var_desc("En","Joules","Total Energy",'1','1')
437  vars(3) = var_desc("APE","Joules","Total Interface APE",'1','i')
438  vars(4) = var_desc("KE","Joules","Total Layer KE",'1','L')
439  vars(5) = var_desc("H0","meter","Zero APE Depth of Interface",'1','i')
440  vars(6) = var_desc("Mass_lay","kg","Total Layer Mass",'1','L')
441  vars(7) = var_desc("Mass","kg","Total Mass",'1','1')
442  vars(8) = var_desc("Mass_chg","kg","Total Mass Change between Entries",'1','1')
443  vars(9) = var_desc("Mass_anom","kg","Anomalous Total Mass Change",'1','1')
444  vars(10) = var_desc("max_CFL_trans","Nondim","Maximum finite-volume CFL",'1','1')
445  vars(11) = var_desc("max_CFL_lin","Nondim","Maximum finite-difference CFL",'1','1')
446  if (cs%use_temperature) then
447  vars(12) = var_desc("Salt","kg","Total Salt",'1','1')
448  vars(13) = var_desc("Salt_chg","kg","Total Salt Change between Entries",'1','1')
449  vars(14) = var_desc("Salt_anom","kg","Anomalous Total Salt Change",'1','1')
450  vars(15) = var_desc("Heat","Joules","Total Heat",'1','1')
451  vars(16) = var_desc("Heat_chg","Joules","Total Heat Change between Entries",'1','1')
452  vars(17) = var_desc("Heat_anom","Joules","Anomalous Total Heat Change",'1','1')
453  endif
454 
455  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
456  isq = g%IscB ; ieq = g%IecB ; jsq = g%JscB ; jeq = g%JecB
457  h_to_m = gv%H_to_m ; h_to_kg_m2 = gv%H_to_kg_m2
458 
459  if (.not.associated(cs)) call mom_error(fatal, &
460  "write_energy: Module must be initialized before it is used.")
461 
462  do j=js,je ; do i=is,ie
463  areatm(i,j) = g%mask2dT(i,j)*g%areaT(i,j)
464  enddo ; enddo
465 
466  if (gv%Boussinesq) then
467  tmp1(:,:,:) = 0.0
468  do k=1,nz ; do j=js,je ; do i=is,ie
469  tmp1(i,j,k) = h(i,j,k) * (h_to_kg_m2*areatm(i,j))
470  enddo ; enddo ; enddo
471  mass_tot = reproducing_sum(tmp1, sums=mass_lay, efp_sum=mass_efp)
472  do k=1,nz ; vol_lay(k) = (h_to_m/h_to_kg_m2)*mass_lay(k) ; enddo
473  else
474  tmp1(:,:,:) = 0.0
475  if (cs%do_APE_calc) then
476  do k=1,nz ; do j=js,je ; do i=is,ie
477  tmp1(i,j,k) = h_to_kg_m2 * h(i,j,k) * areatm(i,j)
478  enddo ; enddo ; enddo
479  mass_tot = reproducing_sum(tmp1, sums=mass_lay, efp_sum=mass_efp)
480 
481  call find_eta(h, tv, gv%g_Earth, g, gv, eta)
482  do k=1,nz ; do j=js,je ; do i=is,ie
483  tmp1(i,j,k) = (eta(i,j,k)-eta(i,j,k+1)) * areatm(i,j)
484  enddo ; enddo ; enddo
485  vol_tot = h_to_m*reproducing_sum(tmp1, sums=vol_lay)
486  else
487  do k=1,nz ; do j=js,je ; do i=is,ie
488  tmp1(i,j,k) = h_to_kg_m2 * h(i,j,k) * areatm(i,j)
489  enddo ; enddo ; enddo
490  mass_tot = reproducing_sum(tmp1, sums=mass_lay, efp_sum=mass_efp)
491  do k=1,nz ; vol_lay(k) = mass_lay(k) / gv%Rho0 ; enddo
492  endif
493  endif ! Boussinesq
494 
495  ntr_stocks = 0
496  if (present(tracer_csp)) then
497  call call_tracer_stocks(h, tr_stocks, g, gv, tracer_csp, stock_names=tr_names, &
498  stock_units=tr_units, num_stocks=ntr_stocks,&
499  got_min_max=tr_minmax_got, global_min=tr_min, global_max=tr_max, &
500  xgmin=tr_min_x, ygmin=tr_min_y, zgmin=tr_min_z,&
501  xgmax=tr_max_x, ygmax=tr_max_y, zgmax=tr_max_z)
502  if (ntr_stocks > 0) then
503  do m=1,ntr_stocks
504  vars(num_nc_fields+m) = var_desc(tr_names(m), units=tr_units(m), &
505  longname=tr_names(m), hor_grid='1', z_grid='1')
506  enddo
507  num_nc_fields = num_nc_fields + ntr_stocks
508  endif
509  endif
510 
511  if (cs%previous_calls == 0) then
512  cs%mass_prev = mass_tot ; cs%fresh_water_input = 0.0
513 
514  cs%mass_prev_EFP = mass_efp
515  cs%fresh_water_in_EFP = real_to_efp(0.0)
516 
517  ! Reopen or create a text output file, with an explanatory header line.
518  if (is_root_pe()) then
519  if (day > cs%Start_time) then
520  call open_file(cs%fileenergy_ascii, trim(cs%energyfile), &
521  action=append_file, form=ascii_file, nohdrs=.true.)
522  else
523  call open_file(cs%fileenergy_ascii, trim(cs%energyfile), &
524  action=writeonly_file, form=ascii_file, nohdrs=.true.)
525  if (abs(cs%timeunit - 86400.0) < 1.0) then
526  if (cs%use_temperature) then
527  write(cs%fileenergy_ascii,'(" Step,",7x,"Day, Truncs, &
528  &Energy/Mass, Maximum CFL, Mean Sea Level, Total Mass, Mean Salin, &
529  &Mean Temp, Frac Mass Err, Salin Err, Temp Err")')
530  write(cs%fileenergy_ascii,'(12x,"[days]",17x,"[m2 s-2]",11x,"[Nondim]",7x,"[m]",13x,&
531  &"[kg]",9x,"[PSU]",6x,"[degC]",7x,"[Nondim]",8x,"[PSU]",8x,"[degC]")')
532  else
533  write(cs%fileenergy_ascii,'(" Step,",7x,"Day, Truncs, &
534  &Energy/Mass, Maximum CFL, Mean sea level, Total Mass, Frac Mass Err")')
535  write(cs%fileenergy_ascii,'(12x,"[days]",17x,"[m2 s-2]",11x,"[Nondim]",8x,"[m]",13x,&
536  &"[kg]",11x,"[Nondim]")')
537  endif
538  else
539  if ((cs%timeunit >= 0.99) .and. (cs%timeunit < 1.01)) then
540  time_units = " [seconds] "
541  else if ((cs%timeunit >= 3599.0) .and. (cs%timeunit < 3601.0)) then
542  time_units = " [hours] "
543  else if ((cs%timeunit >= 86399.0) .and. (cs%timeunit < 86401.0)) then
544  time_units = " [days] "
545  else if ((cs%timeunit >= 3.0e7) .and. (cs%timeunit < 3.2e7)) then
546  time_units = " [years] "
547  else
548  write(time_units,'(9x,"[",es8.2," s] ")') cs%timeunit
549  endif
550 
551  if (cs%use_temperature) then
552  write(cs%fileenergy_ascii,'(" Step,",7x,"Time, Truncs, &
553  &Energy/Mass, Maximum CFL, Mean Sea Level, Total Mass, Mean Salin, &
554  &Mean Temp, Frac Mass Err, Salin Err, Temp Err")')
555  write(cs%fileenergy_ascii,'(A25,10x,"[m2 s-2]",11x,"[Nondim]",7x,"[m]",13x,&
556  &"[kg]",9x,"[PSU]",6x,"[degC]",7x,"[Nondim]",8x,"[PSU]",6x,&
557  &"[degC]")') time_units
558  else
559  write(cs%fileenergy_ascii,'(" Step,",7x,"Time, Truncs, &
560  &Energy/Mass, Maximum CFL, Mean sea level, Total Mass, Frac Mass Err")')
561  write(cs%fileenergy_ascii,'(A25,10x,"[m2 s-2]",11x,"[Nondim]",8x,"[m]",13x,&
562  &"[kg]",11x,"[Nondim]")') time_units
563  endif
564  endif
565  endif
566  endif
567 
568  energypath_nc = trim(cs%energyfile) // ".nc"
569  if (day > cs%Start_time) then
570  call reopen_file(cs%fileenergy_nc, trim(energypath_nc), vars, &
571  num_nc_fields, cs%fields, single_file, cs%timeunit, &
572  g=g, gv=gv)
573  else
574  call create_file(cs%fileenergy_nc, trim(energypath_nc), vars, &
575  num_nc_fields, cs%fields, single_file, cs%timeunit, &
576  g=g, gv=gv)
577  endif
578  endif
579 
580  if (cs%do_APE_calc) then
581  lbelow = 1 ; volbelow = 0.0
582  do k=nz,1,-1
583  volbelow = volbelow + vol_lay(k)
584  if ((volbelow >= cs%DL(cs%lH(k))%vol_below) .and. &
585  (volbelow < cs%DL(cs%lH(k)+1)%vol_below)) then
586  l = cs%lH(k)
587  else
588  labove=cs%list_size+1
589  l = (labove + lbelow) / 2
590  do while (l > lbelow)
591  if (volbelow < cs%DL(l)%vol_below) then ; labove = l
592  else ; lbelow = l ; endif
593  l = (labove + lbelow) / 2
594  enddo
595  cs%lH(k) = l
596  endif
597  lbelow = l
598  h_0ape(k) = cs%DL(l)%depth - (volbelow - cs%DL(l)%vol_below) / cs%DL(l)%area
599  enddo
600  h_0ape(nz+1) = cs%DL(2)%depth
601  else
602  do k=1,nz+1 ; h_0ape(k) = 0.0 ; enddo
603  endif
604 
605 ! Calculate the Kinetic Energy integrated over each layer.
606  tmp1(:,:,:) = 0.0
607  do k=1,nz ; do j=js,je ; do i=is,ie
608  tmp1(i,j,k) = (0.25 * h_to_kg_m2 * (areatm(i,j) * h(i,j,k))) * &
609  (u(i-1,j,k)**2 + u(i,j,k)**2 + v(i,j-1,k)**2 + v(i,j,k)**2)
610  enddo ; enddo ; enddo
611 
612 ! Calculate the Available Potential Energy integrated over each
613 ! interface. With a nonlinear equation of state or with a bulk
614 ! mixed layer this calculation is only approximate.
615  do k=1,nz+1 ; pe(k) = 0.0 ; enddo
616  if (cs%do_APE_calc) then
617  pe_pt(:,:,:) = 0.0
618  if (gv%Boussinesq) then
619  do j=js,je ; do i=is,ie
620  hbelow = 0.0
621  do k=nz,1,-1
622  hbelow = hbelow + h(i,j,k) * h_to_m
623  hint = (h_0ape(k) + hbelow - g%bathyT(i,j))
624  hbot = h_0ape(k) - g%bathyT(i,j)
625  hbot = (hbot + abs(hbot)) * 0.5
626  pe_pt(i,j,k) = 0.5 * areatm(i,j) * (gv%Rho0*gv%g_prime(k)) * &
627  (hint * hint - hbot * hbot)
628  enddo
629  enddo ; enddo
630  else
631  do j=js,je ; do i=is,ie
632  hbelow = 0.0
633  do k=nz,1,-1
634  hint = h_0ape(k) + eta(i,j,k) ! eta and H_0 have opposite signs.
635  hbot = max(h_0ape(k) - g%bathyT(i,j), 0.0)
636  pe_pt(i,j,k) = 0.5 * (areatm(i,j) * (gv%Rho0*gv%g_prime(k))) * &
637  (hint * hint - hbot * hbot)
638  enddo
639  enddo ; enddo
640  endif
641  endif
642 
643  ke_tot = reproducing_sum(tmp1, sums=ke)
644  pe_tot = 0.0
645  if (cs%do_APE_calc) &
646  pe_tot = reproducing_sum(pe_pt, sums=pe)
647  toten = ke_tot + pe_tot
648 
649  salt = 0.0 ; heat = 0.0
650  if (cs%use_temperature) then
651  temp_int(:,:) = 0.0 ; salt_int(:,:) = 0.0
652  do k=1,nz ; do j=js,je ; do i=is,ie
653  salt_int(i,j) = salt_int(i,j) + tv%S(i,j,k) * &
654  (h(i,j,k)*(h_to_kg_m2 * areatm(i,j)))
655  temp_int(i,j) = temp_int(i,j) + (tv%C_p * tv%T(i,j,k)) * &
656  (h(i,j,k)*(h_to_kg_m2 * areatm(i,j)))
657  enddo ; enddo ; enddo
658  salt = reproducing_sum(salt_int, efp_sum=salt_efp)
659  heat = reproducing_sum(temp_int, efp_sum=heat_efp)
660  endif
661 
662 ! Calculate the maximum CFL numbers.
663  max_cfl(1:2) = 0.0
664  do k=1,nz ; do j=js,je ; do i=isq,ieq
665  if (u(i,j,k) < 0.0) then
666  cfl_trans = (-u(i,j,k) * cs%dt) * (g%dy_Cu(i,j) * g%IareaT(i+1,j))
667  else
668  cfl_trans = (u(i,j,k) * cs%dt) * (g%dy_Cu(i,j) * g%IareaT(i,j))
669  endif
670  cfl_lin = abs(u(i,j,k) * cs%dt) * g%IdxCu(i,j)
671  max_cfl(1) = max(max_cfl(1), cfl_trans)
672  max_cfl(2) = max(max_cfl(2), cfl_lin)
673  enddo ; enddo ; enddo
674  do k=1,nz ; do j=jsq,jeq ; do i=is,ie
675  if (v(i,j,k) < 0.0) then
676  cfl_trans = (-v(i,j,k) * cs%dt) * (g%dx_Cv(i,j) * g%IareaT(i,j+1))
677  else
678  cfl_trans = (v(i,j,k) * cs%dt) * (g%dx_Cv(i,j) * g%IareaT(i,j))
679  endif
680  cfl_lin = abs(v(i,j,k) * cs%dt) * g%IdyCv(i,j)
681  max_cfl(1) = max(max_cfl(1), cfl_trans)
682  max_cfl(2) = max(max_cfl(2), cfl_lin)
683  enddo ; enddo ; enddo
684 
685  call sum_across_pes(cs%ntrunc)
686  ! Sum the various quantities across all the processors. This sum is NOT
687  ! guaranteed to be bitwise reproducible, even on the same decomposition.
688  ! The sum of Tr_stocks should be reimplemented using the reproducing sums.
689  if (ntr_stocks > 0) call sum_across_pes(tr_stocks,ntr_stocks)
690 
691  call max_across_pes(max_cfl(1))
692  call max_across_pes(max_cfl(2))
693  if (cs%use_temperature .and. cs%previous_calls == 0) then
694  cs%salt_prev = salt ; cs%net_salt_input = 0.0
695  cs%heat_prev = heat ; cs%net_heat_input = 0.0
696 
697  cs%salt_prev_EFP = salt_efp ; cs%net_salt_in_EFP = real_to_efp(0.0)
698  cs%heat_prev_EFP = heat_efp ; cs%net_heat_in_EFP = real_to_efp(0.0)
699  endif
700  irho0 = 1.0/gv%Rho0
701 
702  if (cs%use_temperature) then
703  salt_chg_efp = salt_efp - cs%salt_prev_EFP
704  salt_anom_efp = salt_chg_efp - cs%net_salt_in_EFP
705  salt_chg = efp_to_real(salt_chg_efp) ; salt_anom = efp_to_real(salt_anom_efp)
706  heat_chg_efp = heat_efp - cs%heat_prev_EFP
707  heat_anom_efp = heat_chg_efp - cs%net_heat_in_EFP
708  heat_chg = efp_to_real(heat_chg_efp) ; heat_anom = efp_to_real(heat_anom_efp)
709  endif
710 
711  mass_chg_efp = mass_efp - cs%mass_prev_EFP
712  salin_mass_in = 0.0
713  if (gv%Boussinesq) then
714  mass_anom_efp = mass_chg_efp - cs%fresh_water_in_EFP
715  else
716  ! net_salt_input needs to be converted from psu m s-1 to kg m-2 s-1.
717  mass_anom_efp = mass_chg_efp - cs%fresh_water_in_EFP
718  if (cs%use_temperature) &
719  salin_mass_in = 0.001*efp_to_real(cs%net_salt_in_EFP)
720  endif
721  mass_chg = efp_to_real(mass_chg_efp)
722  mass_anom = efp_to_real(mass_anom_efp) - salin_mass_in
723 
724  if (cs%use_temperature) then
725  salin = salt / mass_tot ; salin_anom = salt_anom / mass_tot
726  ! salin_chg = Salt_chg / mass_tot
727  temp = heat / (mass_tot*tv%C_p) ; temp_anom = heat_anom / (mass_tot*tv%C_p)
728  endif
729  en_mass = toten / mass_tot
730 
731  call get_time(day, start_of_day, num_days)
732  date_stamped = (cs%date_stamped_output .and. (get_calendar_type() /= no_calendar))
733  if (date_stamped) &
734  call get_date(day, iyear, imonth, iday, ihour, iminute, isecond, itick)
735  if (abs(cs%timeunit - 86400.0) < 1.0) then
736  reday = REAL(num_days)+ (REAL(start_of_day)/86400.0)
737  mesg_intro = "MOM Day "
738  else
739  reday = REAL(num_days)*(86400.0/cs%timeunit) + &
740  REAL(start_of_day)/abs(cs%timeunit)
741  mesg_intro = "MOM Time "
742  endif
743  if (reday < 1.0e8) then ; write(day_str, '(F12.3)') reday
744  elseif (reday < 1.0e11) then ; write(day_str, '(F15.3)') reday
745  else ; write(day_str, '(ES15.9)') reday ; endif
746 
747  if (n < 1000000) then ; write(n_str, '(I6)') n
748  elseif (n < 10000000) then ; write(n_str, '(I7)') n
749  elseif (n < 100000000) then ; write(n_str, '(I8)') n
750  else ; write(n_str, '(I10)') n ; endif
751 
752  if (date_stamped) then
753  write(date_str,'("MOM Date",i7,2("/",i2.2)," ",i2.2,2(":",i2.2))') &
754  iyear, imonth, iday, ihour, iminute, isecond
755  else
756  date_str = trim(mesg_intro)//trim(day_str)
757  endif
758 
759  if (is_root_pe()) then
760  if (cs%use_temperature) then
761  write(*,'(A," ",A,": En ",ES12.6, ", MaxCFL ", F8.5, ", Mass ", &
762  & ES18.12, ", Salt ", F15.11,", Temp ", F15.11)') &
763  trim(date_str), trim(n_str), en_mass, max_cfl(1), mass_tot, salin, temp
764  else
765  write(*,'(A," ",A,": En ",ES12.6, ", MaxCFL ", F8.5, ", Mass ", &
766  & ES18.12)') &
767  trim(date_str), trim(n_str), en_mass, max_cfl(1), mass_tot
768  endif
769 
770  if (cs%use_temperature) then
771  write(cs%fileenergy_ascii,'(A,",",A,",", I6,", En ",ES18.12, &
772  &", CFL ", F8.5, ", SL ",&
773  &es11.4,", M ",ES11.5,", S",f8.4,", T",f8.4,&
774  &", Me ",ES9.2,", Se ",ES9.2,", Te ",ES9.2)') &
775  trim(n_str), trim(day_str), cs%ntrunc, en_mass, max_cfl(1), &
776  -h_0ape(1), mass_tot, salin, temp, mass_anom/mass_tot, salin_anom, &
777  temp_anom
778  else
779  write(cs%fileenergy_ascii,'(A,",",A,",", I6,", En ",ES18.12, &
780  &", CFL ", F8.5, ", SL ",&
781  &ES11.4,", Mass ",ES11.5,", Me ",ES9.2)') &
782  trim(n_str), trim(day_str), cs%ntrunc, en_mass, max_cfl(1), &
783  -h_0ape(1), mass_tot, mass_anom/mass_tot
784  endif
785 
786  if (cs%ntrunc > 0) then
787  write(*,'(A," Energy/Mass:",ES12.5," Truncations ",I0)') &
788  trim(date_str), en_mass, cs%ntrunc
789  endif
790 
791  if (cs%write_stocks) then
792  write(*,'(" Total Energy: ",Z16.16,ES24.16)') toten, toten
793  write(*,'(" Total Mass: ",ES24.16,", Change: ",ES24.16," Error: ",ES12.5," (",ES8.1,")")') &
794  mass_tot, mass_chg, mass_anom, mass_anom/mass_tot
795  if (cs%use_temperature) then
796  if (salt == 0.) then
797  write(*,'(" Total Salt: ",ES24.16,", Change: ",ES24.16," Error: ",ES12.5)') &
798  salt*0.001, salt_chg*0.001, salt_anom*0.001
799  else
800  write(*,'(" Total Salt: ",ES24.16,", Change: ",ES24.16," Error: ",ES12.5," (",ES8.1,")")') &
801  salt*0.001, salt_chg*0.001, salt_anom*0.001, salt_anom/salt
802  endif
803  if (heat == 0.) then
804  write(*,'(" Total Heat: ",ES24.16,", Change: ",ES24.16," Error: ",ES12.5)') &
805  heat, heat_chg, heat_anom
806  else
807  write(*,'(" Total Heat: ",ES24.16,", Change: ",ES24.16," Error: ",ES12.5," (",ES8.1,")")') &
808  heat, heat_chg, heat_anom, heat_anom/heat
809  endif
810  endif
811  do m=1,ntr_stocks
812 
813  write(*,'(" Total ",a,": ",ES24.16,X,a)') &
814  trim(tr_names(m)), tr_stocks(m), trim(tr_units(m))
815 
816  if(tr_minmax_got(m)) then
817  write(*,'(64X,"Global Min:",ES24.16,X,"at: (", f7.2,","f7.2,","f8.2,")" )') &
818  tr_min(m),tr_min_x(m),tr_min_y(m),tr_min_z(m)
819  write(*,'(64X,"Global Max:",ES24.16,X,"at: (", f7.2,","f7.2,","f8.2,")" )') &
820  tr_max(m),tr_max_x(m),tr_max_y(m),tr_max_z(m)
821  endif
822 
823  enddo
824  endif
825  endif
826 
827  var = real(cs%ntrunc)
828  call write_field(cs%fileenergy_nc, cs%fields(1), var, reday)
829  call write_field(cs%fileenergy_nc, cs%fields(2), toten, reday)
830  call write_field(cs%fileenergy_nc, cs%fields(3), pe, reday)
831  call write_field(cs%fileenergy_nc, cs%fields(4), ke, reday)
832  call write_field(cs%fileenergy_nc, cs%fields(5), h_0ape, reday)
833  call write_field(cs%fileenergy_nc, cs%fields(6), mass_lay, reday)
834 
835  call write_field(cs%fileenergy_nc, cs%fields(7), mass_tot, reday)
836  call write_field(cs%fileenergy_nc, cs%fields(8), mass_chg, reday)
837  call write_field(cs%fileenergy_nc, cs%fields(9), mass_anom, reday)
838  call write_field(cs%fileenergy_nc, cs%fields(10), max_cfl(1), reday)
839  call write_field(cs%fileenergy_nc, cs%fields(11), max_cfl(1), reday)
840  if (cs%use_temperature) then
841  call write_field(cs%fileenergy_nc, cs%fields(12), 0.001*salt, reday)
842  call write_field(cs%fileenergy_nc, cs%fields(13), 0.001*salt_chg, reday)
843  call write_field(cs%fileenergy_nc, cs%fields(14), 0.001*salt_anom, reday)
844  call write_field(cs%fileenergy_nc, cs%fields(15), heat, reday)
845  call write_field(cs%fileenergy_nc, cs%fields(16), heat_chg, reday)
846  call write_field(cs%fileenergy_nc, cs%fields(17), heat_anom, reday)
847  do m=1,ntr_stocks
848  call write_field(cs%fileenergy_nc, cs%fields(17+m), tr_stocks(m), reday)
849  enddo
850  else
851  do m=1,ntr_stocks
852  call write_field(cs%fileenergy_nc, cs%fields(11+m), tr_stocks(m), reday)
853  enddo
854  endif
855 
856  call flush_file(cs%fileenergy_nc)
857 
858  ! The second (impossible-looking) test looks for a NaN in En_mass.
859  if ((en_mass>cs%max_Energy) .or. &
860  ((en_mass>cs%max_Energy) .and. (en_mass<cs%max_Energy))) then
861  day = cs%Huge_time
862  write(mesg,'("Energy per unit mass of ",ES11.4," exceeds ",ES11.4)') &
863  en_mass, cs%max_Energy
864  call mom_error(warning, "write_energy : "//trim(mesg))
865  call mom_error(warning, &
866  "write_energy : Time set to a large value to force model termination.")
867  endif
868  if (cs%ntrunc>cs%maxtrunc) then
869  day = cs%Huge_time
870  call mom_error(fatal, "write_energy : Ocean velocity has been truncated too many times.")
871  endif
872  cs%ntrunc = 0
873  cs%previous_calls = cs%previous_calls + 1
874  cs%mass_prev = mass_tot ; cs%fresh_water_input = 0.0
875  if (cs%use_temperature) then
876  cs%salt_prev = salt ; cs%net_salt_input = 0.0
877  cs%heat_prev = heat ; cs%net_heat_input = 0.0
878  endif
879 
880  cs%mass_prev_EFP = mass_efp ; cs%fresh_water_in_EFP = real_to_efp(0.0)
881  if (cs%use_temperature) then
882  cs%salt_prev_EFP = salt_efp ; cs%net_salt_in_EFP = real_to_efp(0.0)
883  cs%heat_prev_EFP = heat_efp ; cs%net_heat_in_EFP = real_to_efp(0.0)
884  endif
Ocean grid type. See mom_grid for details.
Definition: MOM_grid.F90:19
Here is the call graph for this function:
Here is the caller graph for this function:

Variable Documentation

◆ num_fields

integer, parameter mom_sum_output::num_fields = 17
private

Definition at line 85 of file MOM_sum_output.F90.

85 integer, parameter :: num_fields = 17