58 use mom_coms, only : sum_across_pes, pe_here, root_pe, num_pes, max_across_pes
68 use mom_io, only : append_file, ascii_file, single_file, writeonly_file
69 use mom_time_manager, only : time_type, get_time, get_date, set_time,
operator(>),
operator(-)
77 implicit none ;
private 79 #include <MOM_memory.h> 97 integer allocable_,
dimension(NKMEM_) :: lh
101 logical :: do_ape_calc
107 character(len=200) :: depth_list_file
108 real :: d_list_min_inc
111 logical :: use_temperature
113 real :: fresh_water_input
119 real :: net_salt_input
124 real :: net_heat_input
128 fresh_water_in_efp, &
130 net_heat_in_efp, heat_prev_efp, salt_prev_efp, mass_prev_efp
134 logical :: date_stamped_output
135 type(time_type) :: start_time
137 type(time_type) :: huge_time
141 integer,
pointer :: ntrunc
148 logical :: write_stocks
150 integer :: previous_calls = 0
151 integer :: prev_n = 0
152 integer :: fileenergy_nc
153 integer :: fileenergy_ascii
154 type(fieldtype),
dimension(NUM_FIELDS+MAX_FIELDS_) :: &
156 character(len=200) :: energyfile
163 Input_start_time, CS)
167 character(len=*),
intent(in) :: directory
168 integer,
target,
intent(inout) :: ntrnc
171 type(time_type),
intent(in) :: Input_start_time
183 real :: Rho_0, maxvel
185 #include "version_variable.h" 186 character(len=40) :: mdl =
"MOM_sum_output" 187 character(len=200) :: energyfile
188 character(len=32) :: filename_appendix =
'' 190 if (
associated(cs))
then 191 call mom_error(warning,
"MOM_sum_output_init called with associated control structure.")
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.", &
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)
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)
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")
237 call get_filename_appendix(filename_appendix)
238 if(len_trim(filename_appendix) > 0)
then 239 energyfile = trim(energyfile) //
'.'//trim(filename_appendix)
242 cs%energyfile = trim(slasher(directory))//trim(energyfile)
243 call log_param(param_file, mdl,
"output_path/ENERGYFILE", cs%energyfile)
245 cs%energyfile = trim(cs%energyfile)//
"."//trim(adjustl(statslabel))
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", &
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
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", &
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)
279 cs%Huge_time = set_time(int(1e9),0)
280 cs%Start_time = input_start_time
291 if (
associated(cs))
then 292 if (cs%do_APE_calc)
then 304 subroutine write_energy(u, v, h, tv, day, n, G, GV, CS, tracer_CSp)
308 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)),
intent(in) :: u
309 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)),
intent(in) :: v
311 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h
315 type(time_type),
intent(inout) :: day
316 integer,
intent(in) :: n
341 real :: eta(szi_(g),szj_(g),szk_(g)+1)
342 real :: areaTm(szi_(g),szj_(g))
344 real :: PE(szk_(g)+1)
347 real :: H_0APE(szk_(g)+1)
354 real :: vol_lay(szk_(g))
356 real :: mass_lay(szk_(g))
373 real :: salin_mass_in
393 salt_EFP, heat_EFP, salt_chg_EFP, heat_chg_EFP, mass_chg_EFP, &
394 mass_anom_EFP, salt_anom_EFP, heat_anom_EFP
399 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)) :: &
401 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)+1) :: &
403 real,
dimension(SZI_(G),SZJ_(G)) :: &
405 real :: H_to_m, H_to_kg_m2
406 integer :: num_nc_fields
408 integer :: i, j, k, is, ie, js, je, nz, m, Isq, Ieq, Jsq, Jeq
409 integer :: l, lbelow, labove
412 integer :: start_of_day, num_days
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_) :: &
425 integer :: nTr_stocks
426 real,
allocatable :: toten_PE(:)
428 integer :: iyear, imonth, iday, ihour, iminute, isecond, itick
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')
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
459 if (.not.
associated(cs))
call mom_error(fatal, &
460 "write_energy: Module must be initialized before it is used.")
462 do j=js,je ;
do i=is,ie
463 areatm(i,j) = g%mask2dT(i,j)*g%areaT(i,j)
466 if (gv%Boussinesq)
then 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 472 do k=1,nz ; vol_lay(k) = (h_to_m/h_to_kg_m2)*mass_lay(k) ;
enddo 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 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 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 491 do k=1,nz ; vol_lay(k) = mass_lay(k) / gv%Rho0 ;
enddo 496 if (
present(tracer_csp))
then 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 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')
507 num_nc_fields = num_nc_fields + ntr_stocks
511 if (cs%previous_calls == 0)
then 512 cs%mass_prev = mass_tot ; cs%fresh_water_input = 0.0
514 cs%mass_prev_EFP = mass_efp
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.)
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]")')
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]")')
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] " 548 write(time_units,
'(9x,"[",es8.2," s] ")') cs%timeunit
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
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
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, &
574 call create_file(cs%fileenergy_nc, trim(energypath_nc), vars, &
575 num_nc_fields, cs%fields, single_file, cs%timeunit, &
580 if (cs%do_APE_calc)
then 581 lbelow = 1 ; volbelow = 0.0
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 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
598 h_0ape(k) = cs%DL(l)%depth - (volbelow - cs%DL(l)%vol_below) / cs%DL(l)%area
600 h_0ape(nz+1) = cs%DL(2)%depth
602 do k=1,nz+1 ; h_0ape(k) = 0.0 ;
enddo 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 615 do k=1,nz+1 ; pe(k) = 0.0 ;
enddo 616 if (cs%do_APE_calc)
then 618 if (gv%Boussinesq)
then 619 do j=js,je ;
do i=is,ie
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)
631 do j=js,je ;
do i=is,ie
634 hint = h_0ape(k) + eta(i,j,k)
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)
645 if (cs%do_APE_calc) &
647 toten = ke_tot + pe_tot
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 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))
668 cfl_trans = (u(i,j,k) * cs%dt) * (g%dy_Cu(i,j) * g%IareaT(i,j))
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))
678 cfl_trans = (v(i,j,k) * cs%dt) * (g%dx_Cv(i,j) * g%IareaT(i,j))
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 685 call sum_across_pes(cs%ntrunc)
689 if (ntr_stocks > 0)
call sum_across_pes(tr_stocks,ntr_stocks)
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
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)
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
706 heat_chg_efp = heat_efp - cs%heat_prev_EFP
707 heat_anom_efp = heat_chg_efp - cs%net_heat_in_EFP
711 mass_chg_efp = mass_efp - cs%mass_prev_EFP
713 if (gv%Boussinesq)
then 714 mass_anom_efp = mass_chg_efp - cs%fresh_water_in_EFP
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)
722 mass_anom =
efp_to_real(mass_anom_efp) - salin_mass_in
724 if (cs%use_temperature)
then 725 salin = salt / mass_tot ; salin_anom = salt_anom / mass_tot
727 temp = heat / (mass_tot*tv%C_p) ; temp_anom = heat_anom / (mass_tot*tv%C_p)
729 en_mass = toten / mass_tot
731 call get_time(day, start_of_day, num_days)
732 date_stamped = (cs%date_stamped_output .and. (get_calendar_type() /= no_calendar))
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 " 739 reday =
REAL(num_days)*(86400.0/cs%timeunit) + &
740 REAL(start_of_day)/abs(cs%timeunit)
741 mesg_intro =
"MOM Time " 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 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 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
756 date_str = trim(mesg_intro)//trim(day_str)
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
765 write(*,
'(A," ",A,": En ",ES12.6, ", MaxCFL ", F8.5, ", Mass ", & 767 trim(date_str), trim(n_str), en_mass, max_cfl(1), mass_tot
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, &
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
786 if (cs%ntrunc > 0)
then 787 write(*,
'(A," Energy/Mass:",ES12.5," Truncations ",I0)') &
788 trim(date_str), en_mass, cs%ntrunc
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 797 write(*,
'(" Total Salt: ",ES24.16,", Change: ",ES24.16," Error: ",ES12.5)') &
798 salt*0.001, salt_chg*0.001, salt_anom*0.001
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
804 write(*,
'(" Total Heat: ",ES24.16,", Change: ",ES24.16," Error: ",ES12.5)') &
805 heat, heat_chg, heat_anom
807 write(*,
'(" Total Heat: ",ES24.16,", Change: ",ES24.16," Error: ",ES12.5," (",ES8.1,")")') &
808 heat, heat_chg, heat_anom, heat_anom/heat
813 write(*,
'(" Total ",a,": ",ES24.16,X,a)') &
814 trim(tr_names(m)), tr_stocks(m), trim(tr_units(m))
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)
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)
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)
848 call write_field(cs%fileenergy_nc, cs%fields(17+m), tr_stocks(m), reday)
852 call write_field(cs%fileenergy_nc, cs%fields(11+m), tr_stocks(m), reday)
856 call flush_file(cs%fileenergy_nc)
859 if ((en_mass>cs%max_Energy) .or. &
860 ((en_mass>cs%max_Energy) .and. (en_mass<cs%max_Energy)))
then 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))
866 "write_energy : Time set to a large value to force model termination.")
868 if (cs%ntrunc>cs%maxtrunc)
then 870 call mom_error(fatal,
"write_energy : Ocean velocity has been truncated too many times.")
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
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)
891 type(
surface),
intent(in) :: state
892 real,
intent(in) :: dt
904 real,
dimension(SZI_(G),SZJ_(G)) :: &
924 integer :: i, j, is, ie, js, je
926 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec
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))))
939 "accumulate_net_input called with associated evap field, but no precip field.")
943 salt_in(:,:) = 0.0 ; heat_in(:,:) = 0.0
944 if (cs%use_temperature)
then 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 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)
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)
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)
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 990 if (
ASSOCIATED(fluxes%salt_flux))
then ;
do j=js,je ;
do i=is,ie
992 salt_in(i,j) = dt*g%areaT(i,j)*(1000.0*fluxes%salt_flux(i,j))
993 enddo ;
enddo ;
endif 996 if ((cs%use_temperature) .or.
ASSOCIATED(fluxes%lprec) .or. &
997 ASSOCIATED(fluxes%evap))
then 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
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
1027 if (cs%read_depth_list)
then 1032 trim(cs%depth_list_file)//
" does not exist. Creating a new file.")
1042 cs%lH(k) = cs%list_size
1054 real,
dimension(G%Domain%niglobal*G%Domain%njglobal + 1) :: &
1055 Dlist, & !< The global list of bottom depths, in m.
1057 integer,
dimension(G%Domain%niglobal*G%Domain%njglobal+1) :: &
1064 logical :: add_to_list
1066 integer :: ir, indxt
1067 integer :: mls, list_size
1068 integer :: list_pos, i_global, j_global
1069 integer :: i, j, k, kl
1071 mls = g%Domain%niglobal*g%Domain%njglobal
1076 do j=g%jsc,g%jec ;
do i=g%isc,g%iec
1078 j_global = j + g%jdg_offset - (g%jsg-1)
1079 i_global = i + g%idg_offset - (g%isg-1)
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)
1087 call sum_across_pes(dlist, mls+1)
1088 call sum_across_pes(arealist, mls+1)
1090 do j=1,mls+1 ; indx2(j) = j ;
enddo 1091 k = mls / 2 + 1 ; ir = mls
1100 indx2(ir) = indx2(1)
1102 if (ir == 1)
then ; indx2(1) = indxt ;
exit ;
endif 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 1120 d_list_prev = dlist(indx2(mls))
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))
1129 cs%list_size = list_size
1130 allocate(cs%DL(cs%list_size+1))
1132 vol = 0.0 ; area = 0.0
1133 dprev = dlist(indx2(mls))
1139 vol = vol + area * (dprev - dlist(i))
1140 area = area + arealist(i)
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))
1150 if (add_to_list)
then 1152 cs%DL(kl)%depth = dlist(i)
1153 cs%DL(kl)%area = area
1154 cs%DL(kl)%vol_below = vol
1159 do while (kl < list_size)
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
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
1177 character(len=*),
intent(in) :: filename
1178 integer,
intent(in) :: list_size
1182 real,
allocatable :: tmp(:)
1183 integer :: ncid, dimid(1), Did, Aid, Vid, status, k
1187 allocate(tmp(list_size)) ; tmp(:) = 0.0
1189 status = nf90_create(filename, 0, ncid)
1190 if (status /= nf90_noerr)
then 1191 call mom_error(warning, filename//trim(nf90_strerror(status)))
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)))
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)))
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)))
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)))
1229 status = nf90_enddef(ncid)
1230 if (status /= nf90_noerr)
call mom_error(warning, &
1231 filename//trim(nf90_strerror(status)))
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)))
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)))
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)))
1248 status = nf90_close(ncid)
1249 if (status /= nf90_noerr)
call mom_error(warning, &
1250 filename//trim(nf90_strerror(status)))
1259 character(len=*),
intent(in) :: filename
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)
1269 mdl =
"MOM_sum_output read_depth_list:" 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)))
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)))
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.")
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)))
1299 cs%list_size = list_size-1
1300 allocate(cs%DL(list_size))
1301 allocate(tmp(list_size))
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)))
1308 do k=1,list_size ; cs%DL(k)%depth = tmp(k) ;
enddo 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)))
1321 do k=1,list_size ; cs%DL(k)%area = tmp(k) ;
enddo 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)))
1334 do k=1,list_size ; cs%DL(k)%vol_below = tmp(k) ;
enddo 1336 status = nf90_close(ncid)
1337 if (status /= nf90_noerr)
call mom_error(warning, mdl// &
1338 " Difficulties closing "//trim(filename)//
" - "//trim(nf90_strerror(status)))
The following structure contains pointers to various fields which may be used describe the surface st...
subroutine depth_list_setup(G, CS)
This subroutine sets up an ordered list of depths, along with the cross sectional areas at each depth...
type(vardesc) function, public var_desc(name, units, longname, hor_grid, z_grid, t_grid, cmor_field_name, cmor_units, conversion, caller)
Returns a vardesc type whose elements have been filled with the provided fields. The argument name is...
This module implements boundary forcing for MOM6.
type(efp_type) function, public real_to_efp(val, overflow)
The module calculates interface heights, including free surface height.
Ocean grid type. See mom_grid for details.
Provides the ocean grid type.
This module contains I/O framework code.
integer, parameter num_fields
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.
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...
subroutine, public call_tracer_stocks(h, stock_values, G, GV, CS, stock_names, stock_units, num_stocks, stock_index, got_min_max, global_min, global_max, xgmin, ygmin, zgmin, xgmax, ygmax, zgmax)
This subroutine calls all registered tracer packages to enable them to add to the surface state retur...
logical function, public is_root_pe()
Structure that contains pointers to the boundary forcing used to drive the liquid ocean simulated by ...
subroutine, public mom_mesg(message, verb, all_print)
subroutine mom_sum_output_end(CS)
Type for describing a variable, typically a tracer.
subroutine write_depth_list(G, CS, filename, list_size)
This subroutine writes out the depth list to the specified file.
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 CSli...
subroutine create_depth_list(G, CS)
create_depth_list makes an ordered list of depths, along with the cross sectional areas at each depth...
The thermo_var_ptrs structure contains pointers to an assortment of thermodynamic fields that may be ...
subroutine, public reopen_file(unit, filename, vars, novars, fields, threading, timeunit, G, dG, GV)
This routine opens an existing NetCDF file for output. If it does not find the file, a new file is created. It also sets up structures that describe this file and the variables that will later be written to this file.
subroutine, public create_file(unit, filename, vars, novars, fields, threading, timeunit, G, dG, GV)
Routine creates a new NetCDF file. It also sets up structures that describe this file and variables t...
real function, public efp_to_real(EFP1)
subroutine, public mom_error(level, message, all_print)
subroutine, public mom_sum_output_init(G, param_file, directory, ntrnc, Input_start_time, CS)