├── .gitignore
├── LICENSE
├── README.rst
├── cime_config
├── buildlib
├── buildnml
├── config_archive.xml
├── config_component.xml
├── config_compsets.xml
├── namelist_definition_mosart.xml
├── testdefs
│ ├── ExpectedTestFails.xml
│ ├── testlist_mosart.xml
│ └── testmods_dirs
│ │ └── mosart
│ │ ├── clmAccelSpinupIgnoreWarn
│ │ └── shell_commands
│ │ ├── decompOpts
│ │ ├── include_user_mods
│ │ └── user_nl_mosart
│ │ ├── default
│ │ └── user_nl_mosart
│ │ ├── iceOff
│ │ ├── include_user_mods
│ │ └── user_nl_mosart
│ │ ├── inplacethreshold
│ │ ├── include_user_mods
│ │ └── user_nl_mosart
│ │ ├── mosartCold
│ │ ├── include_user_mods
│ │ └── user_nl_mosart
│ │ ├── mosartGridNull
│ │ ├── README
│ │ └── shell_commands
│ │ ├── mosartOff
│ │ └── shell_commands
│ │ ├── nobypass
│ │ └── user_nl_mosart
│ │ ├── passChannelDepths
│ │ ├── include_user_mods
│ │ └── user_nl_cpl
│ │ └── qgrwlOpts
│ │ ├── include_user_mods
│ │ └── user_nl_mosart
└── user_nl_mosart
├── docs
├── ChangeLog.md
└── index.html
└── src
├── cpl
└── nuopc
│ ├── rof_comp_nuopc.F90
│ └── rof_import_export.F90
└── riverroute
├── mosart_budget_type.F90
├── mosart_control_type.F90
├── mosart_data.F90
├── mosart_driver.F90
├── mosart_fileutils.F90
├── mosart_histfile.F90
├── mosart_histflds.F90
├── mosart_io.F90
├── mosart_physics.F90
├── mosart_restfile.F90
├── mosart_tctl_type.F90
├── mosart_timemanager.F90
├── mosart_tparameter_type.F90
├── mosart_tspatialunit_type.F90
├── mosart_tstatusflux_type.F90
└── mosart_vars.F90
/.gitignore:
--------------------------------------------------------------------------------
1 | # ignore svn directories
2 | **/.svn/**
3 | .svn/
4 |
5 | # binary files
6 | *.nc
7 |
8 | # editor files
9 | *.swp
10 | *~
11 |
12 | # mac files
13 | .DS_Store
14 |
15 | # cmake generated files
16 | build/
17 | CMakeFiles/
18 |
19 | # don't ignore cism build utilities directory
20 | !components/cism/**/build
21 |
22 | # build output
23 | *.o
24 | *.mod
25 | core.*
26 | *.gz
27 | *.log
28 | cime_config/buildnmlc
29 | __pycache__
30 |
31 | # test and case directories
32 | tests/
33 | scripts/testreporter.pl
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2005-2017, University Corporation for Atmospheric Research (UCAR)
2 | All rights reserved.
3 |
4 | Developed by:
5 | University Corporation for Atmospheric Research - National Center for Atmospheric Research
6 | https://www2.cesm.ucar.edu/working-groups/sewg
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining
9 | a copy of this software and associated documentation files (the "Software"),
10 | to deal with the Software without restriction, including without limitation
11 | the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 | and/or sell copies of the Software, and to permit persons to whom
13 | the Software is furnished to do so, subject to the following conditions:
14 |
15 | - Redistributions of source code must retain the above copyright notice,
16 | this list of conditions and the following disclaimers.
17 | - Redistributions in binary form must reproduce the above copyright notice,
18 | this list of conditions and the following disclaimers in the documentation
19 | and/or other materials provided with the distribution.
20 | - Neither the names of [Name of Development Group, UCAR],
21 | nor the names of its contributors may be used to endorse or promote
22 | products derived from this Software without specific prior written permission.
23 |
24 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
28 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 | POSSIBILITY OF SUCH DAMAGE.
35 |
--------------------------------------------------------------------------------
/README.rst:
--------------------------------------------------------------------------------
1 | ========================================
2 | Model for Scale Adaptive River Transport
3 | ========================================
4 |
5 | The Model for Scale Adaptive River Transport, Mosart,
6 | is part of the Community Earth System Model.
7 |
8 | IMPORTANT NOTE: MOSART is Obsolescent!
9 |
10 | MOSART is part of CESM3, but is obsolescent.
11 |
12 | We do not have support for creating input datasets for MOSART and
13 | as such can NOT use MOSART for Paleo work.
14 |
15 | Longer term MOSART will be removed in future versions of CESM and the new model
16 | mizuRoute will be used for Paleo work as well as present day.
17 | It's also possible that external collaborators will support the use of MOSART
18 | for present day climate even as mizuRoute becomes the default model for CESM.
19 |
20 | See the CESM web site for documentation and information:
21 |
22 | http://www.cesm.ucar.edu
23 |
--------------------------------------------------------------------------------
/cime_config/buildlib:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | """
3 | Build the mosart component library
4 | """
5 | #pylint: disable=unused-wildcard-import, wildcard-import, multiple-imports
6 | #pylint: disable=wrong-import-position, invalid-name, too-many-locals
7 | import os, sys
8 |
9 | CIMEROOT = os.environ.get("CIMEROOT")
10 | if CIMEROOT is None:
11 | raise SystemExit("ERROR: must set CIMEROOT environment variable")
12 | sys.path.append(os.path.join(CIMEROOT, "scripts", "CIME", "Tools"))
13 |
14 | from standard_script_setup import *
15 | from CIME.case import Case
16 | from CIME.utils import expect, run_cmd
17 | from CIME.buildlib import parse_input
18 | from CIME.build import get_standard_makefile_args
19 |
20 | logger = logging.getLogger(__name__)
21 |
22 | ###############################################################################
23 | def _build_mosart():
24 | ###############################################################################
25 |
26 | caseroot, libroot, bldroot = parse_input(sys.argv)
27 |
28 | with Case(caseroot) as case:
29 | casetools = case.get_value("CASETOOLS")
30 | gmake_j = case.get_value("GMAKE_J")
31 | gmake = case.get_value("GMAKE")
32 |
33 | # create Filepath file
34 | objroot = case.get_value("OBJROOT")
35 | filepath_file = os.path.join(objroot,"rof","obj","Filepath")
36 | driver = case.get_value("COMP_INTERFACE").lower()
37 |
38 | if not os.path.isfile(filepath_file):
39 | srcroot = case.get_value("SRCROOT")
40 | caseroot = case.get_value("CASEROOT")
41 | paths = [ os.path.join(caseroot,"SourceMods","src.mosart"),
42 | os.path.join(srcroot,"components","mosart","src","riverroute"),
43 | os.path.join(srcroot,"components","mosart","src","cpl",driver)]
44 |
45 | with open(filepath_file, "w") as filepath:
46 | filepath.write("\n".join(paths))
47 | filepath.write("\n")
48 |
49 | # build the library
50 | complib = os.path.join(libroot, "librof.a")
51 | makefile = os.path.join(casetools, "Makefile")
52 |
53 | cmd = "{} complib -j {} MODEL=mosart COMPLIB={} -f {} {}" \
54 | .format(gmake, gmake_j, complib, makefile, get_standard_makefile_args(case))
55 |
56 | rc, out, err = run_cmd(cmd, from_dir=bldroot)
57 | expect(rc == 0, "Command %s failed rc=%d\nout=%s\nerr=%s" % (cmd, rc, out, err))
58 |
59 | logger.info("Command %s completed with output %s\nerr %s", cmd, out, err)
60 |
61 | ###############################################################################
62 |
63 | if __name__ == "__main__":
64 | _build_mosart()
65 |
--------------------------------------------------------------------------------
/cime_config/buildnml:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | """Namelist creator for CIME's data atmosphere model.
4 | """
5 |
6 | # Typically ignore this.
7 | # pylint: disable=invalid-name
8 |
9 | # Disable these because this is our standard setup
10 | # pylint: disable=wildcard-import,unused-wildcard-import,wrong-import-position
11 | # pylint: disable=multiple-imports
12 | import os, shutil, sys
13 |
14 | CIMEROOT = os.environ.get("CIMEROOT")
15 | if CIMEROOT is None:
16 | raise SystemExit("ERROR: must set CIMEROOT environment variable")
17 | sys.path.append(os.path.join(CIMEROOT, "scripts", "CIME", "Tools"))
18 |
19 | from standard_script_setup import *
20 | from CIME.case import Case
21 | from CIME.nmlgen import NamelistGenerator
22 | from CIME.utils import expect
23 | from CIME.buildnml import create_namelist_infile, parse_input
24 |
25 | logger = logging.getLogger(__name__)
26 |
27 | # pylint: disable=too-many-arguments,too-many-locals,too-many-branches,too-many-statements
28 | ####################################################################################
29 | def _create_namelists(case, confdir, inst_string, infile, nmlgen, data_list_path):
30 | ####################################################################################
31 | """Write out the namelist for this component.
32 |
33 | Most arguments are the same as those for `NamelistGenerator`. The
34 | `inst_string` argument is used as a suffix to distinguish files for
35 | different instances. The `confdir` argument is used to specify the directory
36 | in which output files will be placed.
37 | """
38 | #----------------------------------------------------
39 | # Create config dictionary
40 | #----------------------------------------------------
41 | config = {}
42 | config['mosart_mode'] = case.get_value("MOSART_MODE")
43 | config['ignore_warn'] = case.get_value("MOSART_IGNORE_WARNINGS")
44 | config['clm_accel'] = case.get_value("CLM_ACCELERATED_SPINUP")
45 | ignore_msg = "\n (Set MOSART_IGNORE_WARNINGS to TRUE with xmlchange in your case to ignore this message and continue anyway)"
46 | if ( config['clm_accel'] != "off" ):
47 | if ( config['mosart_mode'] != "NULL" ):
48 | message = "CLM_ACCELERATED_SPINUP is not off, but MOSART_MODE is not NULL, " + \
49 | "normally you should switch it off to save computer time"
50 | if ( not config['ignore_warn'] ):
51 | expect(False, message+ignore_msg )
52 | else:
53 | logger.warning( "WARNING::"+message )
54 |
55 | config['mosart_flood_mode'] = case.get_value("MOSART_FLOOD_MODE")
56 | config['rof_grid'] = case.get_value("ROF_GRID")
57 | config['lnd_grid'] = case.get_value("LND_GRID")
58 | config['rof_ncpl'] = case.get_value("ROF_NCPL")
59 | config['simyr'] = case.get_value("MOSART_SIM_YEAR")
60 |
61 | logger.debug("River Transport Model (MOSART) mode is %s ", config['mosart_mode'])
62 | logger.debug(" MOSART lnd grid is %s ", config['lnd_grid'])
63 | logger.debug(" MOSART rof grid is %s ", config['rof_grid'])
64 |
65 | #----------------------------------------------------
66 | # Check for incompatible options.
67 | #----------------------------------------------------
68 |
69 | if config["rof_grid"] == "null" and config["mosart_mode"] != "NULL":
70 | expect(False, "ROF_GRID is null MOSART_MODE not NULL")
71 |
72 | #----------------------------------------------------
73 | # Initialize namelist defaults
74 | #----------------------------------------------------
75 | nmlgen.init_defaults(infile, config)
76 |
77 | #----------------------------------------------------
78 | # Set values not obtained in the default settings
79 | #----------------------------------------------------
80 |
81 | run_type = case.get_value("RUN_TYPE")
82 | finidat = str(nmlgen.get_value("finidat"))
83 | if run_type == 'branch' or run_type == 'hybrid':
84 | run_refcase = case.get_value("RUN_REFCASE")
85 | run_refdate = case.get_value("RUN_REFDATE")
86 | run_tod = case.get_value("RUN_REFTOD")
87 | rundir = case.get_value("RUNDIR")
88 | filename = "%s.mosart%s.r.%s-%s.nc" %(run_refcase, inst_string, run_refdate, run_tod)
89 | if not os.path.exists(os.path.join(rundir, filename)):
90 | filename = "%s.mosart.r.%s-%s.nc" %(run_refcase, run_refdate, run_tod)
91 |
92 | if run_type == "hybrid":
93 | nmlgen.add_default("finidat", value=filename, ignore_abs_path=True)
94 | else:
95 |
96 | nmlgen.add_default("nrevsn", value=filename)
97 | elif finidat.strip() == '':
98 | nmlgen.set_value('finidat', value=' ')
99 | else:
100 | if nmlgen.get_default('finidat') == 'UNSET':
101 | nmlgen.add_default('finidat', value=' ', ignore_abs_path=True)
102 | else:
103 | nmlgen.add_default("finidat")
104 |
105 | ncpl_base_period = case.get_value('NCPL_BASE_PERIOD')
106 | if ncpl_base_period == 'hour':
107 | basedt = 3600
108 | elif ncpl_base_period == 'day':
109 | basedt = 3600 * 24
110 | elif ncpl_base_period == 'year':
111 | if case.get_value('CALENDAR') == 'NO_LEAP':
112 | basedt = 3600 * 24 * 365
113 | else:
114 | expect(False, "Invalid CALENDAR for NCPL_BASE_PERIOD %s " %ncpl_base_period)
115 | elif ncpl_base_period == 'decade':
116 | if case.get_value('CALENDAR') == 'NO_LEAP':
117 | basedt = 3600 * 24 * 365 * 10
118 | else:
119 | expect(False, "invalid NCPL_BASE_PERIOD NCPL_BASE_PERIOD %s " %ncpl_base_period)
120 | else:
121 | expect(False, "invalid NCPL_BASE_PERIOD NCPL_BASE_PERIOD %s " %ncpl_base_period)
122 |
123 | if basedt < 0:
124 | expect(False, "basedt invalid overflow for NCPL_BASE_PERIOD %s " %ncpl_base_period)
125 |
126 | mosart_ncpl = case.get_value("ROF_NCPL")
127 | if basedt % mosart_ncpl != 0:
128 | expect(False, "mosart_ncpl %s doesn't divide evenly into basedt %s\n"
129 | %(mosart_ncpl, basedt))
130 | else:
131 | coupling_period = basedt // mosart_ncpl
132 | nmlgen.set_value("coupling_period", value=coupling_period)
133 |
134 | if ( nmlgen.get_value("frivinp") == "UNSET" and config["mosart_mode"] != "NULL" ):
135 | raise SystemExit("ERROR: Direction file is NOT set and is required when MOSART is active: frivinp")
136 |
137 | bypass_routing_option = nmlgen.get_value("bypass_routing_option")
138 | qgwl_runoff_option = nmlgen.get_value("qgwl_runoff_option")
139 | if bypass_routing_option == "none" and qgwl_runoff_option != "all":
140 | raise SystemExit("ERROR: When bypass_routing_option is none, qgwl_runoff_option can only be all")
141 |
142 | if bypass_routing_option == "direct_to_outlet" and qgwl_runoff_option == "threshold":
143 | raise SystemExit("ERROR: When bypass_routing_option is direct_to_outlet, qgwl_runoff_option can not be threshold")
144 |
145 | #----------------------------------------------------
146 | # Write output file
147 | #----------------------------------------------------
148 | namelist_file = os.path.join(confdir, "mosart_in")
149 | nmlgen.write_output_file(namelist_file, data_list_path, groups=['mosart_inparm'])
150 |
151 | ###############################################################################
152 | def buildnml(case, caseroot, compname):
153 | ###############################################################################
154 | """Build the mosart namelist """
155 |
156 | # Build the component namelist
157 | if compname != "mosart":
158 | raise AttributeError
159 |
160 | srcroot = case.get_value("SRCROOT")
161 | rundir = case.get_value("RUNDIR")
162 | ninst = case.get_value("NINST_ROF")
163 |
164 | # Determine configuration directory
165 | confdir = os.path.join(caseroot, "Buildconf", "mosartconf")
166 | if not os.path.isdir(confdir):
167 | os.makedirs(confdir)
168 |
169 | #----------------------------------------------------
170 | # Construct the namelist generator
171 | #----------------------------------------------------
172 | # Determine directory for user modified namelist_definitions.xml and namelist_defaults.xml
173 | user_xml_dir = os.path.join(caseroot, "SourceMods", "src.mosart")
174 | expect(os.path.isdir(user_xml_dir),
175 | "user_xml_dir %s does not exist "%user_xml_dir)
176 |
177 | # NOTE: User definition *replaces* existing definition.
178 | namelist_xml_dir = os.path.join(srcroot, "components", "mosart", "cime_config")
179 | definition_file = [os.path.join(namelist_xml_dir, "namelist_definition_mosart.xml")]
180 | user_definition = os.path.join(user_xml_dir, "namelist_definition_mosart.xml")
181 | if os.path.isfile(user_definition):
182 | definition_file = [user_definition]
183 | for file_ in definition_file:
184 | expect(os.path.isfile(file_), "Namelist XML file %s not found!" % file_)
185 |
186 | # Create the namelist generator object - independent of instance
187 | nmlgen = NamelistGenerator(case, definition_file)
188 |
189 | #----------------------------------------------------
190 | # Clear out old data.
191 | #----------------------------------------------------
192 | data_list_path = os.path.join(case.get_case_root(), "Buildconf", "mosart.input_data_list")
193 | if os.path.exists(data_list_path):
194 | os.remove(data_list_path)
195 | #----------------------------------------------------
196 | # Loop over instances
197 | #----------------------------------------------------
198 | for inst_counter in range(1, ninst+1):
199 |
200 | # determine instance string
201 | inst_string = ""
202 | if ninst > 1:
203 | inst_string = '_' + '%04d' % inst_counter
204 |
205 | # If multi-instance case does not have restart file, use
206 | # single-case restart for each instance
207 | rpointer = "rpointer.rof"
208 | if (os.path.isfile(os.path.join(rundir, rpointer)) and
209 | (not os.path.isfile(os.path.join(rundir, rpointer + inst_string)))):
210 | shutil.copy(os.path.join(rundir, rpointer),
211 | os.path.join(rundir, rpointer + inst_string))
212 |
213 | inst_string_label = inst_string
214 | if not inst_string_label:
215 | inst_string_label = "\"\""
216 |
217 | # create namelist output infile using user_nl_file as input
218 | user_nl_file = os.path.join(caseroot, "user_nl_mosart" + inst_string)
219 | expect(os.path.isfile(user_nl_file),
220 | "Missing required user_nl_file %s " %(user_nl_file))
221 | infile = os.path.join(confdir, "namelist_infile")
222 | create_namelist_infile(case, user_nl_file, infile)
223 | namelist_infile = [infile]
224 |
225 | # create namelist and stream file(s) data component
226 | _create_namelists(case, confdir, inst_string, namelist_infile, nmlgen, data_list_path)
227 |
228 | # copy namelist files and stream text files, to rundir
229 | if os.path.isdir(rundir):
230 | file_src = os.path.join(confdir, 'mosart_in')
231 | file_dest = os.path.join(rundir, 'mosart_in')
232 | if inst_string:
233 | file_dest += inst_string
234 | shutil.copy(file_src, file_dest)
235 |
236 | ###############################################################################
237 | def _main_func():
238 |
239 | caseroot = parse_input(sys.argv)
240 | with Case(caseroot) as case:
241 | buildnml(case, caseroot, "mosart")
242 |
243 | if __name__ == "__main__":
244 | _main_func()
245 |
--------------------------------------------------------------------------------
/cime_config/config_archive.xml:
--------------------------------------------------------------------------------
1 |
If your browser supports Refresh, you'll be transported to the 7 | CESM Website 8 | in 5 seconds, otherwise, select the link manually. 9 | 10 | -------------------------------------------------------------------------------- /src/cpl/nuopc/rof_import_export.F90: -------------------------------------------------------------------------------- 1 | module rof_import_export 2 | 3 | use ESMF , only : ESMF_GridComp, ESMF_State, ESMF_Mesh, ESMF_StateGet 4 | use ESMF , only : ESMF_KIND_R8, ESMF_SUCCESS, ESMF_MAXSTR, ESMF_LOGMSG_INFO 5 | use ESMF , only : ESMF_LogWrite, ESMF_LOGMSG_ERROR, ESMF_LogFoundError 6 | use ESMF , only : ESMF_STATEITEM_NOTFOUND, ESMF_StateItem_Flag 7 | use ESMF , only : operator(/=), operator(==) 8 | use NUOPC , only : NUOPC_CompAttributeGet, NUOPC_Advertise, NUOPC_IsConnected 9 | use NUOPC_Model , only : NUOPC_ModelGet 10 | use shr_kind_mod , only : r8 => shr_kind_r8 11 | use shr_sys_mod , only : shr_sys_abort 12 | use mosart_vars , only : iulog, mainproc, mpicom_rof, ice_runoff 13 | use mosart_data , only : ctl, TRunoff, TUnit 14 | use mosart_timemanager , only : get_nstep 15 | use nuopc_shr_methods , only : chkerr 16 | 17 | implicit none 18 | private ! except 19 | 20 | public :: advertise_fields 21 | public :: realize_fields 22 | public :: import_fields 23 | public :: export_fields 24 | 25 | private :: fldlist_add 26 | private :: fldlist_realize 27 | private :: state_getimport 28 | private :: state_setexport 29 | private :: check_for_nans 30 | private :: fldchk 31 | 32 | type fld_list_type 33 | character(len=128) :: stdname 34 | end type fld_list_type 35 | 36 | integer, parameter :: fldsMax = 100 37 | integer :: fldsToRof_num = 0 38 | integer :: fldsFrRof_num = 0 39 | logical :: flds_r2l_stream_channel_depths = .false. ! If should pass the channel depth fields needed for the hillslope model 40 | type (fld_list_type) :: fldsToRof(fldsMax) 41 | type (fld_list_type) :: fldsFrRof(fldsMax) 42 | 43 | ! area correction factors for fluxes send and received from mediator 44 | real(r8), allocatable :: mod2med_areacor(:) 45 | real(r8), allocatable :: med2mod_areacor(:) 46 | 47 | character(*),parameter :: F01 = "('(mosart_import_export) ',a,i5,2x,i8,2x,d21.14)" 48 | character(*),parameter :: u_FILE_u = & 49 | __FILE__ 50 | 51 | !=============================================================================== 52 | contains 53 | !=============================================================================== 54 | 55 | subroutine advertise_fields(gcomp, flds_scalar_name, rc) 56 | 57 | ! input/output variables 58 | type(ESMF_GridComp) :: gcomp 59 | character(len=*) , intent(in) :: flds_scalar_name 60 | integer , intent(out) :: rc 61 | 62 | ! local variables 63 | type(ESMF_State) :: importState 64 | type(ESMF_State) :: exportState 65 | character(ESMF_MAXSTR) :: cvalue ! Character string read from driver attribute 66 | logical :: isPresent ! Atribute is present 67 | logical :: isSet ! Atribute is set 68 | integer :: n, num 69 | character(len=128) :: fldname 70 | character(len=*), parameter :: subname='(rof_import_export:advertise_fields)' 71 | !------------------------------------------------------------------------------- 72 | 73 | rc = ESMF_SUCCESS 74 | 75 | call NUOPC_ModelGet(gcomp, importState=importState, exportState=exportState, rc=rc) 76 | if (ChkErr(rc,__LINE__,u_FILE_u)) return 77 | 78 | !-------------------------------- 79 | ! Advertise export fields 80 | !-------------------------------- 81 | 82 | call NUOPC_CompAttributeGet(gcomp, name="flds_r2l_stream_channel_depths", value=cvalue, & 83 | isPresent=isPresent, isSet=isSet, rc=rc) 84 | if (ChkErr(rc,__LINE__,u_FILE_u)) return 85 | if (isPresent .and. isSet) read(cvalue,*) flds_r2l_stream_channel_depths 86 | 87 | call fldlist_add(fldsFrRof_num, fldsFrRof, trim(flds_scalar_name)) 88 | call fldlist_add(fldsFrRof_num, fldsFrRof, 'Forr_rofl') 89 | call fldlist_add(fldsFrRof_num, fldsFrRof, 'Forr_rofi') 90 | call fldlist_add(fldsFrRof_num, fldsFrRof, 'Forr_rofl_glc') 91 | call fldlist_add(fldsFrRof_num, fldsFrRof, 'Forr_rofi_glc') 92 | call fldlist_add(fldsFrRof_num, fldsFrRof, 'Flrr_flood') 93 | call fldlist_add(fldsFrRof_num, fldsFrRof, 'Flrr_volr') 94 | call fldlist_add(fldsFrRof_num, fldsFrRof, 'Flrr_volrmch') 95 | if ( flds_r2l_stream_channel_depths )then 96 | call fldlist_add(fldsFrRof_num, fldsFrRof, 'Sr_tdepth') 97 | call fldlist_add(fldsFrRof_num, fldsFrRof, 'Sr_tdepth_max') 98 | end if 99 | 100 | do n = 1,fldsFrRof_num 101 | call NUOPC_Advertise(exportState, standardName=fldsFrRof(n)%stdname, & 102 | TransferOfferGeomObject='will provide', rc=rc) 103 | if (ChkErr(rc,__LINE__,u_FILE_u)) return 104 | enddo 105 | 106 | !-------------------------------- 107 | ! Advertise import fields 108 | !-------------------------------- 109 | 110 | call fldlist_add(fldsToRof_num, fldsToRof, trim(flds_scalar_name)) 111 | call fldlist_add(fldsToRof_num, fldsToRof, 'Flrl_rofsur') 112 | call fldlist_add(fldsToRof_num, fldsToRof, 'Flrl_rofgwl') 113 | call fldlist_add(fldsToRof_num, fldsToRof, 'Flrl_rofsub') 114 | call fldlist_add(fldsToRof_num, fldsToRof, 'Flrl_rofi') 115 | call fldlist_add(fldsToRof_num, fldsToRof, 'Flrl_irrig') 116 | call fldlist_add(fldsToRof_num, fldsToRof, 'Fgrg_rofl') ! liq runoff from glc 117 | call fldlist_add(fldsToRof_num, fldsToRof, 'Fgrg_rofi') ! ice runoff from glc 118 | 119 | do n = 1,fldsToRof_num 120 | call NUOPC_Advertise(importState, standardName=fldsToRof(n)%stdname, & 121 | TransferOfferGeomObject='will provide', rc=rc) 122 | if (ChkErr(rc,__LINE__,u_FILE_u)) return 123 | enddo 124 | 125 | end subroutine advertise_fields 126 | 127 | !=============================================================================== 128 | subroutine realize_fields(gcomp, Emesh, flds_scalar_name, flds_scalar_num, rc) 129 | 130 | use ESMF , only : ESMF_GridComp, ESMF_StateGet 131 | use ESMF , only : ESMF_Mesh, ESMF_MeshGet 132 | use ESMF , only : ESMF_Field, ESMF_FieldGet, ESMF_FieldRegridGetArea 133 | use shr_const_mod , only : shr_const_rearth 134 | use shr_mpi_mod , only : shr_mpi_min, shr_mpi_max 135 | 136 | ! input/output variables 137 | type(ESMF_GridComp) , intent(inout) :: gcomp 138 | type(ESMF_Mesh) , intent(in) :: Emesh 139 | character(len=*) , intent(in) :: flds_scalar_name 140 | integer , intent(in) :: flds_scalar_num 141 | integer , intent(out) :: rc 142 | 143 | ! local variables 144 | type(ESMF_State) :: importState 145 | type(ESMF_State) :: exportState 146 | type(ESMF_Field) :: lfield 147 | integer :: numOwnedElements 148 | integer :: n,g 149 | real(r8), allocatable :: mesh_areas(:) 150 | real(r8), allocatable :: model_areas(:) 151 | real(r8), pointer :: dataptr(:) 152 | real(r8) :: re = shr_const_rearth*0.001_r8 ! radius of earth (km) 153 | real(r8) :: max_mod2med_areacor 154 | real(r8) :: max_med2mod_areacor 155 | real(r8) :: min_mod2med_areacor 156 | real(r8) :: min_med2mod_areacor 157 | real(r8) :: max_mod2med_areacor_glob 158 | real(r8) :: max_med2mod_areacor_glob 159 | real(r8) :: min_mod2med_areacor_glob 160 | real(r8) :: min_med2mod_areacor_glob 161 | character(len=*), parameter :: subname='(rof_import_export:realize_fields)' 162 | !--------------------------------------------------------------------------- 163 | 164 | rc = ESMF_SUCCESS 165 | 166 | call NUOPC_ModelGet(gcomp, importState=importState, exportState=exportState, rc=rc) 167 | if (ChkErr(rc,__LINE__,u_FILE_u)) return 168 | 169 | call fldlist_realize( & 170 | state=ExportState, & 171 | fldList=fldsFrRof, & 172 | numflds=fldsFrRof_num, & 173 | flds_scalar_name=flds_scalar_name, & 174 | flds_scalar_num=flds_scalar_num, & 175 | tag=subname//':MosartExport',& 176 | mesh=Emesh, rc=rc) 177 | if (ChkErr(rc,__LINE__,u_FILE_u)) return 178 | 179 | call fldlist_realize( & 180 | state=importState, & 181 | fldList=fldsToRof, & 182 | numflds=fldsToRof_num, & 183 | flds_scalar_name=flds_scalar_name, & 184 | flds_scalar_num=flds_scalar_num, & 185 | tag=subname//':MosartImport',& 186 | mesh=Emesh, rc=rc) 187 | if (ChkErr(rc,__LINE__,u_FILE_u)) return 188 | 189 | ! Determine areas for regridding 190 | call ESMF_MeshGet(Emesh, numOwnedElements=numOwnedElements, rc=rc) 191 | if (chkerr(rc,__LINE__,u_FILE_u)) return 192 | call ESMF_StateGet(exportState, itemName=trim(fldsFrRof(2)%stdname), field=lfield, rc=rc) 193 | if (ChkErr(rc,__LINE__,u_FILE_u)) return 194 | call ESMF_FieldRegridGetArea(lfield, rc=rc) 195 | if (chkerr(rc,__LINE__,u_FILE_u)) return 196 | call ESMF_FieldGet(lfield, farrayPtr=dataptr, rc=rc) 197 | if (chkerr(rc,__LINE__,u_FILE_u)) return 198 | allocate(mesh_areas(numOwnedElements)) 199 | mesh_areas(:) = dataptr(:) 200 | 201 | ! Determine model areas 202 | allocate(model_areas(numOwnedElements)) 203 | allocate(mod2med_areacor(numOwnedElements)) 204 | allocate(med2mod_areacor(numOwnedElements)) 205 | n = 0 206 | do g = ctl%begr,ctl%endr 207 | n = n + 1 208 | model_areas(n) = ctl%area(g)*1.0e-6_r8/(re*re) 209 | mod2med_areacor(n) = model_areas(n) / mesh_areas(n) 210 | med2mod_areacor(n) = mesh_areas(n) / model_areas(n) 211 | end do 212 | deallocate(model_areas) 213 | deallocate(mesh_areas) 214 | 215 | min_mod2med_areacor = minval(mod2med_areacor) 216 | max_mod2med_areacor = maxval(mod2med_areacor) 217 | min_med2mod_areacor = minval(med2mod_areacor) 218 | max_med2mod_areacor = maxval(med2mod_areacor) 219 | call shr_mpi_max(max_mod2med_areacor, max_mod2med_areacor_glob, mpicom_rof) 220 | call shr_mpi_min(min_mod2med_areacor, min_mod2med_areacor_glob, mpicom_rof) 221 | call shr_mpi_max(max_med2mod_areacor, max_med2mod_areacor_glob, mpicom_rof) 222 | call shr_mpi_min(min_med2mod_areacor, min_med2mod_areacor_glob, mpicom_rof) 223 | 224 | if (mainproc) then 225 | write(iulog,'(2A,2g23.15,A )') trim(subname),' : min_mod2med_areacor, max_mod2med_areacor ',& 226 | min_mod2med_areacor_glob, max_mod2med_areacor_glob, 'MOSART' 227 | write(iulog,'(2A,2g23.15,A )') trim(subname),' : min_med2mod_areacor, max_med2mod_areacor ',& 228 | min_med2mod_areacor_glob, max_med2mod_areacor_glob, 'MOSART' 229 | end if 230 | 231 | if (fldchk(importState, 'Fgrg_rofl') .and. fldchk(importState, 'Fgrg_rofl')) then 232 | ctl%rof_from_glc = .true. 233 | else 234 | ctl%rof_from_glc = .false. 235 | end if 236 | if (mainproc) then 237 | write(iulog,'(A,l1)') trim(subname) //' rof from glc is ',ctl%rof_from_glc 238 | end if 239 | 240 | end subroutine realize_fields 241 | 242 | !=============================================================================== 243 | subroutine import_fields( gcomp, begr, endr, rc ) 244 | 245 | !--------------------------------------------------------------------------- 246 | ! Obtain the runoff input from the mediator and convert from kg/m2s to m3/s 247 | !--------------------------------------------------------------------------- 248 | 249 | ! input/output variables 250 | type(ESMF_GridComp) :: gcomp 251 | integer, intent(in) :: begr, endr 252 | integer, intent(out) :: rc 253 | 254 | ! Local variables 255 | type(ESMF_State) :: importState 256 | integer :: n,nt 257 | integer :: nliq, nice 258 | character(len=*), parameter :: subname='(rof_import_export:import_fields)' 259 | !--------------------------------------------------------------------------- 260 | 261 | rc = ESMF_SUCCESS 262 | call ESMF_LogWrite(subname//' called', ESMF_LOGMSG_INFO) 263 | 264 | ! Get import state 265 | call NUOPC_ModelGet(gcomp, importState=importState, rc=rc) 266 | if (ChkErr(rc,__LINE__,u_FILE_u)) return 267 | 268 | nliq = ctl%nt_liq 269 | nice = ctl%nt_ice 270 | 271 | ! determine output array and scale by unit convertsion 272 | ! NOTE: the call to state_getimport will convert from input kg/m2s to m3/s 273 | 274 | call state_getimport(importState, 'Flrl_rofsur', begr, endr, ctl%area, output=ctl%qsur(:,nliq), & 275 | do_area_correction=.true., rc=rc) 276 | if (ChkErr(rc,__LINE__,u_FILE_u)) return 277 | 278 | call state_getimport(importState, 'Flrl_rofsub', begr, endr, ctl%area, output=ctl%qsub(:,nliq), & 279 | do_area_correction=.true., rc=rc) 280 | if (ChkErr(rc,__LINE__,u_FILE_u)) return 281 | 282 | call state_getimport(importState, 'Flrl_rofgwl', begr, endr, ctl%area, output=ctl%qgwl(:,nliq), & 283 | do_area_correction=.true., rc=rc) 284 | if (ChkErr(rc,__LINE__,u_FILE_u)) return 285 | 286 | call state_getimport(importState, 'Flrl_rofi', begr, endr, ctl%area, output=ctl%qsur(:,nice), & 287 | do_area_correction=.true., rc=rc) 288 | if (ChkErr(rc,__LINE__,u_FILE_u)) return 289 | 290 | call state_getimport(importState, 'Flrl_irrig', begr, endr, ctl%area, output=ctl%qirrig(:), & 291 | do_area_correction=.true., rc=rc) 292 | if (ChkErr(rc,__LINE__,u_FILE_u)) return 293 | 294 | ctl%qsub(begr:endr, nice) = 0.0_r8 295 | ctl%qgwl(begr:endr, nice) = 0.0_r8 296 | 297 | if (ctl%rof_from_glc) then 298 | call state_getimport(importState, 'Fgrg_rofl', begr, endr, ctl%area, output=ctl%qglc_liq(:), & 299 | do_area_correction=.true., rc=rc) 300 | if (ChkErr(rc,__LINE__,u_FILE_u)) return 301 | call state_getimport(importState, 'Fgrg_rofi', begr, endr, ctl%area, output=ctl%qglc_ice(:), & 302 | do_area_correction=.true., rc=rc) 303 | if (ChkErr(rc,__LINE__,u_FILE_u)) return 304 | else 305 | ctl%qglc_liq(:) = 0._r8 306 | ctl%qglc_ice(:) = 0._r8 307 | end if 308 | 309 | end subroutine import_fields 310 | 311 | !==================================================================================== 312 | subroutine export_fields (gcomp, begr, endr, rc) 313 | 314 | !--------------------------------------------------------------------------- 315 | ! Send the runoff model export state to the mediator and convert from m3/s to kg/m2s 316 | !--------------------------------------------------------------------------- 317 | 318 | ! input/output/variables 319 | type(ESMF_GridComp) :: gcomp 320 | integer, intent(in) :: begr, endr 321 | integer, intent(out) :: rc 322 | 323 | ! Local variables 324 | type(ESMF_State) :: exportState 325 | integer :: n,nt 326 | integer :: nliq, nice 327 | real(r8) :: rofl(begr:endr) 328 | real(r8) :: rofi(begr:endr) 329 | real(r8) :: rofl_glc(begr:endr) 330 | real(r8) :: rofi_glc(begr:endr) 331 | real(r8) :: flood(begr:endr) 332 | real(r8) :: volr(begr:endr) 333 | real(r8) :: volrmch(begr:endr) 334 | real(r8) :: tdepth(begr:endr) 335 | real(r8) :: tdepth_max(begr:endr) 336 | logical, save :: first_time = .true. 337 | character(len=*), parameter :: subname='(rof_import_export:export_fields)' 338 | !--------------------------------------------------------------------------- 339 | 340 | rc = ESMF_SUCCESS 341 | call ESMF_LogWrite(subname//' called', ESMF_LOGMSG_INFO) 342 | 343 | ! Get export state 344 | call NUOPC_ModelGet(gcomp, exportState=exportState, rc=rc) 345 | if (ChkErr(rc,__LINE__,u_FILE_u)) return 346 | 347 | ! Set tracers 348 | nliq = ctl%nt_liq 349 | nice = ctl%nt_ice 350 | 351 | if (first_time) then 352 | if (mainproc) then 353 | if ( ice_runoff )then 354 | write(iulog,*)'Snow capping will flow out in frozen river runoff' 355 | else 356 | write(iulog,*)'Snow capping will flow out in liquid river runoff' 357 | endif 358 | endif 359 | first_time = .false. 360 | end if 361 | 362 | if ( ice_runoff )then 363 | ! separate liquid and ice runoff 364 | do n = begr,endr 365 | rofl(n) = ctl%direct(n,nliq) / (ctl%area(n)*0.001_r8) 366 | rofi(n) = ctl%direct(n,nice) / (ctl%area(n)*0.001_r8) 367 | if (ctl%mask(n) >= 2) then 368 | ! liquid and ice runoff are treated separately - this is what goes to the ocean 369 | rofl(n) = rofl(n) + ctl%runoff(n,nliq) / (ctl%area(n)*0.001_r8) 370 | rofi(n) = rofi(n) + ctl%runoff(n,nice) / (ctl%area(n)*0.001_r8) 371 | end if 372 | end do 373 | else 374 | ! liquid and ice runoff added to liquid runoff, ice runoff is zero 375 | do n = begr,endr 376 | rofl(n) = (ctl%direct(n,nice) + ctl%direct(n,nliq)) / (ctl%area(n)*0.001_r8) 377 | if (ctl%mask(n) >= 2) then 378 | rofl(n) = rofl(n) + (ctl%runoff(n,nice) + ctl%runoff(n,nliq)) / (ctl%area(n)*0.001_r8) 379 | endif 380 | rofi(n) = 0._r8 381 | end do 382 | end if 383 | 384 | do n = begr,endr 385 | rofl_glc(n) = ctl%direct_glc(n,nliq) / (ctl%area(n)*0.001_r8) 386 | rofi_glc(n) = ctl%direct_glc(n,nice) / (ctl%area(n)*0.001_r8) 387 | end do 388 | 389 | ! Flooding back to land, sign convention is positive in land->rof direction 390 | ! so if water is sent from rof to land, the flux must be negative. 391 | ! scs: is there a reason for the wr+wt rather than volr (wr+wt+wh)? 392 | ! volr(n) = (Trunoff%wr(n,nliq) + Trunoff%wt(n,nliq)) / ctl%area(n) 393 | 394 | do n = begr, endr 395 | flood(n) = -ctl%flood(n) / (ctl%area(n)*0.001_r8) 396 | volr(n) = ctl%volr(n,nliq)/ ctl%area(n) 397 | volrmch(n) = Trunoff%wr(n,nliq) / ctl%area(n) 398 | if ( flds_r2l_stream_channel_depths )then 399 | tdepth(n) = Trunoff%yt(n,nliq) 400 | ! assume height to width ratio is the same for tributaries and main channel 401 | tdepth_max(n) = max(TUnit%twidth0(n),0._r8)*(TUnit%rdepth(n)/TUnit%rwidth(n)) 402 | end if 403 | end do 404 | 405 | call state_setexport(exportState, 'Forr_rofl', begr, endr, input=rofl, do_area_correction=.true., rc=rc) 406 | if (ChkErr(rc,__LINE__,u_FILE_u)) return 407 | 408 | call state_setexport(exportState, 'Forr_rofi', begr, endr, input=rofi, do_area_correction=.true., rc=rc) 409 | if (ChkErr(rc,__LINE__,u_FILE_u)) return 410 | 411 | call state_setexport(exportState, 'Forr_rofl_glc', begr, endr, input=rofl_glc, do_area_correction=.true., rc=rc) 412 | if (ChkErr(rc,__LINE__,u_FILE_u)) return 413 | 414 | call state_setexport(exportState, 'Forr_rofi_glc', begr, endr, input=rofi_glc, do_area_correction=.true., rc=rc) 415 | if (ChkErr(rc,__LINE__,u_FILE_u)) return 416 | 417 | call state_setexport(exportState, 'Flrr_flood', begr, endr, input=flood, do_area_correction=.true., rc=rc) 418 | if (ChkErr(rc,__LINE__,u_FILE_u)) return 419 | 420 | call state_setexport(exportState, 'Flrr_volr', begr, endr, input=volr, do_area_correction=.true., rc=rc) 421 | if (ChkErr(rc,__LINE__,u_FILE_u)) return 422 | 423 | call state_setexport(exportState, 'Flrr_volrmch', begr, endr, input=volrmch, do_area_correction=.true., rc=rc) 424 | if (ChkErr(rc,__LINE__,u_FILE_u)) return 425 | 426 | if ( flds_r2l_stream_channel_depths ) then 427 | call state_setexport(exportState, 'Sr_tdepth', begr, endr, input=tdepth, do_area_correction=.true., rc=rc) 428 | if (ChkErr(rc,__LINE__,u_FILE_u)) return 429 | 430 | call state_setexport(exportState, 'Sr_tdepth_max', begr, endr, input=tdepth_max, do_area_correction=.true., rc=rc) 431 | if (ChkErr(rc,__LINE__,u_FILE_u)) return 432 | end if 433 | 434 | end subroutine export_fields 435 | 436 | !=============================================================================== 437 | subroutine fldlist_add(num, fldlist, stdname) 438 | integer, intent(inout) :: num 439 | type(fld_list_type), intent(inout) :: fldlist(:) 440 | character(len=*), intent(in) :: stdname 441 | 442 | ! local variables 443 | integer :: rc 444 | character(len=*), parameter :: subname='(rof_import_export:fldlist_add)' 445 | !------------------------------------------------------------------------------- 446 | 447 | ! Set up a list of field information 448 | 449 | num = num + 1 450 | if (num > fldsMax) then 451 | call ESMF_LogWrite(trim(subname)//": ERROR num > fldsMax "//trim(stdname), & 452 | ESMF_LOGMSG_ERROR, line=__LINE__, file=__FILE__) 453 | return 454 | endif 455 | fldlist(num)%stdname = trim(stdname) 456 | 457 | end subroutine fldlist_add 458 | 459 | !=============================================================================== 460 | subroutine fldlist_realize(state, fldList, numflds, flds_scalar_name, flds_scalar_num, mesh, tag, rc) 461 | 462 | use NUOPC , only : NUOPC_IsConnected, NUOPC_Realize 463 | use ESMF , only : ESMF_MeshLoc_Element, ESMF_FieldCreate, ESMF_TYPEKIND_R8 464 | use ESMF , only : ESMF_MAXSTR, ESMF_Field, ESMF_State, ESMF_Mesh, ESMF_StateRemove 465 | use ESMF , only : ESMF_LogFoundError, ESMF_LOGMSG_INFO, ESMF_SUCCESS 466 | use ESMF , only : ESMF_LogWrite, ESMF_LOGMSG_ERROR, ESMF_LOGERR_PASSTHRU 467 | 468 | type(ESMF_State) , intent(inout) :: state 469 | type(fld_list_type) , intent(in) :: fldList(:) 470 | integer , intent(in) :: numflds 471 | character(len=*) , intent(in) :: flds_scalar_name 472 | integer , intent(in) :: flds_scalar_num 473 | character(len=*) , intent(in) :: tag 474 | type(ESMF_Mesh) , intent(in) :: mesh 475 | integer , intent(inout) :: rc 476 | 477 | ! local variables 478 | integer :: dbrc 479 | integer :: n 480 | type(ESMF_Field) :: field 481 | character(len=80) :: stdname 482 | character(len=*),parameter :: subname='(rof_import_export:fldlist_realize)' 483 | ! ---------------------------------------------- 484 | 485 | rc = ESMF_SUCCESS 486 | 487 | do n = 1, numflds 488 | stdname = fldList(n)%stdname 489 | if (NUOPC_IsConnected(state, fieldName=stdname)) then 490 | if (stdname == trim(flds_scalar_name)) then 491 | call ESMF_LogWrite(trim(subname)//trim(tag)//" Field = "//trim(stdname)//" is connected on root pe", & 492 | ESMF_LOGMSG_INFO, rc=dbrc) 493 | ! Create the scalar field 494 | call SetScalarField(field, flds_scalar_name, flds_scalar_num, rc=rc) 495 | if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=u_FILE_u)) return 496 | else 497 | call ESMF_LogWrite(trim(subname)//trim(tag)//" Field = "//trim(stdname)//" is connected using mesh", & 498 | ESMF_LOGMSG_INFO, rc=dbrc) 499 | ! Create the field 500 | field = ESMF_FieldCreate(mesh, ESMF_TYPEKIND_R8, name=stdname, meshloc=ESMF_MESHLOC_ELEMENT, rc=rc) 501 | if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=u_FILE_u)) return 502 | endif 503 | 504 | ! NOW call NUOPC_Realize 505 | call NUOPC_Realize(state, field=field, rc=rc) 506 | if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=u_FILE_u)) return 507 | else 508 | if (stdname /= trim(flds_scalar_name)) then 509 | call ESMF_LogWrite(subname // trim(tag) // " Field = "// trim(stdname) // " is not connected.", & 510 | ESMF_LOGMSG_INFO, rc=dbrc) 511 | call ESMF_StateRemove(state, (/stdname/), rc=rc) 512 | if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=u_FILE_u)) return 513 | end if 514 | end if 515 | end do 516 | 517 | contains !- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 518 | 519 | subroutine SetScalarField(field, flds_scalar_name, flds_scalar_num, rc) 520 | ! ---------------------------------------------- 521 | ! create a field with scalar data on the root pe 522 | ! ---------------------------------------------- 523 | use ESMF, only : ESMF_Field, ESMF_DistGrid, ESMF_Grid 524 | use ESMF, only : ESMF_DistGridCreate, ESMF_GridCreate, ESMF_LogFoundError, ESMF_LOGERR_PASSTHRU 525 | use ESMF, only : ESMF_FieldCreate, ESMF_GridCreate, ESMF_TYPEKIND_R8 526 | 527 | type(ESMF_Field) , intent(inout) :: field 528 | character(len=*) , intent(in) :: flds_scalar_name 529 | integer , intent(in) :: flds_scalar_num 530 | integer , intent(inout) :: rc 531 | 532 | ! local variables 533 | type(ESMF_Distgrid) :: distgrid 534 | type(ESMF_Grid) :: grid 535 | character(len=*), parameter :: subname='(rof_import_export:SetScalarField)' 536 | ! ---------------------------------------------- 537 | 538 | rc = ESMF_SUCCESS 539 | 540 | ! create a DistGrid with a single index space element, which gets mapped onto DE 0. 541 | distgrid = ESMF_DistGridCreate(minIndex=(/1/), maxIndex=(/1/), rc=rc) 542 | if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=u_FILE_u)) return 543 | 544 | grid = ESMF_GridCreate(distgrid, rc=rc) 545 | if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=u_FILE_u)) return 546 | 547 | field = ESMF_FieldCreate(name=trim(flds_scalar_name), grid=grid, typekind=ESMF_TYPEKIND_R8, & 548 | ungriddedLBound=(/1/), ungriddedUBound=(/flds_scalar_num/), gridToFieldMap=(/2/), rc=rc) 549 | if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=u_FILE_u)) return 550 | 551 | end subroutine SetScalarField 552 | 553 | end subroutine fldlist_realize 554 | 555 | !=============================================================================== 556 | subroutine state_getimport(state, fldname, begr, endr, area, output, do_area_correction, rc) 557 | 558 | ! ---------------------------------------------- 559 | ! Map import state field to output array 560 | ! ---------------------------------------------- 561 | 562 | use ESMF, only : ESMF_StateGet, ESMF_FieldGet, ESMF_Field 563 | 564 | ! input/output variables 565 | type(ESMF_State) , intent(in) :: state 566 | character(len=*) , intent(in) :: fldname 567 | integer , intent(in) :: begr 568 | integer , intent(in) :: endr 569 | real(r8) , intent(in) :: area(begr:endr) 570 | logical , intent(in) :: do_area_correction 571 | real(r8) , intent(out) :: output(begr:endr) 572 | integer , intent(out) :: rc 573 | 574 | ! local variables 575 | type(ESMF_Field) :: lfield 576 | integer :: g, i 577 | real(R8), pointer :: fldptr(:) 578 | character(len=*), parameter :: subname='(rof_import_export:state_getimport)' 579 | ! ---------------------------------------------- 580 | 581 | rc = ESMF_SUCCESS 582 | 583 | ! get field pointer 584 | call ESMF_StateGet(State, itemName=trim(fldname), field=lfield, rc=rc) 585 | if (ChkErr(rc,__LINE__,u_FILE_u)) return 586 | call ESMF_FieldGet(lfield, farrayPtr=fldptr, rc=rc) 587 | if (ChkErr(rc,__LINE__,u_FILE_u)) return 588 | 589 | ! determine output array and scale by unit convertsion 590 | if (do_area_correction) then 591 | fldptr(:) = fldptr(:) * med2mod_areacor(:) 592 | end if 593 | do g = begr,endr 594 | output(g) = fldptr(g-begr+1) * area(g)*0.001_r8 595 | end do 596 | 597 | ! check for nans 598 | call check_for_nans(fldptr, trim(fldname), begr) 599 | 600 | end subroutine state_getimport 601 | 602 | !=============================================================================== 603 | subroutine state_setexport(state, fldname, begr, endr, input, do_area_correction, rc) 604 | 605 | ! ---------------------------------------------- 606 | ! Map input array to export state field 607 | ! ---------------------------------------------- 608 | 609 | use ESMF , only : ESMF_StateGet, ESMF_FieldGet, ESMF_Field 610 | use shr_const_mod, only : fillvalue=>shr_const_spval 611 | 612 | ! input/output variables 613 | type(ESMF_State) , intent(inout) :: state 614 | character(len=*) , intent(in) :: fldname 615 | integer , intent(in) :: begr 616 | integer , intent(in) :: endr 617 | real(r8) , intent(in) :: input(begr:endr) 618 | logical , intent(in) :: do_area_correction 619 | integer , intent(out) :: rc 620 | 621 | ! local variables 622 | type(ESMF_Field) :: lfield 623 | integer :: g, i 624 | real(R8), pointer :: fldptr(:) 625 | character(len=*), parameter :: subname='(rof_import_export:state_setexport)' 626 | ! ---------------------------------------------- 627 | 628 | rc = ESMF_SUCCESS 629 | 630 | ! get field pointer 631 | call ESMF_StateGet(State, itemName=trim(fldname), field=lfield, rc=rc) 632 | if (ChkErr(rc,__LINE__,u_FILE_u)) return 633 | call ESMF_FieldGet(lfield, farrayPtr=fldptr, rc=rc) 634 | if (ChkErr(rc,__LINE__,u_FILE_u)) return 635 | 636 | ! set fldptr values to input array 637 | fldptr(:) = 0._r8 638 | do g = begr,endr 639 | fldptr(g-begr+1) = input(g) 640 | end do 641 | if (do_area_correction) then 642 | fldptr(:) = fldptr(:) * mod2med_areacor(:) 643 | end if 644 | 645 | ! check for nans 646 | call check_for_nans(fldptr, trim(fldname), begr) 647 | 648 | end subroutine state_setexport 649 | 650 | !=============================================================================== 651 | 652 | subroutine check_for_nans(array, fname, begg) 653 | 654 | ! uses 655 | use shr_infnan_mod, only : isnan => shr_infnan_isnan 656 | 657 | ! input/output variables 658 | real(r8) , pointer :: array(:) 659 | character(len=*) , intent(in) :: fname 660 | integer , intent(in) :: begg 661 | 662 | ! local variables 663 | integer :: i 664 | !------------------------------------------------------------------------------- 665 | 666 | ! Check if any input from mediator or output to mediator is NaN 667 | 668 | if (any(isnan(array))) then 669 | write(iulog,*) '# of NaNs = ', count(isnan(array)) 670 | write(iulog,*) 'Which are NaNs = ', isnan(array) 671 | do i = 1, size(array) 672 | if (isnan(array(i))) then 673 | write(iulog,*) "NaN found in field ", trim(fname), ' at gridcell index ',begg+i-1 674 | end if 675 | end do 676 | call shr_sys_abort(' ERROR: One or more of the output from MOSART to the coupler are NaN ' ) 677 | end if 678 | end subroutine check_for_nans 679 | 680 | !=============================================================================== 681 | logical function fldchk(state, fldname) 682 | ! ---------------------------------------------- 683 | ! Determine if field with fldname is in the input state 684 | ! ---------------------------------------------- 685 | 686 | ! input/output variables 687 | type(ESMF_State), intent(in) :: state 688 | character(len=*), intent(in) :: fldname 689 | 690 | ! local variables 691 | type(ESMF_StateItem_Flag) :: itemFlag 692 | ! ---------------------------------------------- 693 | call ESMF_StateGet(state, trim(fldname), itemFlag) 694 | if (itemflag /= ESMF_STATEITEM_NOTFOUND) then 695 | fldchk = .true. 696 | else 697 | fldchk = .false. 698 | endif 699 | end function fldchk 700 | 701 | end module rof_import_export 702 | -------------------------------------------------------------------------------- /src/riverroute/mosart_budget_type.F90: -------------------------------------------------------------------------------- 1 | module mosart_budget_type 2 | 3 | ! Variables and routines used for 4 | ! calculating and checking tracer global and local budgets 5 | 6 | use shr_kind_mod, only: r8 => shr_kind_r8, CL => SHR_KIND_CL 7 | use shr_sys_mod, only: shr_sys_abort 8 | use shr_mpi_mod, only: shr_mpi_sum, shr_mpi_max 9 | use mosart_vars, only: re, spval, barrier_timers, iulog, mainproc, npes, iam, mpicom_rof 10 | use mosart_data, only: ctl, Tctl, Tunit, TRunoff, Tpara 11 | use mosart_timemanager, only: get_nstep, get_curr_date 12 | 13 | implicit none 14 | private 15 | 16 | type budget_type 17 | ! accumulated budget over run (not used for now) 18 | real(r8), pointer :: accum_grc(:, :) ! Gridcell level budget accumulator per tracer over the run (m3) 19 | real(r8), pointer :: accum_glob(:) ! Global budget accumulator (1e6 m3) 20 | 21 | ! budget terms per gridcell 22 | real(r8), pointer :: beg_vol_grc(:, :) ! volume begining of the timestep (m3) 23 | real(r8), pointer :: end_vol_grc(:, :) ! volume end of the timestep (m3) 24 | real(r8), pointer :: in_grc(:, :) ! budget in terms (m3) 25 | real(r8), pointer :: out_grc(:, :) ! budget out terms (m3) 26 | real(r8), pointer :: net_grc(:, :) ! net budget (dvolume + inputs - outputs) (m3) 27 | real(r8), pointer :: lag_grc(:, :) ! euler erout lagged (m3) 28 | 29 | ! budget global terms 30 | real(r8), pointer :: beg_vol_glob(:) ! volume begining of the timestep (1e6 m3) 31 | real(r8), pointer :: end_vol_glob(:) ! volume end of the timestep (1e6 m3) 32 | real(r8), pointer :: in_glob(:) ! budget in terms (1e6 m3) 33 | real(r8), pointer :: out_glob(:) ! budget out terms (1e6 m3) 34 | real(r8), pointer :: net_glob(:) ! net budget (dvolume + inputs - outputs) (1e6 m3) 35 | real(r8), pointer :: lag_glob(:) ! euler erout lagged (1e6 m3) 36 | 37 | ! budget parameters 38 | real(r8) :: tolerance = 1e-6_r8 ! budget absolute tolerance 39 | real(r8) :: rel_tolerance = 1e-6_r8 ! budget relative tolerance 40 | logical(r8), pointer :: do_budget(:) ! if budget should be checked (per tracer) 41 | contains 42 | procedure, public :: Init 43 | procedure, public :: set_budget 44 | procedure, public :: check_budget 45 | end type budget_type 46 | public :: budget_type 47 | 48 | integer, parameter :: index_beg_vol_grc = 1 49 | integer, parameter :: index_end_vol_grc = 2 50 | integer, parameter :: index_in_grc = 3 51 | integer, parameter :: index_out_grc = 4 52 | integer, parameter :: index_net_grc = 5 53 | integer, parameter :: index_lag_grc = 6 54 | 55 | character(*), parameter :: u_FILE_u = & 56 | __FILE__ 57 | 58 | !----------------------------------------------------------------------- 59 | contains 60 | !----------------------------------------------------------------------- 61 | 62 | subroutine Init(this, begr, endr, ntracers) 63 | 64 | ! Initialize budget type 65 | 66 | ! Arguments 67 | class(budget_type) :: this 68 | integer, intent(in) :: begr, endr, ntracers 69 | !------------------------------------------------- 70 | 71 | ! gridcell level: 72 | allocate (this%accum_grc(begr:endr, ntracers)) 73 | this%accum_grc = 0._r8 74 | 75 | allocate (this%beg_vol_grc(begr:endr, ntracers)) 76 | this%beg_vol_grc = 0._r8 77 | 78 | allocate (this%end_vol_grc(begr:endr, ntracers)) 79 | this%end_vol_grc = 0._r8 80 | 81 | allocate (this%in_grc(begr:endr, ntracers)) 82 | this%in_grc = 0._r8 83 | 84 | allocate (this%out_grc(begr:endr, ntracers)) 85 | this%out_grc = 0._r8 86 | 87 | allocate (this%net_grc(begr:endr, ntracers)) 88 | this%net_grc = 0._r8 89 | 90 | allocate (this%lag_grc(begr:endr, ntracers)) 91 | this%lag_grc = 0._r8 92 | 93 | ! global level: 94 | allocate (this%accum_glob(ntracers)) 95 | this%accum_glob = 0._r8 96 | 97 | allocate (this%beg_vol_glob(ntracers)) 98 | this%beg_vol_glob = 0._r8 99 | 100 | allocate (this%end_vol_glob(ntracers)) 101 | this%end_vol_glob = 0._r8 102 | 103 | allocate (this%in_glob(ntracers)) 104 | this%in_glob = 0._r8 105 | 106 | allocate (this%out_glob(ntracers)) 107 | this%out_glob = 0._r8 108 | 109 | allocate (this%net_glob(ntracers)) 110 | this%net_glob = 0._r8 111 | 112 | allocate (this%lag_glob(ntracers)) 113 | this%lag_glob = 0._r8 114 | 115 | allocate (this%do_budget(ntracers)) 116 | this%do_budget = .true. 117 | 118 | end subroutine Init 119 | 120 | !----------------------------------------------------------------------- 121 | 122 | subroutine set_budget(this, begr, endr, ntracers, dt) 123 | 124 | ! Arguments 125 | class(budget_type) :: this 126 | integer, intent(in) :: begr, endr, ntracers 127 | real(r8), intent(in) :: dt 128 | 129 | ! local variables 130 | integer :: nr, nt !indices 131 | integer :: nt_liq, nt_ice 132 | !------------------------------------------------- 133 | 134 | nt_liq = ctl%nt_liq 135 | nt_ice = ctl%nt_ice 136 | do nr = begr, endr 137 | do nt = 1, ntracers 138 | this%beg_vol_grc(nr, nt) = ctl%volr(nr, nt) 139 | if (nt == nt_ice) then 140 | this%in_grc(nr, nt) = (ctl%qsur(nr, nt) + ctl%qsub(nr, nt) + ctl%qgwl(nr, nt) + ctl%qglc_ice(nr)) * dt 141 | else if (nt == nt_liq) then 142 | this%in_grc(nr, nt) = (ctl%qsur(nr, nt) + ctl%qsub(nr, nt) + ctl%qgwl(nr, nt) + ctl%qglc_liq(nr)) * dt 143 | end if 144 | ! this was for budget_terms(17) 145 | !if (nt==1) then 146 | ! this%in_grc(nr,nt)=this%in_grc(nr,nt) +ctl%qirrig(nr) 147 | !endif 148 | end do 149 | end do 150 | 151 | this%end_vol_grc(:,:) = 0.0_r8 152 | this%out_grc(:,:) = 0.0_r8 153 | this%net_grc(:,:) = 0.0_r8 154 | this%lag_grc(:,:) = 0.0_r8 155 | 156 | this%beg_vol_glob(:) = 0.0_r8 157 | this%end_vol_glob(:) = 0.0_r8 158 | this%in_glob(:) = 0.0_r8 159 | this%out_glob(:) = 0.0_r8 160 | this%net_glob(:) = 0.0_r8 161 | this%lag_glob(:) = 0.0_r8 162 | 163 | end subroutine set_budget 164 | 165 | !----------------------------------------------------------------------- 166 | 167 | subroutine check_budget(this, begr, endr, ntracers, dt) 168 | 169 | ! Arguments 170 | class(budget_type) :: this 171 | integer, intent(in) :: begr, endr, ntracers 172 | real(r8), intent(in) :: dt 173 | 174 | ! Local variables 175 | integer :: nr, nt !indecies 176 | integer :: nt_liq ! liquid index 177 | integer :: yr,mon,day,ymd,tod !time vars 178 | real(r8) :: tmp_in(6, ntracers) ! array to pass to mpi_sum 179 | real(r8) :: tmp_glob(6, ntracers) ! array from mpi_sum 180 | logical :: error_budget ! flag for an error 181 | real(r8) :: abserr, relerr 182 | !------------------------------------------------- 183 | 184 | call get_curr_date(yr, mon, day, tod) 185 | ymd = yr*10000 + mon*100 + day 186 | tmp_in = 0.0_r8 187 | tmp_glob = 0.0_r8 188 | 189 | nt_liq = ctl%nt_liq 190 | do nr = begr, endr 191 | do nt = 1, ntracers 192 | this%end_vol_grc(nr, nt) = ctl%volr(nr, nt) 193 | this%out_grc(nr, nt) = this%out_grc(nr, nt) + ctl%direct(nr, nt) + ctl%direct_glc(nr, nt) 194 | if (nt == nt_liq) then 195 | this%out_grc(nr, nt) = this%out_grc(nr, nt) + ctl%flood(nr) 196 | end if 197 | if (ctl%mask(nr) >= 2) then 198 | this%out_grc(nr, nt) = this%out_grc(nr, nt) + ctl%runoff(nr, nt) 199 | else 200 | this%lag_grc(nr, nt) = this%lag_grc(nr, nt) - ctl%erout_prev(nr, nt) - ctl%flow(nr, nt) 201 | end if 202 | this%out_grc(nr,nt) = this%out_grc(nr,nt) * dt 203 | this%lag_grc(nr,nt) = this%lag_grc(nr,nt) * dt 204 | this%net_grc(nr,nt) = this%end_vol_grc(nr,nt) - this%beg_vol_grc(nr,nt) - (this%in_grc(nr,nt)-this%out_grc(nr,nt)) 205 | this%accum_grc(nr,nt) = this%accum_grc(nr,nt) + this%net_grc(nr,nt) 206 | end do 207 | end do 208 | 209 | do nt = 1, ntracers 210 | tmp_in(index_beg_vol_grc, nt) = sum(this%beg_vol_grc(:, nt)) 211 | tmp_in(index_end_vol_grc, nt) = sum(this%end_vol_grc(:, nt)) 212 | tmp_in(index_in_grc, nt) = sum(this%in_grc(:, nt)) 213 | tmp_in(index_out_grc, nt) = sum(this%out_grc(:, nt)) 214 | tmp_in(index_net_grc, nt) = sum(this%net_grc(:, nt)) 215 | tmp_in(index_lag_grc, nt) = sum(this%lag_grc(:, nt)) 216 | end do 217 | 218 | tmp_in = tmp_in*1e-6_r8 !convert to million m3 219 | call shr_mpi_sum(tmp_in, tmp_glob, mpicom_rof, 'mosart global budget', all=.false.) 220 | 221 | do nt = 1, ntracers 222 | error_budget = .false. 223 | abserr = 0.0_r8 224 | relerr = 0.0_r8 225 | this%beg_vol_glob(nt) = tmp_glob(index_beg_vol_grc, nt) 226 | this%end_vol_glob(nt) = tmp_glob(index_end_vol_grc, nt) 227 | this%in_glob(nt) = tmp_glob(index_in_grc, nt) 228 | this%out_glob(nt) = tmp_glob(index_out_grc, nt) 229 | this%net_glob(nt) = tmp_glob(index_net_grc, nt) 230 | this%lag_glob(nt) = tmp_glob(index_lag_grc, nt) 231 | if (this%do_budget(nt)) then 232 | if (abs(this%net_glob(nt) - this%lag_glob(nt)*dt) > this%tolerance) then 233 | error_budget = .true. 234 | abserr = abs(this%net_glob(nt) - this%lag_glob(nt)) 235 | end if 236 | if (abs(this%net_glob(nt) + this%lag_glob(nt)) > 1e-6) then 237 | if ( abs(this%net_glob(nt) - this%lag_glob(nt)) & 238 | /abs(this%net_glob(nt) + this%lag_glob(nt)) > this%rel_tolerance) then 239 | error_budget = .true. 240 | relerr = abs(this%net_glob(nt) - this%lag_glob(nt)) /abs(this%net_glob(nt) + this%lag_glob(nt)) 241 | end if 242 | end if 243 | if (mainproc) then 244 | write (iulog, '(a)') '-----------------------------------' 245 | write (iulog, '(a)') '*****MOSART BUDGET DIAGNOSTICS*****' 246 | write (iulog,'(a,i10,i6)') ' diagnostics for ', ymd, tod 247 | write (iulog, '(a,i4,2a)') ' tracer = ', nt, ' ', ctl%tracer_names(nt) 248 | write (iulog, '(a,f22.6,a)') ' time step size = ', dt, ' sec' 249 | write (iulog, '(a,f22.6,a)') ' volume begining of the step = ', this%beg_vol_glob(nt), ' (mil m3)' 250 | write (iulog, '(a,f22.6,a)') ' volume end of the step = ', this%end_vol_glob(nt), ' (mil m3)' 251 | write (iulog, '(a,f22.6,a)') ' inputs = ', this%in_glob(nt), ' (mil m3)' 252 | write (iulog, '(a,f22.6,a)') ' outputs = ', this%out_glob(nt), ' (mil m3)' 253 | write (iulog, '(a,f22.6,a)') ' net budget (dv -i + o) = ', this%net_glob(nt), ' (mil m3)' 254 | write (iulog, '(a,f22.6,a)') ' eul erout lag = ', this%lag_glob(nt), '(mil m3)' 255 | write (iulog, '(a,f22.6)') ' absolute budget error = ', abserr 256 | write (iulog, '(a,f22.6)') ' relative budget error = ', relerr 257 | if (error_budget) then 258 | write(iulog,'(a)') ' BUDGET OUT OF BALANCE WARNING ' 259 | endif 260 | write (iulog, '(a)') '-----------------------------------' 261 | end if 262 | end if 263 | end do 264 | 265 | end subroutine check_budget 266 | 267 | end module mosart_budget_type 268 | -------------------------------------------------------------------------------- /src/riverroute/mosart_data.F90: -------------------------------------------------------------------------------- 1 | module mosart_data 2 | 3 | use mosart_control_type, only : control_type 4 | use mosart_tctl_type, only : tctl_type 5 | use mosart_tspatialunit_type, only : tspatialunit_type 6 | use mosart_tstatusflux_type, only : tstatusflux_type 7 | use mosart_tparameter_type, only : tparameter_type 8 | 9 | implicit none 10 | private 11 | 12 | ! Derived types 13 | type(Tctl_type), public :: Tctl 14 | type(Tspatialunit_type), public :: TUnit 15 | type(TstatusFlux_type), public :: TRunoff 16 | type(Tparameter_type), public :: TPara 17 | type(control_type), public :: ctl 18 | 19 | end module mosart_data 20 | -------------------------------------------------------------------------------- /src/riverroute/mosart_fileutils.F90: -------------------------------------------------------------------------------- 1 | module mosart_fileutils 2 | 3 | ! Module containing file I/O utilities 4 | 5 | use shr_sys_mod , only : shr_sys_abort 6 | use shr_kind_mod, only : CL=>shr_kind_cl 7 | use mosart_vars , only : iulog, mainproc 8 | 9 | implicit none 10 | private 11 | 12 | ! !PUBLIC MEMBER FUNCTIONS: 13 | public :: get_filename !Returns filename given full pathname 14 | public :: getfil !Obtain local copy of file 15 | !----------------------------------------------------------------------- 16 | 17 | contains 18 | 19 | !----------------------------------------------------------------------- 20 | character(len=CL) function get_filename (fulpath) 21 | 22 | ! Returns filename given full pathname 23 | ! 24 | ! !ARGUMENTS: 25 | character(len=*), intent(in) :: fulpath !full pathname 26 | ! 27 | ! !LOCAL VARIABLES: 28 | integer i !loop index 29 | integer klen !length of fulpath character string 30 | !---------------------------------------------------------- 31 | 32 | klen = len_trim(fulpath) 33 | do i = klen, 1, -1 34 | if (fulpath(i:i) == '/') go to 10 35 | end do 36 | i = 0 37 | 10 get_filename = fulpath(i+1:klen) 38 | 39 | end function get_filename 40 | 41 | !------------------------------------------------------------------------ 42 | 43 | subroutine getfil (fulpath, locfn, iflag) 44 | 45 | ! Obtain local copy of file. First check current working directory, 46 | ! Next check full pathname[fulpath] on disk 47 | ! 48 | ! !ARGUMENTS: 49 | character(len=*), intent(in) :: fulpath !Archival or permanent disk full pathname 50 | character(len=*), intent(out) :: locfn !output local file name 51 | integer, intent(in) :: iflag !0=>abort if file not found 1=>do not abort 52 | 53 | ! !LOCAL VARIABLES: 54 | integer i !loop index 55 | logical lexist !true if local file exists 56 | !-------------------------------------------------- 57 | 58 | ! get local file name from full name 59 | locfn = get_filename( fulpath ) 60 | if (len_trim(locfn) == 0) then 61 | if (mainproc) write(iulog,*)'(GETFIL): local filename has zero length' 62 | call shr_sys_abort() 63 | else 64 | if (mainproc) write(iulog,*)'(GETFIL): attempting to find local file ',trim(locfn) 65 | endif 66 | 67 | ! first check if file is in current working directory. 68 | inquire (file=locfn,exist=lexist) 69 | if (lexist) then 70 | if (mainproc) write(iulog,*) '(GETFIL): using ',trim(locfn),' in current working directory' 71 | RETURN 72 | endif 73 | 74 | ! second check for full pathname on disk 75 | locfn = fulpath 76 | 77 | inquire (file=fulpath,exist=lexist) 78 | if (lexist) then 79 | if (mainproc) write(iulog,*) '(GETFIL): using ',trim(fulpath) 80 | RETURN 81 | else 82 | if (mainproc) write(iulog,*)'(GETFIL): failed getting file from full path: ', fulpath 83 | if (iflag==0) then 84 | call shr_sys_abort ('GETFIL: FAILED to get '//trim(fulpath)) 85 | else 86 | RETURN 87 | endif 88 | endif 89 | 90 | end subroutine getfil 91 | 92 | end module mosart_fileutils 93 | -------------------------------------------------------------------------------- /src/riverroute/mosart_histflds.F90: -------------------------------------------------------------------------------- 1 | module mosart_histflds 2 | 3 | ! Module containing initialization of history fields and files 4 | ! This is the module that the user must modify in order to add new 5 | ! history fields or modify defaults associated with existing history 6 | ! fields. 7 | 8 | use shr_kind_mod , only : r8 => shr_kind_r8 9 | use mosart_histfile , only : mosart_hist_addfld, mosart_hist_printflds 10 | use mosart_data , only : ctl, Trunoff 11 | 12 | implicit none 13 | private 14 | 15 | public :: mosart_histflds_init 16 | public :: mosart_histflds_set 17 | 18 | type, public :: hist_pointer_type 19 | real(r8), pointer :: data(:) => null() 20 | end type hist_pointer_type 21 | 22 | type(hist_pointer_type), allocatable :: h_runofflnd(:) 23 | type(hist_pointer_type), allocatable :: h_runoffocn(:) 24 | type(hist_pointer_type), allocatable :: h_runofftot(:) 25 | type(hist_pointer_type), allocatable :: h_direct(:) 26 | type(hist_pointer_type), allocatable :: h_direct_glc(:) 27 | type(hist_pointer_type), allocatable :: h_dvolrdtlnd(:) 28 | type(hist_pointer_type), allocatable :: h_dvolrdtocn(:) 29 | type(hist_pointer_type), allocatable :: h_volr(:) 30 | type(hist_pointer_type), allocatable :: h_qsur(:) 31 | type(hist_pointer_type), allocatable :: h_qsub(:) 32 | type(hist_pointer_type), allocatable :: h_qgwl(:) 33 | 34 | real(r8), pointer :: h_volr_mch(:) 35 | real(r8), pointer :: h_qglc_liq_input(:) 36 | real(r8), pointer :: h_qglc_ice_input(:) 37 | 38 | !------------------------------------------------------------------------ 39 | contains 40 | !----------------------------------------------------------------------- 41 | 42 | subroutine mosart_histflds_init(begr, endr, ntracers) 43 | 44 | ! Arguments 45 | integer, intent(in) :: begr 46 | integer, intent(in) :: endr 47 | integer, intent(in) :: ntracers 48 | 49 | ! Local variables 50 | integer :: nt 51 | 52 | !------------------------------------------------------- 53 | ! Allocate memory for module variables 54 | !------------------------------------------------------- 55 | 56 | allocate(h_runofflnd(ntracers)) 57 | allocate(h_runoffocn(ntracers)) 58 | allocate(h_runofftot(ntracers)) 59 | allocate(h_direct(ntracers)) 60 | allocate(h_dvolrdtlnd(ntracers)) 61 | allocate(h_dvolrdtocn(ntracers)) 62 | allocate(h_volr(ntracers)) 63 | allocate(h_qsur(ntracers)) 64 | allocate(h_qsub(ntracers)) 65 | allocate(h_qgwl(ntracers)) 66 | allocate(h_direct_glc(2)) 67 | 68 | do nt = 1,ntracers 69 | allocate(h_runofflnd(nt)%data(begr:endr)) 70 | allocate(h_runoffocn(nt)%data(begr:endr)) 71 | allocate(h_runofftot(nt)%data(begr:endr)) 72 | allocate(h_direct(nt)%data(begr:endr)) 73 | allocate(h_dvolrdtlnd(nt)%data(begr:endr)) 74 | allocate(h_dvolrdtocn(nt)%data(begr:endr)) 75 | allocate(h_volr(nt)%data(begr:endr)) 76 | allocate(h_qsur(nt)%data(begr:endr)) 77 | allocate(h_qsub(nt)%data(begr:endr)) 78 | allocate(h_qgwl(nt)%data(begr:endr)) 79 | end do 80 | allocate(h_direct_glc(ctl%nt_liq)%data(begr:endr)) 81 | allocate(h_direct_glc(ctl%nt_ice)%data(begr:endr)) 82 | 83 | allocate(h_volr_mch(begr:endr)) 84 | allocate(h_qglc_liq_input(begr:endr)) 85 | allocate(h_qglc_ice_input(begr:endr)) 86 | 87 | !------------------------------------------------------- 88 | ! Build master field list of all possible fields in a history file. 89 | ! Each field has associated with it a ``long\_name'' netcdf attribute that 90 | ! describes what the field is, and a ``units'' attribute. A subroutine is 91 | ! called to add each field to the masterlist. 92 | !------------------------------------------------------- 93 | 94 | do nt = 1,ctl%ntracers 95 | 96 | call mosart_hist_addfld (fname='RIVER_DISCHARGE_OVER_LAND'//'_'//trim(ctl%tracer_names(nt)), units='m3/s', & 97 | avgflag='A', long_name='MOSART river basin flow: '//trim(ctl%tracer_names(nt)), & 98 | ptr_rof=h_runofflnd(nt)%data, default='active') 99 | 100 | call mosart_hist_addfld (fname='RIVER_DISCHARGE_TO_OCEAN'//'_'//trim(ctl%tracer_names(nt)), units='m3/s', & 101 | avgflag='A', long_name='MOSART river discharge into ocean: '//trim(ctl%tracer_names(nt)), & 102 | ptr_rof=h_runoffocn(nt)%data, default='active') 103 | 104 | call mosart_hist_addfld (fname='TOTAL_DISCHARGE_TO_OCEAN'//'_'//trim(ctl%tracer_names(nt)), units='m3/s', & 105 | avgflag='A', long_name='MOSART total discharge into ocean: '//trim(ctl%tracer_names(nt)), & 106 | ptr_rof=h_runofftot(nt)%data, default='active') 107 | 108 | call mosart_hist_addfld (fname='DIRECT_DISCHARGE_TO_OCEAN'//'_'//trim(ctl%tracer_names(nt)), units='m3/s', & 109 | avgflag='A', long_name='MOSART direct discharge into ocean: '//trim(ctl%tracer_names(nt)), & 110 | ptr_rof=h_direct(nt)%data, default='active') 111 | 112 | call mosart_hist_addfld (fname='DIRECT_DISCHARGE_TO_OCEAN_GLC'//'_'//trim(ctl%tracer_names(nt)), units='m3/s', & 113 | avgflag='A', long_name='MOSART direct discharge into ocean from glc: '//trim(ctl%tracer_names(nt)), & 114 | ptr_rof=h_direct_glc(nt)%data, default='active') 115 | 116 | call mosart_hist_addfld (fname='STORAGE'//'_'//trim(ctl%tracer_names(nt)), units='m3', & 117 | avgflag='A', long_name='MOSART storage: '//trim(ctl%tracer_names(nt)), & 118 | ptr_rof=h_volr(nt)%data, default='inactive') 119 | 120 | call mosart_hist_addfld (fname='DVOLRDT_LND'//'_'//trim(ctl%tracer_names(nt)), units='m3/s', & 121 | avgflag='A', long_name='MOSART land change in storage: '//trim(ctl%tracer_names(nt)), & 122 | ptr_rof=h_dvolrdtlnd(nt)%data, default='inactive') 123 | 124 | call mosart_hist_addfld (fname='DVOLRDT_OCN'//'_'//trim(ctl%tracer_names(nt)), units='m3/s', & 125 | avgflag='A', long_name='MOSART ocean change of storage: '//trim(ctl%tracer_names(nt)), & 126 | ptr_rof=h_dvolrdtocn(nt)%data, default='inactive') 127 | 128 | call mosart_hist_addfld (fname='QSUR'//'_'//trim(ctl%tracer_names(nt)), units='m3/s', & 129 | avgflag='A', long_name='MOSART input surface runoff: '//trim(ctl%tracer_names(nt)), & 130 | ptr_rof=h_qsur(nt)%data, default='inactive') 131 | 132 | call mosart_hist_addfld (fname='QSUB'//'_'//trim(ctl%tracer_names(nt)), units='m3/s', & 133 | avgflag='A', long_name='MOSART input subsurface runoff: '//trim(ctl%tracer_names(nt)), & 134 | ptr_rof=h_qsub(nt)%data, default='inactive') 135 | 136 | call mosart_hist_addfld (fname='QGWL'//'_'//trim(ctl%tracer_names(nt)), units='m3/s', & 137 | avgflag='A', long_name='MOSART input GWL runoff: '//trim(ctl%tracer_names(nt)), & 138 | ptr_rof=h_qgwl(nt)%data, default='inactive') 139 | end do 140 | 141 | call mosart_hist_addfld (fname='STORAGE_MCH', units='m3', & 142 | avgflag='A', long_name='MOSART main channelstorage', & 143 | ptr_rof=h_volr_mch, default='inactive') 144 | 145 | call mosart_hist_addfld (fname='QIRRIG_FROM_COUPLER', units='m3/s', & 146 | avgflag='A', long_name='Amount of water used for irrigation (total flux received from coupler)', & 147 | ptr_rof=ctl%qirrig, default='inactive') 148 | 149 | call mosart_hist_addfld (fname='QIRRIG_ACTUAL', units='m3/s', & 150 | avgflag='A', long_name='Actual irrigation (if limited by river storage)', & 151 | ptr_rof=ctl%qirrig_actual, default='inactive') 152 | 153 | call mosart_hist_addfld (fname='QGLC_LIQ_INPUT', units='m3', & 154 | avgflag='A', long_name='liquid runoff from glc input', & 155 | ptr_rof=h_qglc_liq_input, default='active') 156 | 157 | call mosart_hist_addfld (fname='QGLC_ICE_INPUT', units='m3', & 158 | avgflag='A', long_name='ice runoff from glc input', & 159 | ptr_rof=h_qglc_ice_input, default='active') 160 | 161 | ! print masterlist of history fields 162 | call mosart_hist_printflds() 163 | 164 | end subroutine mosart_histflds_init 165 | 166 | !----------------------------------------------------------------------- 167 | 168 | subroutine mosart_histflds_set(ntracers) 169 | 170 | !----------------------------------------------------------------------- 171 | ! Set mosart history fields as 1d pointer arrays 172 | !----------------------------------------------------------------------- 173 | 174 | ! Arguments 175 | integer, intent(in) :: ntracers 176 | 177 | ! Local variables 178 | integer :: nt 179 | integer :: nt_liq, nt_ice 180 | 181 | nt_liq = ctl%nt_liq 182 | nt_ice = ctl%nt_ice 183 | 184 | do nt = 1,ntracers 185 | h_runofflnd(nt)%data(:) = ctl%runofflnd(:,nt) 186 | h_runoffocn(nt)%data(:) = ctl%runoffocn(:,nt) 187 | h_runofftot(nt)%data(:) = ctl%runofftot(:,nt) 188 | h_direct(nt)%data(:) = ctl%direct(:,nt) 189 | h_dvolrdtlnd(nt)%data(:) = ctl%dvolrdtlnd(:,nt) 190 | h_dvolrdtocn(nt)%data(:) = ctl%dvolrdtocn(:,nt) 191 | h_qsub(nt)%data(:) = ctl%qsub(:,nt) 192 | h_qsur(nt)%data(:) = ctl%qsur(:,nt) 193 | h_qgwl(nt)%data(:) = ctl%qgwl(:,nt) 194 | end do 195 | h_volr_mch(:) = Trunoff%wr(:,1) 196 | h_qglc_liq_input(:) = ctl%qglc_liq(:) 197 | h_qglc_ice_input(:) = ctl%qglc_ice(:) 198 | h_direct_glc(nt_liq)%data(:) = ctl%direct_glc(:,nt_liq) 199 | h_direct_glc(nt_ice)%data(:) = ctl%direct_glc(:,nt_ice) 200 | 201 | end subroutine mosart_histflds_set 202 | 203 | end module mosart_histflds 204 | -------------------------------------------------------------------------------- /src/riverroute/mosart_physics.F90: -------------------------------------------------------------------------------- 1 | module mosart_physics 2 | 3 | !----------------------------------------------------------------------- 4 | ! Description: core code of MOSART. 5 | ! Contains routines for solving diffusion wave and update the state of 6 | ! hillslope, subnetwork and main channel variables 7 | ! Developed by Hongyi Li, 12/29/2011. 8 | !----------------------------------------------------------------------- 9 | 10 | use shr_kind_mod , only : r8 => shr_kind_r8 11 | use shr_const_mod , only : SHR_CONST_REARTH, SHR_CONST_PI 12 | use shr_sys_mod , only : shr_sys_abort 13 | use mosart_vars , only : iulog, barrier_timers, mpicom_rof, bypass_routing_option 14 | use mosart_data , only : Tctl, TUnit, TRunoff, TPara, ctl 15 | use perf_mod , only : t_startf, t_stopf 16 | use nuopc_shr_methods , only : chkerr 17 | use ESMF , only : ESMF_FieldGet, ESMF_FieldSMM, ESMF_Finalize, & 18 | ESMF_SUCCESS, ESMF_END_ABORT, ESMF_TERMORDER_SRCSEQ 19 | 20 | implicit none 21 | private 22 | 23 | public :: Euler 24 | public :: updatestate_hillslope 25 | public :: updatestate_subnetwork 26 | public :: updatestate_mainchannel 27 | public :: hillsloperouting 28 | public :: subnetworkrouting 29 | public :: mainchannelrouting 30 | 31 | private :: Routing_KW 32 | private :: CRVRMAN_nosqrt 33 | private :: CREHT_nosqrt 34 | private :: GRMR 35 | private :: GRHT 36 | private :: GRPT 37 | private :: GRRR 38 | private :: GRPR 39 | 40 | real(r8), parameter :: TINYVALUE = 1.0e-14_r8 ! double precision variable has a significance of about 16 decimal digits 41 | real(r8), parameter :: SLOPE1def = 0.1_r8 ! here give it a small value in order to avoid the abrupt change of hydraulic radidus etc. 42 | real(r8) :: sinatanSLOPE1defr ! 1.0/sin(atan(slope1)) 43 | 44 | character(*), parameter :: u_FILE_u = & 45 | __FILE__ 46 | 47 | !----------------------------------------------------------------------- 48 | contains 49 | !----------------------------------------------------------------------- 50 | 51 | subroutine Euler(rc) 52 | 53 | ! solve the ODEs with Euler algorithm 54 | 55 | ! Arguments 56 | integer, intent(out) :: rc 57 | 58 | ! Local variables 59 | integer :: nt, nr, m, k, unitUp, cnt, ier !local index 60 | real(r8) :: temp_erout, localDeltaT 61 | real(r8) :: negchan 62 | real(r8), pointer :: src_eroutUp(:,:) 63 | real(r8), pointer :: dst_eroutUp(:,:) 64 | 65 | !------------------ 66 | ! hillslope 67 | !------------------ 68 | 69 | rc = ESMF_SUCCESS 70 | 71 | call t_startf('mosartr_hillslope') 72 | do nt=1,ctl%ntracers 73 | if (TUnit%euler_calc(nt)) then 74 | do nr=ctl%begr,ctl%endr 75 | if(TUnit%mask(nr) > 0) then 76 | call hillslopeRouting(nr,nt,Tctl%DeltaT) 77 | TRunoff%wh(nr,nt) = TRunoff%wh(nr,nt) + TRunoff%dwh(nr,nt) * Tctl%DeltaT 78 | call UpdateState_hillslope(nr,nt) 79 | TRunoff%etin(nr,nt) = (-TRunoff%ehout(nr,nt) + TRunoff%qsub(nr,nt)) * TUnit%area(nr) * TUnit%frac(nr) 80 | endif 81 | end do 82 | endif 83 | end do 84 | call t_stopf('mosartr_hillslope') 85 | 86 | call ESMF_FieldGet(Tunit%srcfield, farrayPtr=src_eroutUp, rc=rc) 87 | if (chkerr(rc,__LINE__,u_FILE_u)) return 88 | call ESMF_FieldGet(Tunit%dstfield, farrayPtr=dst_eroutUp, rc=rc) 89 | if (chkerr(rc,__LINE__,u_FILE_u)) return 90 | src_eroutUp(:,:) = 0._r8 91 | dst_eroutUp(:,:) = 0._r8 92 | 93 | TRunoff%flow = 0._r8 94 | TRunoff%erout_prev = 0._r8 95 | TRunoff%eroutup_avg = 0._r8 96 | TRunoff%erlat_avg = 0._r8 97 | negchan = 9999.0_r8 98 | 99 | do m=1,Tctl%DLevelH2R 100 | 101 | ! accumulate/average erout at prior timestep (used in eroutUp calc) for budget analysis 102 | do nt=1,ctl%ntracers 103 | if (TUnit%euler_calc(nt)) then 104 | do nr=ctl%begr,ctl%endr 105 | TRunoff%erout_prev(nr,nt) = TRunoff%erout_prev(nr,nt) + TRunoff%erout(nr,nt) 106 | end do 107 | end if 108 | end do 109 | 110 | !------------------ 111 | ! subnetwork 112 | !------------------ 113 | 114 | call t_startf('mosartr_subnetwork') 115 | TRunoff%erlateral(:,:) = 0._r8 116 | do nt=1,ctl%ntracers 117 | if (TUnit%euler_calc(nt)) then 118 | do nr=ctl%begr,ctl%endr 119 | if(TUnit%mask(nr) > 0) then 120 | localDeltaT = Tctl%DeltaT/Tctl%DLevelH2R/TUnit%numDT_t(nr) 121 | do k=1,TUnit%numDT_t(nr) 122 | call subnetworkRouting(nr,nt,localDeltaT) 123 | TRunoff%wt(nr,nt) = TRunoff%wt(nr,nt) + TRunoff%dwt(nr,nt) * localDeltaT 124 | call UpdateState_subnetwork(nr,nt) 125 | TRunoff%erlateral(nr,nt) = TRunoff%erlateral(nr,nt)-TRunoff%etout(nr,nt) 126 | end do ! numDT_t 127 | TRunoff%erlateral(nr,nt) = TRunoff%erlateral(nr,nt) / TUnit%numDT_t(nr) 128 | endif 129 | end do ! nr 130 | endif ! euler_calc 131 | end do ! nt 132 | call t_stopf('mosartr_subnetwork') 133 | 134 | !------------------ 135 | ! upstream interactions 136 | !------------------ 137 | 138 | if (barrier_timers) then 139 | call t_startf('mosartr_SMeroutUp_barrier') 140 | call mpi_barrier(mpicom_rof,ier) 141 | call t_stopf('mosartr_SMeroutUp_barrier') 142 | endif 143 | 144 | call t_startf('mosartr_SMeroutUp') 145 | 146 | !--- copy erout into src_eroutUp --- 147 | TRunoff%eroutUp = 0._r8 148 | src_eroutUp(:,:) = 0._r8 149 | cnt = 0 150 | do nr = ctl%begr,ctl%endr 151 | cnt = cnt + 1 152 | do nt = 1,ctl%ntracers 153 | src_eroutUp(nt,cnt) = TRunoff%erout(nr,nt) 154 | enddo 155 | enddo 156 | 157 | ! --- map src_eroutUp to dst_eroutUp 158 | call ESMF_FieldSMM(TUnit%srcfield, TUnit%dstField, TUnit%rh_eroutUp, termorderflag=ESMF_TERMORDER_SRCSEQ, rc=rc) 159 | if (chkerr(rc,__LINE__,u_FILE_u)) return 160 | 161 | !--- copy mapped eroutUp to TRunoff --- 162 | cnt = 0 163 | do nr = ctl%begr,ctl%endr 164 | cnt = cnt + 1 165 | do nt = 1,ctl%ntracers 166 | TRunoff%eroutUp(nr,nt) = dst_eroutUp(nt,cnt) 167 | enddo 168 | enddo 169 | 170 | call t_stopf('mosartr_SMeroutUp') 171 | 172 | TRunoff%eroutup_avg = TRunoff%eroutup_avg + TRunoff%eroutUp 173 | TRunoff%erlat_avg = TRunoff%erlat_avg + TRunoff%erlateral 174 | 175 | !------------------ 176 | ! channel routing 177 | !------------------ 178 | 179 | call t_startf('mosartr_chanroute') 180 | do nt=1,ctl%ntracers 181 | if (TUnit%euler_calc(nt)) then 182 | do nr=ctl%begr,ctl%endr 183 | if(TUnit%mask(nr) > 0) then 184 | localDeltaT = Tctl%DeltaT/Tctl%DLevelH2R/TUnit%numDT_r(nr) 185 | temp_erout = 0._r8 186 | do k=1,TUnit%numDT_r(nr) 187 | ! TODO: is it positive (TRunoff%wr) and negative afterwards 188 | call mainchannelRouting(nr,nt,localDeltaT) 189 | TRunoff%wr(nr,nt) = TRunoff%wr(nr,nt) + TRunoff%dwr(nr,nt) * localDeltaT 190 | ! check for negative channel storage 191 | ! if(TRunoff%wr(nr,1) < -1.e-10) then 192 | ! write(iulog,*) 'Negative channel storage! ', nr, TRunoff%wr(nr,1) 193 | ! call shr_sys_abort('mosart: negative channel storage') 194 | ! end if 195 | call UpdateState_mainchannel(nr,nt) 196 | ! erout here might be inflow to some downstream subbasin, so treat it differently than erlateral 197 | temp_erout = temp_erout + TRunoff%erout(nr,nt) 198 | end do 199 | temp_erout = temp_erout / TUnit%numDT_r(nr) 200 | TRunoff%erout(nr,nt) = temp_erout 201 | TRunoff%flow(nr,nt) = TRunoff%flow(nr,nt) - TRunoff%erout(nr,nt) 202 | endif 203 | end do ! nr 204 | endif ! euler_calc 205 | end do ! nt 206 | negchan = min(negchan, minval(TRunoff%wr(:,:))) 207 | 208 | call t_stopf('mosartr_chanroute') 209 | end do 210 | 211 | ! check for negative channel storage 212 | if (negchan < -1.e-10) then 213 | write(iulog,*) 'Warning: Negative channel storage found! ',negchan 214 | ! call shr_sys_abort('mosart: negative channel storage') 215 | endif 216 | TRunoff%flow = TRunoff%flow / Tctl%DLevelH2R 217 | TRunoff%erout_prev = TRunoff%erout_prev / Tctl%DLevelH2R 218 | TRunoff%eroutup_avg = TRunoff%eroutup_avg / Tctl%DLevelH2R 219 | TRunoff%erlat_avg = TRunoff%erlat_avg / Tctl%DLevelH2R 220 | 221 | end subroutine Euler 222 | 223 | !----------------------------------------------------------------------- 224 | 225 | subroutine hillslopeRouting(nr, nt, theDeltaT) 226 | ! Hillslope routing considering uniform runoff generation across hillslope 227 | 228 | ! Arguments 229 | integer, intent(in) :: nr, nt 230 | real(r8), intent(in) :: theDeltaT 231 | 232 | TRunoff%ehout(nr,nt) = -CREHT_nosqrt(TUnit%hslpsqrt(nr), TUnit%nh(nr), TUnit%Gxr(nr), TRunoff%yh(nr,nt)) 233 | if(TRunoff%ehout(nr,nt) < 0._r8 .and. & 234 | TRunoff%wh(nr,nt) + (TRunoff%qsur(nr,nt) + TRunoff%ehout(nr,nt)) * theDeltaT < TINYVALUE) then 235 | TRunoff%ehout(nr,nt) = -(TRunoff%qsur(nr,nt) + TRunoff%wh(nr,nt) / theDeltaT) 236 | end if 237 | TRunoff%dwh(nr,nt) = (TRunoff%qsur(nr,nt) + TRunoff%ehout(nr,nt)) 238 | 239 | end subroutine hillslopeRouting 240 | 241 | !----------------------------------------------------------------------- 242 | 243 | subroutine subnetworkRouting(nr,nt,theDeltaT) 244 | ! subnetwork channel routing 245 | 246 | ! Arguments 247 | integer, intent(in) :: nr,nt 248 | real(r8), intent(in) :: theDeltaT 249 | 250 | if(TUnit%tlen(nr) <= TUnit%hlen(nr)) then ! if no tributaries, not subnetwork channel routing 251 | TRunoff%etout(nr,nt) = -TRunoff%etin(nr,nt) 252 | else 253 | TRunoff%vt(nr,nt) = CRVRMAN_nosqrt(TUnit%tslpsqrt(nr), TUnit%nt(nr), TRunoff%rt(nr,nt)) 254 | TRunoff%etout(nr,nt) = -TRunoff%vt(nr,nt) * TRunoff%mt(nr,nt) 255 | if(TRunoff%wt(nr,nt) + (TRunoff%etin(nr,nt) + TRunoff%etout(nr,nt)) * theDeltaT < TINYVALUE) then 256 | TRunoff%etout(nr,nt) = -(TRunoff%etin(nr,nt) + TRunoff%wt(nr,nt)/theDeltaT) 257 | if(TRunoff%mt(nr,nt) > 0._r8) then 258 | TRunoff%vt(nr,nt) = -TRunoff%etout(nr,nt)/TRunoff%mt(nr,nt) 259 | end if 260 | end if 261 | end if 262 | TRunoff%dwt(nr,nt) = TRunoff%etin(nr,nt) + TRunoff%etout(nr,nt) 263 | 264 | ! check stability 265 | ! if(TRunoff%vt(nr,nt) < -TINYVALUE .or. TRunoff%vt(nr,nt) > 30) then 266 | ! write(iulog,*) "Numerical error in subnetworkRouting, ", nr,nt,TRunoff%vt(nr,nt) 267 | ! end if 268 | 269 | end subroutine subnetworkRouting 270 | 271 | !----------------------------------------------------------------------- 272 | 273 | subroutine mainchannelRouting(nr, nt, theDeltaT) 274 | ! main channel routing 275 | 276 | ! Arguments 277 | integer, intent(in) :: nr, nt 278 | real(r8), intent(in) :: theDeltaT 279 | 280 | if(Tctl%RoutingMethod == 1) then 281 | call Routing_KW(nr, nt, theDeltaT) 282 | else 283 | call shr_sys_abort( "mosart: Please check the routing method! There is only 1 method currently available." ) 284 | end if 285 | 286 | end subroutine mainchannelRouting 287 | 288 | !----------------------------------------------------------------------- 289 | 290 | subroutine Routing_KW(nr, nt, theDeltaT) 291 | ! classic kinematic wave routing method 292 | 293 | ! Arguments 294 | integer, intent(in) :: nr, nt 295 | real(r8), intent(in) :: theDeltaT 296 | 297 | ! Local variables 298 | integer :: k 299 | real(r8) :: temp_gwl, temp_dwr, temp_gwl0 300 | 301 | ! estimate the inflow from upstream units 302 | TRunoff%erin(nr,nt) = 0._r8 303 | TRunoff%erin(nr,nt) = TRunoff%erin(nr,nt) - TRunoff%eroutUp(nr,nt) 304 | 305 | ! estimate the outflow 306 | if(TUnit%rlen(nr) <= 0._r8) then ! no river network, no channel routing 307 | TRunoff%vr(nr,nt) = 0._r8 308 | TRunoff%erout(nr,nt) = -TRunoff%erin(nr,nt)-TRunoff%erlateral(nr,nt) 309 | else 310 | if(TUnit%areaTotal2(nr)/TUnit%rwidth(nr)/TUnit%rlen(nr) > 1e6_r8) then 311 | TRunoff%erout(nr,nt) = -TRunoff%erin(nr,nt)-TRunoff%erlateral(nr,nt) 312 | else 313 | TRunoff%vr(nr,nt) = CRVRMAN_nosqrt(TUnit%rslpsqrt(nr), TUnit%nr(nr), TRunoff%rr(nr,nt)) 314 | TRunoff%erout(nr,nt) = -TRunoff%vr(nr,nt) * TRunoff%mr(nr,nt) 315 | if(-TRunoff%erout(nr,nt) > TINYVALUE .and. TRunoff%wr(nr,nt) + & 316 | (TRunoff%erlateral(nr,nt) + TRunoff%erin(nr,nt) + TRunoff%erout(nr,nt)) * theDeltaT < TINYVALUE) then 317 | TRunoff%erout(nr,nt) = -(TRunoff%erlateral(nr,nt) + TRunoff%erin(nr,nt) + TRunoff%wr(nr,nt) / theDeltaT) 318 | if(TRunoff%mr(nr,nt) > 0._r8) then 319 | TRunoff%vr(nr,nt) = -TRunoff%erout(nr,nt) / TRunoff%mr(nr,nt) 320 | end if 321 | end if 322 | end if 323 | end if 324 | 325 | temp_gwl = TRunoff%qgwl(nr,nt) * TUnit%area(nr) * TUnit%frac(nr) 326 | 327 | TRunoff%dwr(nr,nt) = TRunoff%erlateral(nr,nt) + TRunoff%erin(nr,nt) + TRunoff%erout(nr,nt) + temp_gwl 328 | 329 | if ((TRunoff%wr(nr,nt)/theDeltaT + TRunoff%dwr(nr,nt)) < -TINYVALUE .and. (trim(bypass_routing_option)/='none') ) then 330 | write(iulog,*) 'mosart: ERROR main channel going negative: ', nr, nt 331 | write(iulog,*) theDeltaT, TRunoff%wr(nr,nt), & 332 | TRunoff%wr(nr,nt)/theDeltaT, TRunoff%dwr(nr,nt), temp_gwl 333 | write(iulog,*) ' ' 334 | endif 335 | 336 | ! check for stability 337 | ! if(TRunoff%vr(nr,nt) < -TINYVALUE .or. TRunoff%vr(nr,nt) > 30) then 338 | ! write(iulog,*) "Numerical error inRouting_KW, ", nr,nt,TRunoff%vr(nr,nt) 339 | ! end if 340 | 341 | ! check for negative wr 342 | ! if(TRunoff%wr(nr,nt) > 1._r8 .and. & 343 | ! (TRunoff%wr(nr,nt)/theDeltaT + TRunoff%dwr(nr,nt))/TRunoff%wr(nr,nt) < -TINYVALUE) then 344 | ! write(iulog,*) 'negative wr!', TRunoff%wr(nr,nt), TRunoff%dwr(nr,nt), temp_dwr, temp_gwl, temp_gwl0, theDeltaT 345 | ! stop 346 | ! end if 347 | 348 | end subroutine Routing_KW 349 | 350 | !----------------------------------------------------------------------- 351 | 352 | subroutine updateState_hillslope(nr,nt) 353 | ! update the state variables at hillslope 354 | 355 | ! Arguments 356 | integer, intent(in) :: nr, nt 357 | 358 | TRunoff%yh(nr,nt) = TRunoff%wh(nr,nt) !/ TUnit%area(nr) / TUnit%frac(nr) 359 | 360 | end subroutine updateState_hillslope 361 | 362 | !----------------------------------------------------------------------- 363 | 364 | subroutine updateState_subnetwork(nr,nt) 365 | ! update the state variables in subnetwork channel 366 | 367 | ! Arguments 368 | integer, intent(in) :: nr,nt 369 | 370 | if(TUnit%tlen(nr) > 0._r8 .and. TRunoff%wt(nr,nt) > 0._r8) then 371 | TRunoff%mt(nr,nt) = GRMR(TRunoff%wt(nr,nt), TUnit%tlen(nr)) 372 | TRunoff%yt(nr,nt) = GRHT(TRunoff%mt(nr,nt), TUnit%twidth(nr)) 373 | TRunoff%pt(nr,nt) = GRPT(TRunoff%yt(nr,nt), TUnit%twidth(nr)) 374 | TRunoff%rt(nr,nt) = GRRR(TRunoff%mt(nr,nt), TRunoff%pt(nr,nt)) 375 | else 376 | TRunoff%mt(nr,nt) = 0._r8 377 | TRunoff%yt(nr,nt) = 0._r8 378 | TRunoff%pt(nr,nt) = 0._r8 379 | TRunoff%rt(nr,nt) = 0._r8 380 | end if 381 | end subroutine updateState_subnetwork 382 | 383 | !----------------------------------------------------------------------- 384 | 385 | subroutine updateState_mainchannel(nr, nt) 386 | ! update the state variables in main channel 387 | 388 | ! Arguments 389 | integer, intent(in) :: nr, nt 390 | 391 | if(TUnit%rlen(nr) > 0._r8 .and. TRunoff%wr(nr,nt) > 0._r8) then 392 | TRunoff%mr(nr,nt) = GRMR(TRunoff%wr(nr,nt), TUnit%rlen(nr)) 393 | TRunoff%yr(nr,nt) = GRHR(TRunoff%mr(nr,nt), TUnit%rwidth(nr), TUnit%rwidth0(nr), TUnit%rdepth(nr)) 394 | TRunoff%pr(nr,nt) = GRPR(TRunoff%yr(nr,nt), TUnit%rwidth(nr), TUnit%rwidth0(nr), TUnit%rdepth(nr)) 395 | TRunoff%rr(nr,nt) = GRRR(TRunoff%mr(nr,nt), TRunoff%pr(nr,nt)) 396 | else 397 | TRunoff%mr(nr,nt) = 0._r8 398 | TRunoff%yr(nr,nt) = 0._r8 399 | TRunoff%pr(nr,nt) = 0._r8 400 | TRunoff%rr(nr,nt) = 0._r8 401 | end if 402 | end subroutine updateState_mainchannel 403 | 404 | !----------------------------------------------------------------------- 405 | 406 | function CRVRMAN_nosqrt(sqrtslp_, n_, rr_) result(v_) 407 | ! Function for calculating channel velocity according to Manning's equation. 408 | 409 | ! Arguments 410 | real(r8), intent(in) :: sqrtslp_, n_, rr_ ! sqrt(slope), manning's roughness coeff., hydraulic radius 411 | real(r8) :: v_ ! v_ is discharge 412 | 413 | ! Local varaibles 414 | real(r8) :: ftemp, vtemp 415 | 416 | if(rr_ <= 0._r8) then 417 | v_ = 0._r8 418 | else 419 | v_ = ((rr_*rr_)**(1._r8/3._r8)) * sqrtslp_ / n_ 420 | end if 421 | 422 | end function CRVRMAN_nosqrt 423 | 424 | !----------------------------------------------------------------------- 425 | 426 | function CREHT_nosqrt(sqrthslp_, nh_, Gxr_, yh_) result(eht_) 427 | ! Function for overland from hillslope into the sub-network channels 428 | 429 | ! Arguments 430 | real(r8), intent(in) :: sqrthslp_, nh_, Gxr_, yh_ ! topographic slope, manning's roughness coeff., drainage density, overland flow depth 431 | real(r8) :: eht_ ! velocity, specific discharge 432 | 433 | real(r8) :: vh_ 434 | vh_ = CRVRMAN_nosqrt(sqrthslp_,nh_,yh_) 435 | eht_ = Gxr_*yh_*vh_ 436 | 437 | end function CREHT_nosqrt 438 | 439 | !----------------------------------------------------------------------- 440 | 441 | function GRMR(wr_, rlen_) result(mr_) 442 | ! Function for estimate wetted channel area 443 | 444 | ! Arguments 445 | real(r8), intent(in) :: wr_, rlen_ ! storage of water, channel length 446 | real(r8) :: mr_ ! wetted channel area 447 | 448 | mr_ = wr_ / rlen_ 449 | end function GRMR 450 | 451 | !----------------------------------------------------------------------- 452 | 453 | function GRHT(mt_, twid_) result(ht_) 454 | ! Function for estimating water depth assuming rectangular channel 455 | 456 | ! Arguments 457 | real(r8), intent(in) :: mt_, twid_ ! wetted channel area, channel width 458 | real(r8) :: ht_ ! water depth 459 | 460 | if(mt_ <= TINYVALUE) then 461 | ht_ = 0._r8 462 | else 463 | ht_ = mt_ / twid_ 464 | end if 465 | end function GRHT 466 | 467 | !----------------------------------------------------------------------- 468 | 469 | function GRPT(ht_, twid_) result(pt_) 470 | ! Function for estimating wetted perimeter assuming rectangular channel 471 | 472 | ! Arguments 473 | real(r8), intent(in) :: ht_, twid_ ! water depth, channel width 474 | real(r8) :: pt_ ! wetted perimeter 475 | 476 | if(ht_ <= TINYVALUE) then 477 | pt_ = 0._r8 478 | else 479 | pt_ = twid_ + 2._r8 * ht_ 480 | end if 481 | end function GRPT 482 | 483 | !----------------------------------------------------------------------- 484 | 485 | function GRRR(mr_, pr_) result(rr_) 486 | ! Function for estimating hydraulic radius 487 | 488 | ! Arguments 489 | real(r8), intent(in) :: mr_, pr_ ! wetted area and perimeter 490 | real(r8) :: rr_ ! hydraulic radius 491 | 492 | if(pr_ <= TINYVALUE) then 493 | rr_ = 0._r8 494 | else 495 | rr_ = mr_ / pr_ 496 | end if 497 | end function GRRR 498 | 499 | !----------------------------------------------------------------------- 500 | 501 | function GRHR(mr_, rwidth_, rwidth0_, rdepth_) result(hr_) 502 | ! Function for estimating maximum water depth assuming rectangular channel and tropezoidal flood plain 503 | ! here assuming the channel cross-section consists of three parts, from bottom to up, 504 | ! part 1 is a rectangular with bankfull depth (rdep) and bankfull width (rwid) 505 | ! part 2 is a tropezoidal, bottom width rwid and top width rwid0, height 0.1*((rwid0-rwid)/2), assuming slope is 0.1 506 | ! part 3 is a rectagular with the width rwid0 507 | 508 | ! Arguments 509 | real(r8), intent(in) :: mr_, rwidth_, rwidth0_, rdepth_ ! wetted channel area, channel width, flood plain wid, water depth 510 | real(r8) :: hr_ ! water depth 511 | 512 | ! Local variables 513 | real(r8) :: SLOPE1 ! slope of flood plain, TO DO 514 | real(r8) :: deltamr_ 515 | 516 | SLOPE1 = SLOPE1def 517 | if(mr_ <= TINYVALUE) then 518 | hr_ = 0._r8 519 | else 520 | if(mr_ - rdepth_*rwidth_ <= TINYVALUE) then ! not flooded 521 | hr_ = mr_/rwidth_ 522 | else ! if flooded, the find out the equivalent depth 523 | if(mr_ > rdepth_*rwidth_ + (rwidth_ + rwidth0_)*SLOPE1*((rwidth0_-rwidth_)/2._r8)/2._r8 + TINYVALUE) then 524 | deltamr_ = mr_ - rdepth_*rwidth_ - (rwidth_ + rwidth0_)*SLOPE1*((rwidth0_ - rwidth_)/2._r8)/2._r8; 525 | hr_ = rdepth_ + SLOPE1*((rwidth0_ - rwidth_)/2._r8) + deltamr_/(rwidth0_); 526 | else 527 | deltamr_ = mr_ - rdepth_*rwidth_; 528 | hr_ = rdepth_ + (-rwidth_+sqrt((rwidth_*rwidth_)+4._r8*deltamr_/SLOPE1))*SLOPE1/2._r8 529 | end if 530 | end if 531 | end if 532 | end function GRHR 533 | 534 | !----------------------------------------------------------------------- 535 | 536 | function GRPR(hr_, rwidth_, rwidth0_,rdepth_) result(pr_) 537 | ! Function for estimating maximum water depth assuming rectangular channel and tropezoidal flood plain 538 | ! here assuming the channel cross-section consists of three parts, from bottom to up, 539 | ! part 1 is a rectangular with bankfull depth (rdep) and bankfull width (rwid) 540 | ! part 2 is a tropezoidal, bottom width rwid and top width rwid0, height 0.1*((rwid0-rwid)/2), assuming slope is 0.1 541 | ! part 3 is a rectagular with the width rwid0 542 | 543 | ! Arguments 544 | real(r8), intent(in) :: hr_, rwidth_, rwidth0_, rdepth_ ! wwater depth, channel width, flood plain wid, water depth 545 | real(r8) :: pr_ ! water depth 546 | 547 | ! Local variables 548 | real(r8) :: SLOPE1 ! slope of flood plain, TO DO 549 | real(r8) :: deltahr_ 550 | logical, save :: first_call = .true. 551 | 552 | SLOPE1 = SLOPE1def 553 | if (first_call) then 554 | sinatanSLOPE1defr = 1.0_r8/(sin(atan(SLOPE1def))) 555 | endif 556 | first_call = .false. 557 | 558 | if(hr_ < TINYVALUE) then 559 | pr_ = 0._r8 560 | else 561 | if(hr_ <= rdepth_ + TINYVALUE) then ! not flooded 562 | pr_ = rwidth_ + 2._r8*hr_ 563 | else 564 | if(hr_ > rdepth_ + ((rwidth0_-rwidth_)/2._r8)*SLOPE1 + TINYVALUE) then 565 | deltahr_ = hr_ - rdepth_ - ((rwidth0_-rwidth_)/2._r8)*SLOPE1 566 | pr_ = rwidth_ + 2._r8*(rdepth_ + ((rwidth0_-rwidth_)/2._r8)*SLOPE1*sinatanSLOPE1defr + deltahr_) 567 | else 568 | pr_ = rwidth_ + 2._r8*(rdepth_ + (hr_ - rdepth_)*sinatanSLOPE1defr) 569 | end if 570 | end if 571 | end if 572 | end function GRPR 573 | 574 | end module mosart_physics 575 | -------------------------------------------------------------------------------- /src/riverroute/mosart_restfile.F90: -------------------------------------------------------------------------------- 1 | module mosart_restfile 2 | 3 | ! Read from and write to the MOSART restart file. 4 | 5 | use shr_kind_mod, only : r8 => shr_kind_r8, CL => shr_kind_cl, CS => shr_kind_cs 6 | use shr_sys_mod, only : shr_sys_abort 7 | use mosart_vars, only : iulog, inst_suffix, caseid, nsrest, & 8 | spval, mainproc, nsrContinue, nsrBranch, nsrStartup, & 9 | ctitle, version, username, hostname, conventions, source 10 | use mosart_data, only : ctl, Trunoff 11 | use mosart_histfile, only : mosart_hist_restart 12 | use mosart_fileutils, only : getfil 13 | use mosart_timemanager, only : timemgr_restart, get_nstep, get_curr_date, get_prev_date 14 | use mosart_io, only : ncd_pio_createfile, ncd_enddef, ncd_pio_openfile, ncd_pio_closefile, & 15 | ncd_defdim, ncd_putatt, ncd_defvar, ncd_io, ncd_global, ncd_double, & 16 | ncd_getdatetime 17 | use pio, only : file_desc_t 18 | 19 | implicit none 20 | private 21 | 22 | ! public member functions: 23 | public :: mosart_rest_FileName 24 | public :: mosart_rest_FileRead 25 | public :: mosart_rest_FileWrite 26 | public :: mosart_rest_Getfile 27 | public :: mosart_rest_TimeManager 28 | public :: mosart_rest_restart 29 | ! 30 | ! private member functions: 31 | private :: restFile_read_pfile 32 | private :: restFile_write_pfile ! Writes restart pointer file 33 | private :: restFile_dimset 34 | 35 | ! true => allow case name to remain the same for branch run 36 | ! by default this is not allowed 37 | logical, public :: brnch_retain_casename = .false. 38 | 39 | ! file name for local restart pointer file 40 | character(len=CL) :: rpntfil = 'rpointer.rof' 41 | 42 | ! initial conditions file name 43 | character(len=CL), public :: finidat 44 | 45 | ! restart data file name for branch run 46 | character(len=CL), public :: nrevsn 47 | 48 | !----------------------------------------------------------------------- 49 | contains 50 | !----------------------------------------------------------------------- 51 | 52 | subroutine mosart_rest_FileWrite( file, rdate ) 53 | 54 | !------------------------------------- 55 | ! Read/write MOSART restart file. 56 | 57 | ! Arguments: 58 | character(len=*) , intent(in) :: file ! output netcdf restart file 59 | character(len=*) , intent(in) :: rdate ! restart file time stamp for name 60 | 61 | ! Local variables 62 | type(file_desc_t) :: ncid ! netcdf id 63 | integer :: i ! index 64 | logical :: ptrfile ! write out the restart pointer file 65 | !------------------------------------- 66 | 67 | ! Define dimensions and variables 68 | 69 | if (mainproc) then 70 | write(iulog,*) 71 | write(iulog,*)'restFile_open: writing MOSART restart dataset ' 72 | write(iulog,*) 73 | end if 74 | call ncd_pio_createfile(ncid, trim(file)) 75 | call restFile_dimset( ncid ) 76 | call mosart_rest_restart ( ncid, flag='define' ) 77 | call mosart_hist_restart ( ncid, flag='define', rdate=rdate ) 78 | call timemgr_restart( ncid, flag='define' ) 79 | call ncd_enddef(ncid) 80 | 81 | ! Write restart file variables 82 | call mosart_rest_restart( ncid, flag='write' ) 83 | call mosart_hist_restart ( ncid, flag='write' ) 84 | call timemgr_restart( ncid, flag='write' ) 85 | call ncd_pio_closefile(ncid) 86 | 87 | if (mainproc) then 88 | write(iulog,*) 'Successfully wrote local restart file ',trim(file) 89 | write(iulog,'(72a1)') ("-",i=1,60) 90 | write(iulog,*) 91 | end if 92 | 93 | ! Write restart pointer file 94 | call restFile_write_pfile( file ) 95 | 96 | ! Write out diagnostic info 97 | 98 | if (mainproc) then 99 | write(iulog,*) 'Successfully wrote out restart data at nstep = ',get_nstep() 100 | write(iulog,'(72a1)') ("-",i=1,60) 101 | end if 102 | 103 | end subroutine mosart_rest_FileWrite 104 | 105 | !----------------------------------------------------------------------- 106 | 107 | subroutine mosart_rest_FileRead( file ) 108 | 109 | !------------------------------------- 110 | ! Read a MOSART restart file. 111 | ! 112 | ! Arguments 113 | character(len=*), intent(in) :: file ! output netcdf restart file 114 | ! 115 | ! Local variables 116 | type(file_desc_t) :: ncid ! netcdf id 117 | integer :: i ! index 118 | !------------------------------------- 119 | 120 | ! Read file 121 | if (mainproc) write(iulog,*) 'Reading restart dataset' 122 | call ncd_pio_openfile (ncid, trim(file), 0) 123 | call mosart_rest_restart(ncid, flag='read') 124 | call mosart_hist_restart(ncid, flag='read') 125 | call ncd_pio_closefile(ncid) 126 | 127 | ! Write out diagnostic info 128 | if (mainproc) then 129 | write(iulog,'(72a1)') ("-",i=1,60) 130 | write(iulog,*) 'Successfully read restart data for restart run' 131 | write(iulog,*) 132 | end if 133 | 134 | end subroutine mosart_rest_FileRead 135 | 136 | !----------------------------------------------------------------------- 137 | 138 | subroutine mosart_rest_TimeManager( file ) 139 | 140 | !------------------------------------- 141 | ! Read a MOSART restart file. 142 | ! 143 | ! Arguments 144 | character(len=*), intent(in) :: file ! output netcdf restart file 145 | ! 146 | ! Local Variables: 147 | type(file_desc_t) :: ncid ! netcdf id 148 | integer :: i ! index 149 | !------------------------------------- 150 | 151 | ! Read file 152 | if (mainproc) write(iulog,*) 'Reading restart Timemanger' 153 | call ncd_pio_openfile (ncid, trim(file), 0) 154 | call timemgr_restart(ncid, flag='read') 155 | call ncd_pio_closefile(ncid) 156 | 157 | ! Write out diagnostic info 158 | if (mainproc) then 159 | write(iulog,'(72a1)') ("-",i=1,60) 160 | write(iulog,*) 'Successfully read restart data for restart run' 161 | write(iulog,*) 162 | end if 163 | 164 | end subroutine mosart_rest_TimeManager 165 | 166 | !----------------------------------------------------------------------- 167 | 168 | subroutine mosart_rest_Getfile( file ) 169 | 170 | !------------------------------------- 171 | ! Determine and obtain netcdf restart file 172 | 173 | ! Arguments: 174 | character(len=*), intent(out) :: file ! name of netcdf restart file 175 | 176 | ! Local variables: 177 | integer :: status ! return status 178 | integer :: length ! temporary 179 | character(len=CL) :: ftest,ctest ! temporaries 180 | character(len=CL) :: path ! full pathname of netcdf restart file 181 | !------------------------------------- 182 | 183 | ! Continue run: 184 | ! Restart file pathname is read restart pointer file 185 | if (nsrest==nsrContinue) then 186 | call restFile_read_pfile( path ) 187 | call getfil( path, file, 0 ) 188 | end if 189 | 190 | ! Branch run: 191 | ! Restart file pathname is obtained from namelist "nrevsn" 192 | if (nsrest==nsrBranch) then 193 | length = len_trim(nrevsn) 194 | if (nrevsn(length-2:length) == '.nc') then 195 | path = trim(nrevsn) 196 | else 197 | path = trim(nrevsn) // '.nc' 198 | end if 199 | call getfil( path, file, 0 ) 200 | 201 | ! Check case name consistency (case name must be different 202 | ! for branch run, unless brnch_retain_casename is set) 203 | ctest = 'xx.'//trim(caseid)//'.mosart' 204 | ftest = 'xx.'//trim(file) 205 | status = index(trim(ftest),trim(ctest)) 206 | if (status /= 0 .and. .not.(brnch_retain_casename)) then 207 | write(iulog,*) 'Must change case name on branch run if ',& 208 | 'brnch_retain_casename namelist is not set' 209 | write(iulog,*) 'previous case filename= ',trim(file),& 210 | ' current case = ',trim(caseid), ' ctest = ',trim(ctest), & 211 | ' ftest = ',trim(ftest) 212 | call shr_sys_abort() 213 | end if 214 | end if 215 | 216 | ! Initial run 217 | if (nsrest==nsrStartup) then 218 | call getfil( finidat, file, 0 ) 219 | end if 220 | 221 | end subroutine mosart_rest_Getfile 222 | 223 | !----------------------------------------------------------------------- 224 | 225 | subroutine restFile_read_pfile( pnamer ) 226 | use mpi, only : MPI_CHARACTER 227 | use mosart_vars, only : mpicom_rof 228 | !------------------------------------- 229 | ! Setup restart file and perform necessary consistency checks 230 | 231 | ! Arguments 232 | character(len=*), intent(out) :: pnamer ! full path of restart file 233 | 234 | ! Local variables 235 | integer :: nio ! restart unit 236 | integer :: ier ! error return from fortran open 237 | integer :: i ! index 238 | integer :: yr, mon, day, tod 239 | character(len=17) :: timestamp 240 | character(len=CL) :: locfn ! Restart pointer file name 241 | !------------------------------------- 242 | 243 | ! Obtain the restart file from the restart pointer file. 244 | ! For restart runs, the restart pointer file contains the full pathname 245 | ! of the restart file. For branch runs, the namelist variable 246 | ! [nrevsn] contains the full pathname of the restart file. 247 | ! New history files are always created for branch runs. 248 | 249 | if (mainproc) then 250 | call get_curr_date(yr, mon, day, tod) 251 | write(timestamp,'(".",i4.4,"-",i2.2,"-",i2.2,"-",i5.5)') yr,mon,day,tod 252 | locfn = './'// trim(rpntfil)//trim(inst_suffix)//timestamp 253 | 254 | write(iulog,*) 'Reading restart pointer file: '//trim(locfn) 255 | open (newunit=nio, file=trim(locfn), status='old', form='formatted', iostat=ier) 256 | if (ier /= 0) then 257 | locfn = './'// trim(rpntfil)//trim(inst_suffix) 258 | open (newunit=nio, file=trim(locfn), status='old', form='formatted', iostat=ier) 259 | if (ier /= 0) then 260 | write(iulog,'(a,i8)')'(restFile_read_pfile): failed to open file '//trim(locfn)//' ierr=',ier 261 | call shr_sys_abort() 262 | end if 263 | endif 264 | read (nio,'(a256)') pnamer 265 | close(nio) 266 | endif 267 | call mpi_bcast (pnamer, CL, MPI_CHARACTER, 0, mpicom_rof, ier) 268 | if(mainproc) then 269 | write(iulog,'(a)') 'Reading restart data: ',trim(pnamer) 270 | write(iulog,'(72a1)') ("-",i=1,60) 271 | end if 272 | 273 | end subroutine restFile_read_pfile 274 | 275 | !----------------------------------------------------------------------- 276 | 277 | subroutine restFile_write_pfile( fnamer ) 278 | 279 | !------------------------------------- 280 | ! Open restart pointer file. Write names of current netcdf restart file. 281 | ! 282 | ! Arguments 283 | character(len=*), intent(in) :: fnamer 284 | ! 285 | ! Local variables 286 | integer :: nio ! restart pointer file unit number 287 | integer :: ier ! error return from fortran open 288 | character(len=CL) :: filename ! local file name 289 | integer :: yr, mon, day, tod 290 | character(len=17) :: timestamp 291 | !------------------------------------- 292 | 293 | if (mainproc) then 294 | call get_curr_date(yr, mon, day, tod) 295 | write(timestamp,'(".",i4.4,"-",i2.2,"-",i2.2,"-",i5.5)') yr, mon, day, tod 296 | filename= './'// trim(rpntfil)//trim(inst_suffix)//timestamp 297 | open (newunit=nio, file=trim(filename), status='unknown', form='formatted', iostat=ier) 298 | if (ier /= 0) then 299 | write(iulog,'(a,i8)')'(restFile_write_pfile): failed to open file '//trim(filename)//' ierr=',ier 300 | call shr_sys_abort() 301 | end if 302 | write(nio,'(a)') fnamer 303 | close(nio) 304 | write(iulog,*)'Successfully wrote local restart pointer file: '//trim(filename) 305 | end if 306 | 307 | end subroutine restFile_write_pfile 308 | 309 | !----------------------------------------------------------------------- 310 | 311 | character(len=CL) function mosart_rest_FileName( rdate ) 312 | 313 | ! Arguments 314 | character(len=*), intent(in) :: rdate ! input date for restart file name 315 | 316 | mosart_rest_FileName = "./"//trim(caseid)//".mosart"//trim(inst_suffix)//".r."//trim(rdate)//".nc" 317 | if (mainproc) then 318 | write(iulog,*)'writing restart file ',trim(mosart_rest_FileName),' for model date = ',rdate 319 | end if 320 | 321 | end function mosart_rest_FileName 322 | 323 | !------------------------------------------------------------------------ 324 | 325 | subroutine restFile_dimset( ncid ) 326 | 327 | !------------------------------------- 328 | ! Read/Write initial data from/to netCDF instantaneous initial data file 329 | 330 | ! Arguments 331 | type(file_desc_t), intent(inout) :: ncid 332 | 333 | ! Local Variables: 334 | integer :: dimid ! netCDF dimension id 335 | integer :: ier ! error status 336 | character(len= 8) :: curdate ! current date 337 | character(len= 8) :: curtime ! current time 338 | character(len=CL) :: str 339 | character(len=*),parameter :: subname='restFile_dimset' 340 | !------------------------------------- 341 | 342 | ! Define dimensions 343 | 344 | call ncd_defdim(ncid, 'nlon' , ctl%nlon , dimid) 345 | call ncd_defdim(ncid, 'nlat' , ctl%nlat , dimid) 346 | call ncd_defdim(ncid, 'string_length', CS , dimid) 347 | 348 | ! Define global attributes 349 | 350 | call ncd_putatt(ncid, NCD_GLOBAL, 'Conventions', trim(conventions)) 351 | call ncd_getdatetime(curdate, curtime) 352 | str = 'created on ' // curdate // ' ' // curtime 353 | call ncd_putatt(ncid, NCD_GLOBAL, 'history' , trim(str)) 354 | call ncd_putatt(ncid, NCD_GLOBAL, 'username', trim(username)) 355 | call ncd_putatt(ncid, NCD_GLOBAL, 'host' , trim(hostname)) 356 | call ncd_putatt(ncid, NCD_GLOBAL, 'version' , trim(version)) 357 | call ncd_putatt(ncid, NCD_GLOBAL, 'source' , trim(source)) 358 | call ncd_putatt(ncid, NCD_GLOBAL, 'case_title' , trim(ctitle)) 359 | call ncd_putatt(ncid, NCD_GLOBAL, 'case_id' , trim(caseid)) 360 | call ncd_putatt(ncid, NCD_GLOBAL, 'title', & 361 | 'MOSART Restart information, required to continue a simulation' ) 362 | 363 | end subroutine restFile_dimset 364 | 365 | !----------------------------------------------------------------------- 366 | 367 | subroutine mosart_rest_restart(ncid, flag) 368 | 369 | !------------------------------------- 370 | ! Read/write MOSART restart data. 371 | ! 372 | ! Arguments: 373 | type(file_desc_t), intent(inout) :: ncid ! netcdf id 374 | character(len=*) , intent(in) :: flag ! 'read' or 'write' 375 | 376 | ! Local variables 377 | logical :: readvar ! determine if variable is on initial file 378 | integer :: n,nt,nv ! indices 379 | integer :: nvariables 380 | real(r8) , pointer :: dfld(:) ! temporary array 381 | character(len=CS) :: vname,uname 382 | character(len=CL) :: lname 383 | !------------------------------------- 384 | 385 | nvariables = 7 386 | do nv = 1,nvariables 387 | do nt = 1,ctl%ntracers 388 | 389 | if (nv == 1) then 390 | vname = 'VOLR_'//trim(ctl%tracer_names(nt)) 391 | lname = 'water volume in cell (volr)' 392 | uname = 'm3' 393 | dfld => ctl%volr(:,nt) 394 | elseif (nv == 2) then 395 | vname = 'RUNOFF_'//trim(ctl%tracer_names(nt)) 396 | lname = 'runoff (runoff)' 397 | uname = 'm3/s' 398 | dfld => ctl%runoff(:,nt) 399 | elseif (nv == 3) then 400 | vname = 'DVOLRDT_'//trim(ctl%tracer_names(nt)) 401 | lname = 'water volume change in cell (dvolrdt)' 402 | uname = 'mm/s' 403 | dfld => ctl%dvolrdt(:,nt) 404 | elseif (nv == 4) then 405 | vname = 'WH_'//trim(ctl%tracer_names(nt)) 406 | lname = 'surface water storage at hillslopes in cell' 407 | uname = 'm' 408 | dfld => Trunoff%wh(:,nt) 409 | elseif (nv == 5) then 410 | vname = 'WT_'//trim(ctl%tracer_names(nt)) 411 | lname = 'water storage in tributary channels in cell' 412 | uname = 'm3' 413 | dfld => Trunoff%wt(:,nt) 414 | elseif (nv == 6) then 415 | vname = 'WR_'//trim(ctl%tracer_names(nt)) 416 | lname = 'water storage in main channel in cell' 417 | uname = 'm3' 418 | dfld => Trunoff%wr(:,nt) 419 | elseif (nv == 7) then 420 | vname = 'EROUT_'//trim(ctl%tracer_names(nt)) 421 | lname = 'instataneous flow out of main channel in cell' 422 | uname = 'm3/s' 423 | dfld => Trunoff%erout(:,nt) 424 | else 425 | write(iulog,*) 'ERROR: illegal nv value a ',nv 426 | call shr_sys_abort() 427 | endif 428 | 429 | if (flag == 'define') then 430 | call ncd_defvar(ncid=ncid, varname=trim(vname), & 431 | xtype=ncd_double, dim1name='nlon', dim2name='nlat', & 432 | long_name=trim(lname), units=trim(uname), fill_value=spval) 433 | else if (flag == 'read' .or. flag == 'write') then 434 | call ncd_io(varname=trim(vname), data=dfld, dim1name='allrof', & 435 | ncid=ncid, flag=flag, readvar=readvar) 436 | if (flag=='read' .and. .not. readvar) then 437 | if (nsrest == nsrContinue) then 438 | call shr_sys_abort() 439 | else 440 | dfld = 0._r8 441 | end if 442 | end if 443 | end if 444 | 445 | enddo 446 | enddo 447 | 448 | if (flag == 'read') then 449 | do n = ctl%begr,ctl%endr 450 | do nt = 1,ctl%ntracers 451 | if (abs(ctl%volr(n,nt)) > 1.e30) ctl%volr(n,nt) = 0. 452 | if (abs(ctl%runoff(n,nt)) > 1.e30) ctl%runoff(n,nt) = 0. 453 | if (abs(ctl%dvolrdt(n,nt)) > 1.e30) ctl%dvolrdt(n,nt) = 0. 454 | if (abs(Trunoff%wh(n,nt)) > 1.e30) Trunoff%wh(n,nt) = 0. 455 | if (abs(Trunoff%wt(n,nt)) > 1.e30) Trunoff%wt(n,nt) = 0. 456 | if (abs(Trunoff%wr(n,nt)) > 1.e30) Trunoff%wr(n,nt) = 0. 457 | if (abs(Trunoff%erout(n,nt)) > 1.e30) Trunoff%erout(n,nt) = 0. 458 | end do 459 | if (ctl%mask(n) == 1) then 460 | do nt = 1,ctl%ntracers 461 | ctl%runofflnd(n,nt) = ctl%runoff(n,nt) 462 | ctl%dvolrdtlnd(n,nt)= ctl%dvolrdt(n,nt) 463 | end do 464 | elseif (ctl%mask(n) >= 2) then 465 | do nt = 1,ctl%ntracers 466 | ctl%runoffocn(n,nt) = ctl%runoff(n,nt) 467 | ctl%dvolrdtocn(n,nt)= ctl%dvolrdt(n,nt) 468 | enddo 469 | endif 470 | enddo 471 | endif 472 | 473 | end subroutine mosart_rest_restart 474 | 475 | end module mosart_restfile 476 | -------------------------------------------------------------------------------- /src/riverroute/mosart_tctl_type.F90: -------------------------------------------------------------------------------- 1 | module mosart_tctl_type 2 | 3 | use shr_kind_mod, only : r8 => shr_kind_r8, CL => SHR_KIND_CL 4 | 5 | implicit none 6 | private 7 | 8 | type Tctl_type 9 | real(r8) :: DeltaT ! Time step in seconds 10 | integer :: DLevelH2R ! The base number of channel routing sub-time-steps within one hillslope routing step. 11 | ! Usually channel routing requires small time steps than hillslope routing. 12 | integer :: DLevelR ! The number of channel routing sub-time-steps at a higher level within one channel routing step at a lower level. 13 | integer :: RoutingMethod ! Flag for routing methods. 1 --> variable storage method from SWAT model 14 | contains 15 | procedure :: Init 16 | end type Tctl_type 17 | public :: Tctl_type 18 | 19 | contains 20 | 21 | subroutine Init(this) 22 | class(Tctl_type) :: this 23 | 24 | this%RoutingMethod = 1 25 | this%DLevelH2R = 5 26 | this%DLevelR = 3 27 | 28 | end subroutine Init 29 | 30 | end module mosart_tctl_type 31 | -------------------------------------------------------------------------------- /src/riverroute/mosart_timemanager.F90: -------------------------------------------------------------------------------- 1 | module mosart_timemanager 2 | 3 | use shr_kind_mod , only: r8 => shr_kind_r8, CS => shr_kind_CS 4 | use shr_sys_mod , only: shr_sys_abort 5 | use shr_string_mod , only: shr_string_toUpper 6 | use mosart_vars , only: isecspday, iulog, nsrest, nsrContinue, mainproc 7 | use ESMF , only: ESMF_MAXSTR, ESMF_Calendar, ESMF_Clock, ESMF_Time, ESMF_TimeInterval, & 8 | ESMF_TimeIntervalSet, ESMF_TimeIntervalGet, ESMF_TimeSet, ESMF_TimeGet, & 9 | ESMF_ClockCreate, ESMF_ClockGet, ESMF_ClockAdvance, & 10 | ESMF_CalKind_Flag, ESMF_CalendarCreate, & 11 | ESMF_CALKIND_NOLEAP, ESMF_CALKIND_GREGORIAN, ESMF_SUCCESS, ESMF_KIND_I8, & 12 | operator(==), operator(/=), operator(<), operator(<=), & 13 | operator(>), operator(>=), operator(-) 14 | use mosart_io , only: ncd_defvar, ncd_io, ncd_int 15 | use pio , only: file_desc_t 16 | 17 | implicit none 18 | private 19 | 20 | ! Public methods 21 | 22 | public :: timemgr_setup ! setup startup values 23 | public :: timemgr_init ! time manager initialization, always called 24 | public :: timemgr_restart ! read/write time manager restart info and setup after a restart 25 | public :: advance_timestep ! increment timestep number 26 | public :: get_step_size ! return step size in seconds 27 | public :: get_nstep ! return timestep number 28 | public :: get_curr_date ! return date components at end of current timestep 29 | public :: get_prev_date ! return date components at beginning of current timestep 30 | public :: get_start_date ! return components of the start date 31 | public :: get_ref_date ! return components of the reference date 32 | public :: get_curr_time ! return components of elapsed time since reference date at end of current timestep 33 | public :: get_prev_time ! return components of elapsed time since reference date at beg of current timestep 34 | public :: get_calendar ! return calendar 35 | public :: is_restart ! return true if this is a restart run 36 | 37 | ! Calendar types 38 | character(len=*), public, parameter :: NO_LEAP_C = 'NO_LEAP' 39 | character(len=*), public, parameter :: GREGORIAN_C = 'GREGORIAN' 40 | 41 | type(ESMF_Calendar), target :: tm_cal ! calendar 42 | type(ESMF_Clock) :: tm_clock ! model clock 43 | 44 | character(len=ESMF_MAXSTR) :: calendar = NO_LEAP_C ! Calendar to use in date calculations 45 | integer, parameter :: uninit_int = -999999999 46 | real(r8), parameter :: uninit_r8 = -999999999.0 47 | 48 | ! Input 49 | integer :: dtime = uninit_int ! timestep in seconds 50 | 51 | ! Initialization data 52 | integer :: start_ymd = uninit_int ! starting date for run in yearmmdd format 53 | integer :: start_tod = 0 ! starting time of day for run in seconds 54 | integer :: stop_ymd = uninit_int ! stopping date for run in yearmmdd format 55 | integer :: stop_tod = 0 ! stopping time of day for run in seconds 56 | integer :: ref_ymd = uninit_int ! reference date for time coordinate in yearmmdd format 57 | integer :: ref_tod = 0 ! reference time of day for time coordinate in seconds 58 | 59 | ! Data required to restart time manager: 60 | integer :: rst_step_sec = uninit_int ! timestep size seconds 61 | integer :: rst_start_ymd = uninit_int ! start date 62 | integer :: rst_start_tod = uninit_int ! start time of day 63 | integer :: rst_ref_ymd = uninit_int ! reference date 64 | integer :: rst_ref_tod = uninit_int ! reference time of day 65 | integer :: rst_curr_ymd = uninit_int ! current date 66 | integer :: rst_curr_tod = uninit_int ! current time of day 67 | character(len=ESMF_MAXSTR) :: rst_calendar ! Calendar 68 | 69 | integer :: cal_type = uninit_int ! calendar type 70 | logical :: timemgr_set = .false. ! true when timemgr initialized 71 | 72 | ! Private module methods 73 | private :: init_calendar 74 | private :: init_clock 75 | private :: timemgr_print 76 | private :: TimeGetymd 77 | 78 | !========================================================================================= 79 | contains 80 | !========================================================================================= 81 | 82 | subroutine timemgr_setup( calendar_in, start_ymd_in, start_tod_in, ref_ymd_in, & 83 | ref_tod_in, stop_ymd_in, stop_tod_in) 84 | 85 | ! set time manager startup values 86 | character(len=*), optional, intent(in) :: calendar_in ! Calendar type 87 | integer , optional, intent(in) :: start_ymd_in ! Start date (YYYYMMDD) 88 | integer , optional, intent(in) :: start_tod_in ! Start time of day (sec) 89 | integer , optional, intent(in) :: ref_ymd_in ! Reference date (YYYYMMDD) 90 | integer , optional, intent(in) :: ref_tod_in ! Reference time of day (sec) 91 | integer , optional, intent(in) :: stop_ymd_in ! Stop date (YYYYMMDD) 92 | integer , optional, intent(in) :: stop_tod_in ! Stop time of day (sec) 93 | character(len=*), parameter :: sub = 'timemgr_setup' 94 | 95 | ! timemgr_set is called in timemgr_init 96 | if ( timemgr_set ) then 97 | call shr_sys_abort( sub//":: timemgr_init already called" ) 98 | end if 99 | if (present(calendar_in) ) calendar = trim(calendar_in) 100 | if (present(start_ymd_in)) start_ymd = start_ymd_in 101 | if (present(start_tod_in)) start_tod = start_tod_in 102 | if (present(ref_ymd_in) ) ref_ymd = ref_ymd_in 103 | if (present(ref_tod_in) ) ref_tod = ref_tod_in 104 | if (present(stop_ymd_in) ) stop_ymd = stop_ymd_in 105 | if (present(stop_tod_in) ) stop_tod = stop_tod_in 106 | 107 | end subroutine timemgr_setup 108 | 109 | !========================================================================================= 110 | 111 | subroutine timemgr_init( dtime_in, curr_date ) 112 | 113 | ! Initialize the ESMF time manager from the sync clock 114 | 115 | ! Arguments 116 | integer, intent(in) :: dtime_in ! Time-step (sec) 117 | type(ESMF_Time), intent(in) :: curr_date ! Current date 118 | 119 | ! Local variables 120 | integer :: rc ! return code 121 | integer :: yr, mon, day, tod ! Year, month, day, and second as integers 122 | type(ESMF_Time) :: start_date ! start date for run 123 | type(ESMF_Time) :: stop_date ! stop date for run 124 | type(ESMF_Time) :: ref_date ! reference date for time coordinate 125 | type(ESMF_Time) :: current ! current date (from clock) 126 | type(ESMF_TimeInterval) :: day_step_size ! day step size 127 | type(ESMF_TimeInterval) :: step_size ! timestep size 128 | character(len=*), parameter :: sub = 'timemgr_init' 129 | 130 | dtime = real(dtime_in) 131 | 132 | ! Initalize calendar 133 | call init_calendar() 134 | 135 | ! Initalize start date. 136 | if ( start_ymd == uninit_int ) then 137 | write(iulog,*)sub,': start_ymd must be specified ' 138 | call shr_sys_abort 139 | end if 140 | if ( start_tod == uninit_int ) then 141 | write(iulog,*)sub,': start_tod must be specified ' 142 | call shr_sys_abort 143 | end if 144 | start_date = TimeSetymd( start_ymd, start_tod, "start_date" ) 145 | 146 | ! Initalize stop date. 147 | stop_date = TimeSetymd( 99991231, stop_tod, "stop_date" ) 148 | call ESMF_TimeIntervalSet( step_size, s=dtime, rc=rc ) 149 | call chkrc(rc, sub//': error return from ESMF_TimeIntervalSet: setting step_size') 150 | call ESMF_TimeIntervalSet( day_step_size, d=1, rc=rc ) 151 | call chkrc(rc, sub//': error return from ESMF_TimeIntervalSet: setting day_step_size') 152 | if ( stop_ymd /= uninit_int ) then 153 | current = TimeSetymd( stop_ymd, stop_tod, "stop_date" ) 154 | if ( current < stop_date ) stop_date = current 155 | else 156 | call shr_sys_abort (sub//': Must specify stop_ymd') 157 | end if 158 | 159 | ! Error check 160 | if ( stop_date <= start_date ) then 161 | write(iulog,*)sub, ': stop date must be specified later than start date: ' 162 | call ESMF_TimeGet( start_date, yy=yr, mm=mon, dd=day, s=tod ) 163 | write(iulog,*) ' Start date (yr, mon, day, tod): ', yr, mon, day, tod 164 | call ESMF_TimeGet( stop_date, yy=yr, mm=mon, dd=day, s=tod ) 165 | write(iulog,*) ' Stop date (yr, mon, day, tod): ', yr, mon, day, tod 166 | call shr_sys_abort 167 | end if 168 | if ( curr_date >= stop_date ) then 169 | write(iulog,*)sub, ': stop date must be specified later than current date: ' 170 | call ESMF_TimeGet( curr_date, yy=yr, mm=mon, dd=day, s=tod ) 171 | write(iulog,*) ' Current date (yr, mon, day, tod): ', yr, mon, day, tod 172 | call ESMF_TimeGet( stop_date, yy=yr, mm=mon, dd=day, s=tod ) 173 | write(iulog,*) ' Stop date (yr, mon, day, tod): ', yr, mon, day, tod 174 | call shr_sys_abort 175 | end if 176 | 177 | ! Initalize reference date for time coordinate. 178 | if ( ref_ymd /= uninit_int ) then 179 | ref_date = TimeSetymd( ref_ymd, ref_tod, "ref_date" ) 180 | else 181 | ref_date = start_date 182 | end if 183 | 184 | ! Initialize clock 185 | call init_clock( start_date, ref_date, curr_date, stop_date ) 186 | 187 | ! Print configuration summary to log file (stdout). 188 | if (mainproc) call timemgr_print() 189 | 190 | timemgr_set = .true. 191 | 192 | end subroutine timemgr_init 193 | 194 | !========================================================================================= 195 | 196 | subroutine init_clock( start_date, ref_date, curr_date, stop_date ) 197 | 198 | ! Initialize the clock based on the start_date, ref_date, and curr_date 199 | ! as well as the settings from the namelist specifying the time to stop 200 | 201 | ! Arguments 202 | type(ESMF_Time), intent(in) :: start_date ! start date for run 203 | type(ESMF_Time), intent(in) :: ref_date ! reference date for time coordinate 204 | type(ESMF_Time), intent(in) :: curr_date ! current date (equal to start_date) 205 | type(ESMF_Time), intent(in) :: stop_date ! stop date for run 206 | 207 | ! Local variables 208 | type(ESMF_TimeInterval) :: step_size ! timestep size 209 | type(ESMF_Time) :: current ! current date (from clock) 210 | integer :: yr, mon, day, tod ! Year, month, day, and second as integers 211 | integer :: rc ! return code 212 | character(len=*), parameter :: sub = 'init_clock' 213 | 214 | ! Initialize the clock 215 | call ESMF_TimeIntervalSet( step_size, s=dtime, rc=rc ) 216 | call chkrc(rc, sub//': error return from ESMF_TimeIntervalSet: setting step_size') 217 | tm_clock = ESMF_ClockCreate(name="MOSART Time-manager clock", timeStep=step_size, startTime=start_date, & 218 | stopTime=stop_date, refTime=ref_date, rc=rc) 219 | call chkrc(rc, sub//': error return from ESMF_ClockSetup') 220 | 221 | ! Advance clock to the current time (in case of a restart) 222 | call ESMF_ClockGet(tm_clock, currTime=current, rc=rc ) 223 | call chkrc(rc, sub//': error return from ESMF_ClockGet') 224 | do while( curr_date > current ) 225 | call ESMF_ClockAdvance( tm_clock, rc=rc ) 226 | call chkrc(rc, sub//': error return from ESMF_ClockAdvance') 227 | call ESMF_ClockGet(tm_clock, currTime=current ) 228 | call chkrc(rc, sub//': error return from ESMF_ClockGet') 229 | end do 230 | end subroutine init_clock 231 | 232 | !========================================================================================= 233 | 234 | function TimeSetymd( ymd, tod, desc ) 235 | 236 | ! Set the time by an integer as YYYYMMDD and integer seconds in the day 237 | 238 | ! Arguments 239 | integer , intent(in) :: ymd ! Year, month, day YYYYMMDD 240 | integer , intent(in) :: tod ! Time of day in seconds 241 | character(len=*) , intent(in) :: desc ! Description of time to set 242 | 243 | ! Return value 244 | type(ESMF_Time) :: TimeSetymd ! Return value 245 | 246 | ! Local variables 247 | integer :: yr, mon, day ! Year, month, day as integers 248 | integer :: rc ! return code 249 | character(len=*), parameter :: sub = 'TimeSetymd' 250 | 251 | if ( (ymd < 0) .or. (tod < 0) .or. (tod > isecspday) )then 252 | write(iulog,*) sub//': error yymmdd is a negative number or time-of-day out of bounds', & 253 | ymd, tod 254 | call shr_sys_abort 255 | end if 256 | yr = ymd / 10000 257 | mon = (ymd - yr*10000) / 100 258 | day = ymd - yr*10000 - mon*100 259 | call ESMF_TimeSet( TimeSetymd, yy=yr, mm=mon, dd=day, s=tod, calendar=tm_cal, rc=rc) 260 | call chkrc(rc, sub//': error return from ESMF_TimeSet: setting '//trim(desc)) 261 | end function TimeSetymd 262 | 263 | !========================================================================================= 264 | 265 | integer function TimeGetymd( date, tod ) 266 | 267 | ! Get the date and time of day in ymd from ESMF Time. 268 | ! 269 | type(ESMF_Time), intent(inout) :: date ! Input date to convert to ymd 270 | integer, intent(out), optional :: tod ! Time of day in seconds 271 | ! 272 | integer :: yr, mon, day 273 | integer :: rc ! return code 274 | character(len=*), parameter :: sub = 'TimeGetymd' 275 | ! 276 | call ESMF_TimeGet( date, yy=yr, mm=mon, dd=day, rc=rc) 277 | call chkrc(rc, sub//': error return from ESMF_TimeGet') 278 | TimeGetymd = yr*10000 + mon*100 + day 279 | if ( present( tod ) )then 280 | call ESMF_TimeGet( date, yy=yr, mm=mon, dd=day, s=tod, rc=rc) 281 | call chkrc(rc, sub//': error return from ESMF_TimeGet') 282 | end if 283 | if ( yr < 0 )then 284 | write(iulog,*) sub//': error year is less than zero', yr 285 | call shr_sys_abort 286 | end if 287 | end function TimeGetymd 288 | 289 | !========================================================================================= 290 | 291 | subroutine timemgr_restart(ncid, flag) 292 | 293 | ! Read/Write information needed on restart to a netcdf file. 294 | ! 295 | type(file_desc_t), intent(inout) :: ncid ! netcdf id 296 | character(len=*) , intent(in) :: flag ! 'read' or 'write' 297 | ! 298 | integer :: yr, mon, day, tod ! Year, month, day, and second as integers 299 | logical :: readvar ! determine if variable is on initial file 300 | integer :: rst_caltype ! calendar type 301 | type(ESMF_Time) :: start_date ! start date for run 302 | type(ESMF_Time) :: stop_date ! stop date for run 303 | type(ESMF_Time) :: ref_date ! reference date for run 304 | type(ESMF_Time) :: curr_date ! date of data in restart file 305 | type(ESMF_Time) :: current ! current date (from clock) 306 | type(ESMF_TimeInterval) :: day_step_size ! day step size 307 | type(ESMF_TimeInterval) :: step_size ! timestep size 308 | integer, parameter :: noleap = 1 309 | integer, parameter :: gregorian = 2 310 | character(len=CS) :: varname 311 | character(len=len(calendar)) :: cal 312 | integer :: rc ! return code 313 | character(len=*), parameter :: sub = 'timemgr_restart' 314 | ! 315 | if ( .not. timemgr_set ) then 316 | call shr_sys_abort( sub//":: timemgr_init MUST be called first" ) 317 | end if 318 | ! 319 | ! Read/Write/Define restart time from restart file 320 | ! 321 | if (flag == 'write') then 322 | rst_calendar = calendar 323 | else if (flag == 'read') then 324 | calendar = rst_calendar 325 | end if 326 | varname = 'timemgr_rst_type' 327 | if (flag == 'define') then 328 | call ncd_defvar(ncid=ncid, varname=varname, xtype=ncd_int, & 329 | long_name='calendar type', units='unitless', flag_meanings=(/ "NO_LEAP_C", "GREGORIAN" /), & 330 | flag_values=(/ noleap, gregorian /), ifill_value=uninit_int ) 331 | else if (flag == 'read' .or. flag == 'write') then 332 | if (flag== 'write') then 333 | cal = shr_string_toUpper(calendar) 334 | if ( trim(cal) == NO_LEAP_C ) then 335 | rst_caltype = noleap 336 | else if ( trim(cal) == GREGORIAN_C ) then 337 | rst_caltype = gregorian 338 | else 339 | call shr_sys_abort(sub//'ERROR: unrecognized calendar specified= '//trim(calendar)) 340 | end if 341 | end if 342 | call ncd_io(varname=varname, data=rst_caltype, & 343 | ncid=ncid, flag=flag, readvar=readvar) 344 | if (flag=='read' .and. .not. readvar) then 345 | if (is_restart()) then 346 | call shr_sys_abort( sub//'ERROR: '//trim(varname)//' not on file') 347 | end if 348 | end if 349 | if (flag == 'read') then 350 | if ( rst_caltype == noleap ) then 351 | calendar = NO_LEAP_C 352 | else if ( rst_caltype == gregorian ) then 353 | calendar = GREGORIAN_C 354 | else 355 | write(iulog,*)sub,': unrecognized calendar type in restart file: ',rst_caltype 356 | call shr_sys_abort( sub//'ERROR: bad calendar type in restart file') 357 | end if 358 | end if 359 | end if 360 | 361 | if (flag == 'write') then 362 | call ESMF_ClockGet( tm_clock, startTime=start_date, currTime=curr_date, refTime=ref_date, rc=rc ) 363 | call chkrc(rc, sub//': error return from ESMF_ClockGet') 364 | rst_step_sec = dtime 365 | rst_start_ymd = TimeGetymd( start_date, tod=rst_start_tod ) 366 | rst_ref_ymd = TimeGetymd( ref_date, tod=rst_ref_tod ) 367 | rst_curr_ymd = TimeGetymd( curr_date, tod=rst_curr_tod ) 368 | end if 369 | 370 | varname = 'timemgr_rst_step_sec' 371 | if (flag == 'define') then 372 | call ncd_defvar(ncid=ncid, varname=varname, xtype=ncd_int, & 373 | long_name='seconds component of timestep size', units='sec', nvalid_range=(/0,isecspday/), ifill_value=uninit_int) 374 | else if (flag == 'read' .or. flag == 'write') then 375 | call ncd_io(varname=varname, data=rst_step_sec, & 376 | ncid=ncid, flag=flag, readvar=readvar) 377 | if (flag=='read' .and. .not. readvar) then 378 | if (is_restart()) then 379 | call shr_sys_abort( sub//'ERROR: '//trim(varname)//' not on file') 380 | end if 381 | end if 382 | if ( rst_step_sec < 0 .or. rst_step_sec > isecspday ) then 383 | call shr_sys_abort( sub//'ERROR: '//trim(varname)//' out of range') 384 | end if 385 | end if 386 | 387 | varname = 'timemgr_rst_start_ymd' 388 | if (flag == 'define') then 389 | call ncd_defvar(ncid=ncid, varname=varname, xtype=ncd_int, & 390 | long_name='start date', units='YYYYMMDD', ifill_value=uninit_int) 391 | else if (flag == 'read' .or. flag == 'write') then 392 | call ncd_io(varname=varname, data=rst_start_ymd, & 393 | ncid=ncid, flag=flag, readvar=readvar) 394 | if (flag=='read' .and. .not. readvar) then 395 | if (is_restart()) then 396 | call shr_sys_abort( sub//'ERROR: '//trim(varname)//' not on file') 397 | end if 398 | end if 399 | end if 400 | 401 | varname = 'timemgr_rst_start_tod' 402 | if (flag == 'define') then 403 | call ncd_defvar(ncid=ncid, varname=varname, xtype=ncd_int, & 404 | long_name='start time of day', units='sec', nvalid_range=(/0,isecspday/), ifill_value=uninit_int) 405 | else if (flag == 'read' .or. flag == 'write') then 406 | call ncd_io(varname=varname, data=rst_start_tod, & 407 | ncid=ncid, flag=flag, readvar=readvar) 408 | if (flag=='read' .and. .not. readvar) then 409 | if (is_restart()) then 410 | call shr_sys_abort( sub//'ERROR: '//trim(varname)//' not on file') 411 | end if 412 | end if 413 | if ( rst_start_tod < 0 .or. rst_start_tod > isecspday ) then 414 | call shr_sys_abort( sub//'ERROR: '//trim(varname)//' out of range') 415 | end if 416 | end if 417 | 418 | varname = 'timemgr_rst_ref_ymd' 419 | if (flag == 'define') then 420 | call ncd_defvar(ncid=ncid, varname=varname, xtype=ncd_int, & 421 | long_name='reference date', units='YYYYMMDD', ifill_value=uninit_int) 422 | else if (flag == 'read' .or. flag == 'write') then 423 | call ncd_io(varname=varname, data=rst_ref_ymd, & 424 | ncid=ncid, flag=flag, readvar=readvar) 425 | if (flag=='read' .and. .not. readvar) then 426 | if (is_restart()) then 427 | call shr_sys_abort( sub//'ERROR: '//trim(varname)//' not on file') 428 | end if 429 | end if 430 | end if 431 | 432 | varname = 'timemgr_rst_ref_tod' 433 | if (flag == 'define') then 434 | call ncd_defvar(ncid=ncid, varname=varname, xtype=ncd_int, & 435 | long_name='reference time of day', units='sec', nvalid_range=(/0,isecspday/), ifill_value=uninit_int) 436 | else if (flag == 'read' .or. flag == 'write') then 437 | call ncd_io(varname=varname, data=rst_ref_tod, & 438 | ncid=ncid, flag=flag, readvar=readvar) 439 | if (flag=='read' .and. .not. readvar) then 440 | if (is_restart()) then 441 | call shr_sys_abort( sub//'ERROR: '//trim(varname)//' not on file') 442 | end if 443 | end if 444 | if ( rst_start_tod < 0 .or. rst_start_tod > isecspday ) then 445 | call shr_sys_abort( sub//'ERROR: '//trim(varname)//' out of range') 446 | end if 447 | end if 448 | 449 | varname = 'timemgr_rst_curr_ymd' 450 | if (flag == 'define') then 451 | call ncd_defvar(ncid=ncid, varname=varname, xtype=ncd_int, & 452 | long_name='current date', units='YYYYMMDD', ifill_value=uninit_int) 453 | else if (flag == 'read' .or. flag == 'write') then 454 | call ncd_io(varname=varname, data=rst_curr_ymd, & 455 | ncid=ncid, flag=flag, readvar=readvar) 456 | if (flag=='read' .and. .not. readvar) then 457 | if (is_restart()) then 458 | call shr_sys_abort( sub//'ERROR: '//trim(varname)//' not on file') 459 | end if 460 | end if 461 | end if 462 | 463 | varname = 'timemgr_rst_curr_tod' 464 | if (flag == 'define') then 465 | call ncd_defvar(ncid=ncid, varname=varname, xtype=ncd_int, & 466 | long_name='current time of day', units='sec', nvalid_range=(/0,isecspday/), ifill_value=uninit_int ) 467 | else if (flag == 'read' .or. flag == 'write') then 468 | call ncd_io(varname=varname, data=rst_curr_tod, & 469 | ncid=ncid, flag=flag, readvar=readvar) 470 | if (flag=='read' .and. .not. readvar) then 471 | if (is_restart()) then 472 | call shr_sys_abort( sub//'ERROR: '//trim(varname)//' not on file') 473 | end if 474 | end if 475 | if ( rst_curr_tod < 0 .or. rst_curr_tod > isecspday ) then 476 | call shr_sys_abort( sub//'ERROR: '//trim(varname)//' out of range') 477 | end if 478 | end if 479 | 480 | ! 481 | ! On read make sure restart read in agrees with the system clock sent in 482 | ! 483 | if (flag == 'read') then 484 | 485 | ! Compare the timestep to restart file 486 | if(dtime .ne. rst_step_sec) then 487 | call shr_sys_abort( sub//'ERROR: dtime does not match restart file rst_step_sec') 488 | endif 489 | if(start_ymd .ne. rst_start_ymd) then 490 | call shr_sys_abort( sub//'ERROR: start_ymd does not match restart file rst_start_ymd') 491 | endif 492 | if(start_tod .ne. rst_start_tod) then 493 | call shr_sys_abort( sub//'ERROR: start_tod does not match restart file rst_start_tod') 494 | endif 495 | 496 | if(ref_ymd .ne. rst_ref_ymd) then 497 | call shr_sys_abort( sub//'ERROR: ref_ymd does not match restart file rst_ref_ymd') 498 | endif 499 | if(ref_tod .ne. rst_ref_tod) then 500 | call shr_sys_abort( sub//'ERROR: ref_tod does not match restart file rst_ref_tod') 501 | endif 502 | 503 | call ESMF_TimeIntervalSet( step_size, s=dtime, rc=rc ) 504 | call chkrc(rc, sub//': error return from ESMF_TimeIntervalSet: setting step_size') 505 | call ESMF_TimeIntervalSet( day_step_size, d=1, rc=rc ) 506 | call chkrc(rc, sub//': error return from ESMF_TimeIntervalSet: setting day_step_size') 507 | 508 | end if 509 | 510 | end subroutine timemgr_restart 511 | 512 | !========================================================================================= 513 | 514 | subroutine init_calendar( ) 515 | 516 | !--------------------------------------------------------------------------------- 517 | ! Initialize calendar 518 | ! 519 | ! Local variables 520 | type(ESMF_CalKind_Flag) :: cal_type ! calendar type 521 | character(len=len(calendar)) :: caltmp 522 | integer :: rc ! return code 523 | character(len=*), parameter :: sub = 'init_calendar' 524 | !--------------------------------------------------------------------------------- 525 | 526 | caltmp = shr_string_toUpper(calendar) 527 | if ( trim(caltmp) == NO_LEAP_C ) then 528 | cal_type = ESMF_CALKIND_NOLEAP 529 | else if ( trim(caltmp) == GREGORIAN_C ) then 530 | cal_type = ESMF_CALKIND_GREGORIAN 531 | else 532 | write(iulog,*)sub,': unrecognized calendar specified: ',calendar 533 | call shr_sys_abort 534 | end if 535 | tm_cal = ESMF_CalendarCreate( name=caltmp, calkindflag=cal_type, rc=rc ) 536 | call chkrc(rc, sub//': error return from ESMF_CalendarSet') 537 | 538 | end subroutine init_calendar 539 | 540 | !========================================================================================= 541 | 542 | subroutine timemgr_print() 543 | 544 | !--------------------------------------------------------------------------------- 545 | integer :: rc 546 | integer :: yr, mon, day 547 | integer :: nstep = uninit_int ! current step number 548 | integer :: step_sec = uninit_int ! timestep size seconds 549 | integer :: start_yr = uninit_int ! start year 550 | integer :: start_mon = uninit_int ! start month 551 | integer :: start_day = uninit_int ! start day of month 552 | integer :: start_tod = uninit_int ! start time of day 553 | integer :: stop_yr = uninit_int ! stop year 554 | integer :: stop_mon = uninit_int ! stop month 555 | integer :: stop_day = uninit_int ! stop day of month 556 | integer :: stop_tod = uninit_int ! stop time of day 557 | integer :: ref_yr = uninit_int ! reference year 558 | integer :: ref_mon = uninit_int ! reference month 559 | integer :: ref_day = uninit_int ! reference day of month 560 | integer :: ref_tod = uninit_int ! reference time of day 561 | integer :: curr_yr = uninit_int ! current year 562 | integer :: curr_mon = uninit_int ! current month 563 | integer :: curr_day = uninit_int ! current day of month 564 | integer :: curr_tod = uninit_int ! current time of day 565 | type(ESMF_Time) :: start_date ! start date for run 566 | type(ESMF_Time) :: stop_date ! stop date for run 567 | type(ESMF_Time) :: curr_date ! date of data in restart file 568 | type(ESMF_Time) :: ref_date ! reference date 569 | type(ESMF_TimeInterval) :: step ! Time-step 570 | integer(ESMF_KIND_I8) :: step_no 571 | character(len=*), parameter :: sub = 'timemgr_print' 572 | !--------------------------------------------------------------------------------- 573 | 574 | call ESMF_ClockGet( tm_clock, startTime=start_date, currTime=curr_date, & 575 | refTime=ref_date, stopTime=stop_date, timeStep=step, advanceCount=step_no, rc=rc ) 576 | call chkrc(rc, sub//': error return from ESMF_ClockGet') 577 | nstep = step_no 578 | call ESMF_TimeIntervalGet( step, s=step_sec, rc=rc ) 579 | call chkrc(rc, sub//': error return from ESMF_TimeIntervalGet') 580 | call ESMF_TimeGet( start_date, yy=start_yr, mm=start_mon, dd=start_day, s=start_tod, rc=rc ) 581 | call chkrc(rc, sub//': error return from ESMF_TimeGet') 582 | call ESMF_TimeGet( stop_date, yy=stop_yr, mm=stop_mon, dd=stop_day, s=stop_tod, rc=rc ) 583 | call chkrc(rc, sub//': error return from ESMF_TimeGet') 584 | call ESMF_TimeGet( ref_date, yy=ref_yr, mm=ref_mon, dd=ref_day, s=ref_tod, rc=rc ) 585 | call chkrc(rc, sub//': error return from ESMF_TimeGet') 586 | call ESMF_TimeGet( curr_date, yy=curr_yr, mm=curr_mon, dd=curr_day, s=curr_tod, rc=rc ) 587 | call chkrc(rc, sub//': error return from ESMF_TimeGet') 588 | 589 | write(iulog,*)' ******** Time Manager Configuration ********' 590 | write(iulog,*)' Calendar type: ', trim(calendar) 591 | write(iulog,*)' Timestep size (seconds): ', step_sec 592 | write(iulog,*)' Start date (yr mon day tod): ', start_yr, start_mon, start_day, start_tod 593 | write(iulog,*)' Stop date (yr mon day tod): ', stop_yr, stop_mon, stop_day, stop_tod 594 | write(iulog,*)' Reference date (yr mon day tod): ', ref_yr, ref_mon, ref_day, ref_tod 595 | write(iulog,*)' Current step number: ', nstep 596 | write(iulog,*)' Current date (yr mon day tod): ', curr_yr, curr_mon, curr_day, curr_tod 597 | write(iulog,*)' ************************************************' 598 | 599 | end subroutine timemgr_print 600 | 601 | !========================================================================================= 602 | 603 | subroutine advance_timestep() 604 | 605 | ! Increment the timestep number. 606 | 607 | integer :: rc 608 | character(len=*), parameter :: sub = 'advance_timestep' 609 | 610 | call ESMF_ClockAdvance( tm_clock, rc=rc ) 611 | call chkrc(rc, sub//': error return from ESMF_ClockAdvance') 612 | 613 | end subroutine advance_timestep 614 | 615 | !========================================================================================= 616 | 617 | integer function get_step_size() 618 | 619 | ! Return the step size in seconds. 620 | 621 | type(ESMF_TimeInterval) :: step_size ! timestep size 622 | integer :: rc 623 | character(len=*), parameter :: sub = 'get_step_size' 624 | 625 | call ESMF_ClockGet(tm_clock, timeStep=step_size, rc=rc) 626 | call chkrc(rc, sub//': error return from ESMF_ClockGet') 627 | call ESMF_TimeIntervalGet(step_size, s=get_step_size, rc=rc) 628 | call chkrc(rc, sub//': error return from ESMF_ClockTimeIntervalGet') 629 | 630 | end function get_step_size 631 | 632 | !========================================================================================= 633 | 634 | integer function get_nstep() 635 | 636 | ! Return the timestep number. 637 | 638 | integer :: rc 639 | integer(ESMF_KIND_I8) :: step_no 640 | character(len=*), parameter :: sub = 'get_nstep' 641 | 642 | call ESMF_ClockGet(tm_clock, advanceCount=step_no, rc=rc) 643 | call chkrc(rc, sub//': error return from ESMF_ClockGet') 644 | 645 | get_nstep = step_no 646 | 647 | end function get_nstep 648 | 649 | !========================================================================================= 650 | 651 | subroutine get_curr_date(yr, mon, day, tod) 652 | 653 | ! Return date components valid at end of current timestep 654 | 655 | integer , intent(out) :: yr ! year 656 | integer , intent(out) :: mon ! month 657 | integer , intent(out) :: day ! day of month 658 | integer , intent(out) :: tod ! time of day (seconds past 0Z) 659 | 660 | ! Local variables 661 | integer :: rc 662 | type(ESMF_Time) :: date 663 | type(ESMF_TimeInterval) :: off 664 | character(len=*), parameter :: sub = 'get_curr_date' 665 | 666 | call ESMF_ClockGet( tm_clock, currTime=date, rc=rc ) 667 | call chkrc(rc, sub//': error return from ESMF_ClockGet') 668 | call ESMF_TimeGet(date, yy=yr, mm=mon, dd=day, s=tod, rc=rc) 669 | call chkrc(rc, sub//': error return from ESMF_TimeGet') 670 | 671 | end subroutine get_curr_date 672 | 673 | !========================================================================================= 674 | 675 | subroutine get_prev_date(yr, mon, day, tod) 676 | 677 | ! Return date components valid at beginning of current timestep. 678 | 679 | ! Arguments 680 | integer, intent(out) :: yr ! year 681 | integer, intent(out) :: mon ! month 682 | integer, intent(out) :: day ! day of month 683 | integer, intent(out) :: tod ! time of day (seconds past 0Z) 684 | 685 | ! Local variables 686 | integer :: rc 687 | type(ESMF_Time) :: date 688 | character(len=*), parameter :: sub = 'get_prev_date' 689 | 690 | call ESMF_ClockGet(tm_clock, prevTime=date, rc=rc ) 691 | call chkrc(rc, sub//': error return from ESMF_ClockGet') 692 | call ESMF_TimeGet(date, yy=yr, mm=mon, dd=day, s=tod, rc=rc) 693 | call chkrc(rc, sub//': error return from ESMF_TimeGet') 694 | 695 | end subroutine get_prev_date 696 | 697 | !========================================================================================= 698 | 699 | subroutine get_start_date(yr, mon, day, tod) 700 | 701 | ! Return date components valid at beginning of initial run. 702 | 703 | ! Arguments 704 | integer, intent(out) :: yr ! year 705 | integer, intent(out) :: mon ! month 706 | integer, intent(out) :: day ! day of month 707 | integer, intent(out) :: tod ! time of day (seconds past 0Z) 708 | 709 | ! Local variables 710 | integer :: rc 711 | type(ESMF_Time) :: date 712 | character(len=*), parameter :: sub = 'get_start_date' 713 | 714 | call ESMF_ClockGet(tm_clock, startTime=date, rc=rc) 715 | call chkrc(rc, sub//': error return from ESMF_ClockGet') 716 | call ESMF_TimeGet(date, yy=yr, mm=mon, dd=day, s=tod, rc=rc) 717 | call chkrc(rc, sub//': error return from ESMF_TimeGet') 718 | 719 | end subroutine get_start_date 720 | 721 | !========================================================================================= 722 | 723 | subroutine get_ref_date(yr, mon, day, tod) 724 | 725 | ! Return date components of the reference date. 726 | 727 | ! Arguments 728 | integer, intent(out) :: yr ! year 729 | integer, intent(out) :: mon ! month 730 | integer, intent(out) :: day ! day of month 731 | integer, intent(out) :: tod ! time of day (seconds past 0Z) 732 | 733 | ! Local variables 734 | integer :: rc 735 | type(ESMF_Time) :: date 736 | character(len=*), parameter :: sub = 'get_ref_date' 737 | 738 | call ESMF_ClockGet(tm_clock, refTime=date, rc=rc) 739 | call chkrc(rc, sub//': error return from ESMF_ClockGet') 740 | call ESMF_TimeGet(date, yy=yr, mm=mon, dd=day, s=tod, rc=rc) 741 | call chkrc(rc, sub//': error return from ESMF_TimeGet') 742 | 743 | end subroutine get_ref_date 744 | 745 | !========================================================================================= 746 | 747 | subroutine get_curr_time(days, seconds) 748 | 749 | ! Return time components valid at end of current timestep. 750 | ! Current time is the time interval between the current date and the reference date. 751 | 752 | ! Arguments 753 | integer, intent(out) :: days ! number of whole days in time interval 754 | integer, intent(out) :: seconds ! remaining seconds in time interval 755 | 756 | ! Local variables 757 | integer :: rc 758 | type(ESMF_Time) :: cdate, rdate 759 | type(ESMF_TimeInterval) :: diff 760 | character(len=*), parameter :: sub = 'get_curr_time' 761 | 762 | call ESMF_ClockGet( tm_clock, currTime=cdate, rc=rc ) 763 | call chkrc(rc, sub//': error return from ESMF_ClockGet') 764 | call ESMF_ClockGet( tm_clock, refTime=rdate, rc=rc ) 765 | call chkrc(rc, sub//': error return from ESMF_ClockGet') 766 | diff = cdate - rdate 767 | call ESMF_TimeIntervalGet(diff, d=days, s=seconds, rc=rc) 768 | call chkrc(rc, sub//': error return from ESMF_TimeIntervalGet') 769 | 770 | end subroutine get_curr_time 771 | 772 | !========================================================================================= 773 | 774 | subroutine get_prev_time(days, seconds) 775 | 776 | ! Return time components valid at beg of current timestep. 777 | ! prev time is the time interval between the prev date and the reference date. 778 | 779 | ! Arguments 780 | integer, intent(out) :: days ! number of whole days in time interval 781 | integer, intent(out) :: seconds ! remaining seconds in time interval 782 | 783 | ! Local variables 784 | integer :: rc 785 | type(ESMF_Time) :: date, ref_date 786 | type(ESMF_TimeInterval) :: diff 787 | character(len=*), parameter :: sub = 'get_prev_time' 788 | 789 | call ESMF_ClockGet(tm_clock, prevTime=date, rc=rc ) 790 | call chkrc(rc, sub//': error return from ESMF_ClockGet for prevTime') 791 | call ESMF_ClockGet(tm_clock, refTime=ref_date, rc=rc ) 792 | call chkrc(rc, sub//': error return from ESMF_ClockGet for refTime') 793 | diff = date - ref_date 794 | call ESMF_TimeIntervalGet( diff, d=days, s=seconds, rc=rc ) 795 | call chkrc(rc, sub//': error return from ESMF_TimeintervalGet') 796 | 797 | end subroutine get_prev_time 798 | 799 | !========================================================================================= 800 | 801 | function get_calendar() 802 | 803 | ! Return calendar 804 | character(len=ESMF_MAXSTR) :: get_calendar 805 | 806 | get_calendar = calendar 807 | 808 | end function get_calendar 809 | 810 | !========================================================================================= 811 | 812 | logical function is_restart( ) 813 | ! Determine if restart run 814 | if (nsrest == nsrContinue) then 815 | is_restart = .true. 816 | else 817 | is_restart = .false. 818 | end if 819 | end function is_restart 820 | 821 | !========================================================================================= 822 | 823 | subroutine chkrc(rc, mes) 824 | integer, intent(in) :: rc ! return code from time management library 825 | character(len=*), intent(in) :: mes ! error message 826 | if ( rc == ESMF_SUCCESS ) return 827 | write(iulog,*) mes 828 | call shr_sys_abort ('CHKRC') 829 | end subroutine chkrc 830 | 831 | 832 | end module mosart_timemanager 833 | -------------------------------------------------------------------------------- /src/riverroute/mosart_tparameter_type.F90: -------------------------------------------------------------------------------- 1 | module mosart_tparameter_type 2 | 3 | ! parameters to be calibrated. Ideally, these parameters are supposed to be uniform for one region 4 | 5 | use shr_kind_mod, only : r8 => shr_kind_r8, CL => SHR_KIND_CL 6 | 7 | implicit none 8 | private 9 | 10 | public :: Tparameter_type 11 | type Tparameter_type 12 | real(r8), pointer :: c_nr(:) ! coefficient to adjust the manning's roughness of channels NOT_USED 13 | real(r8), pointer :: c_nh(:) ! coefficient to adjust the manning's roughness of overland flow across hillslopes NOT_USED 14 | real(r8), pointer :: c_twid(:) ! coefficient to adjust the width of sub-reach channel 15 | contains 16 | procedure, public :: Init 17 | end type Tparameter_type 18 | 19 | contains 20 | 21 | subroutine Init(this, begr, endr) 22 | 23 | ! Arguments 24 | class(tparameter_type) :: this 25 | integer, intent(in) :: begr, endr 26 | 27 | ! Initialize TPara 28 | allocate (this%c_twid(begr:endr)) 29 | this%c_twid = 1.0_r8 30 | 31 | end subroutine Init 32 | 33 | end module mosart_tparameter_type 34 | -------------------------------------------------------------------------------- /src/riverroute/mosart_tspatialunit_type.F90: -------------------------------------------------------------------------------- 1 | module mosart_tspatialunit_type 2 | 3 | ! Topographic and geometric properties, applicable for both grid- and subbasin-based representations 4 | 5 | use shr_kind_mod, only : r8=>shr_kind_r8, CL=>SHR_KIND_CL, CS=>SHR_KIND_CS 6 | use shr_sys_mod, only : shr_sys_abort 7 | use shr_mpi_mod, only : shr_mpi_sum, shr_mpi_max 8 | use shr_string_mod, only : shr_string_listGetName 9 | use mosart_io, only : ncd_pio_openfile, compDOF 10 | use mosart_vars, only : mainproc, mpicom_rof, iulog 11 | use nuopc_shr_methods, only : chkerr 12 | use ESMF, only : ESMF_Field, ESMF_RouteHandle, ESMF_Mesh, ESMF_FieldCreate, & 13 | ESMF_FieldSMMStore, ESMF_FieldGet, ESMF_FieldSMM, & 14 | ESMF_SUCCESS, ESMF_TYPEKIND_R8, ESMF_MESHLOC_ELEMENT, ESMF_TERMORDER_SRCSEQ 15 | use pio, only : iosystem_desc_t, var_desc_t, io_desc_t, file_desc_t, pio_seterrorhandling, & 16 | pio_inq_varid, pio_inq_vardimid, pio_inq_dimlen, pio_initdecomp, pio_closefile, & 17 | pio_int, pio_double, PIO_INTERNAL_ERROR, pio_read_darray, pio_freedecomp 18 | 19 | implicit none 20 | private 21 | 22 | type Tspatialunit_type 23 | 24 | ! grid properties 25 | integer , pointer :: mask(:) ! mosart mask of mosart cell, 0=null, 1=land with dnID, 2=outlet 26 | integer , pointer :: ID0(:) 27 | real(r8), pointer :: lat(:) ! latitude of the centroid of the cell 28 | real(r8), pointer :: lon(:) ! longitude of the centroid of the cell 29 | real(r8), pointer :: area(:) ! area of local cell, [m2] 30 | real(r8), pointer :: areaTotal(:) ! total upstream drainage area, [m2] 31 | real(r8), pointer :: areaTotal2(:)! computed total upstream drainage area, [m2] 32 | real(r8), pointer :: rlenTotal(:) ! length of all reaches, [m] 33 | real(r8), pointer :: Gxr(:) ! drainage density within the cell, [1/m] 34 | real(r8), pointer :: frac(:) ! fraction of cell included in the study area, [-] 35 | logical , pointer :: euler_calc(:) ! flag for calculating tracers in euler 36 | 37 | ! hillslope properties 38 | real(r8), pointer :: nh(:) ! manning's roughness of the hillslope (channel network excluded) 39 | real(r8), pointer :: hslp(:) ! slope of hillslope, [-] 40 | real(r8), pointer :: hslpsqrt(:) ! sqrt of slope of hillslope, [-] 41 | real(r8), pointer :: hlen(:) ! length of hillslope within the cell, [m] 42 | 43 | ! subnetwork channel properties 44 | real(r8), pointer :: nt(:) ! manning's roughness of the subnetwork at hillslope 45 | real(r8), pointer :: tslp(:) ! average slope of tributaries, [-] 46 | real(r8), pointer :: tslpsqrt(:) ! sqrt of average slope of tributaries, [-] 47 | real(r8), pointer :: tlen(:) ! length of all sub-network reach within the cell, [m] 48 | real(r8), pointer :: twidth(:) ! bankfull width of the sub-reach, [m] 49 | real(r8), pointer :: twidth0(:) ! unadjusted twidth 50 | 51 | ! main channel properties 52 | real(r8), pointer :: nr(:) ! manning's roughness of the main reach 53 | real(r8), pointer :: rlen(:) ! length of main river reach, [m] 54 | real(r8), pointer :: rslp(:) ! slope of main river reach, [-] 55 | real(r8), pointer :: rslpsqrt(:) ! sqrt of slope of main river reach, [-] 56 | real(r8), pointer :: rwidth(:) ! bankfull width of main reach, [m] 57 | real(r8), pointer :: rwidth0(:) ! total width of the flood plain, [m] 58 | real(r8), pointer :: rdepth(:) ! bankfull depth of river cross section, [m] 59 | ! 60 | integer , pointer :: dnID(:) ! IDs of the downstream units, corresponding to the subbasin ID in the input table 61 | integer , pointer :: iUp(:,:) ! IDs of upstream units, corresponding to the subbasin ID in the input table 62 | integer , pointer :: nUp(:) ! number of upstream units, maximum 8 63 | integer , pointer :: indexDown(:) ! indices of the downstream units in the ID array. sometimes subbasins IDs may not be continuous 64 | integer , pointer :: numDT_r(:) ! for a main reach, the number of sub-time-steps needed for numerical stability 65 | integer , pointer :: numDT_t(:) ! for a subnetwork reach, the number of sub-time-steps needed for numerical stability 66 | real(r8), pointer :: phi_r(:) ! the indicator used to define numDT_r 67 | real(r8), pointer :: phi_t(:) ! the indicator used to define numDT_t 68 | 69 | ! mapping 70 | type(ESMF_Field) :: srcField 71 | type(ESMF_Field) :: dstField 72 | type(ESMF_RouteHandle) :: rh_direct 73 | type(ESMF_RouteHandle) :: rh_eroutUp 74 | 75 | contains 76 | 77 | procedure, public :: Init 78 | procedure, private :: set_routehandles 79 | procedure, private :: set_subtimesteps 80 | procedure, private :: set_areatotal2 81 | 82 | end type Tspatialunit_type 83 | public :: Tspatialunit_type 84 | 85 | character(*), parameter :: u_FILE_u = & 86 | __FILE__ 87 | !----------------------------------------------------------------------- 88 | 89 | contains 90 | 91 | !----------------------------------------------------------------------- 92 | subroutine Init(this, begr, endr, ntracers, mosart_euler_calc, nlon, nlat, EMesh, & 93 | frivinp, IDkey, c_twid, DLevelR, area, gindex, outletg, pio_subsystem, rc) 94 | 95 | ! Arguments 96 | class(Tspatialunit_type) :: this 97 | integer , intent(in) :: begr, endr 98 | integer , intent(in) :: ntracers 99 | character(len=*) , intent(in) :: mosart_euler_calc 100 | real(r8) , intent(in) :: area(begr:endr) 101 | integer , intent(in) :: nlon, nlat 102 | character(len=*) , intent(in) :: frivinp 103 | integer , intent(in) :: IDkey(:) 104 | real(r8) , intent(in) :: c_twid(begr:endr) 105 | integer , intent(in) :: DLevelR 106 | type(iosystem_desc_t) , pointer :: pio_subsystem 107 | type(ESMF_Mesh) , intent(in) :: Emesh 108 | integer , intent(in) :: gindex(begr:endr) 109 | integer , intent(in) :: outletg(begr:endr) 110 | integer , intent(out) :: rc 111 | 112 | ! Local variables 113 | integer :: n 114 | integer :: ier 115 | type(file_desc_t) :: ncid ! pio file desc 116 | type(var_desc_t) :: vardesc ! pio variable desc 117 | type(io_desc_t) :: iodesc_dbl ! pio io desc 118 | type(io_desc_t) :: iodesc_int ! pio io desc 119 | integer :: dids(2) ! variable dimension ids 120 | integer :: dsizes(2) ! variable dimension lengths 121 | real(r8) :: hlen_max, rlen_min 122 | character(len=CS) :: ctemp 123 | character(len=*),parameter :: FORMI = '(2A,2i10)' 124 | character(len=*),parameter :: FORMR = '(2A,2g15.7)' 125 | character(len=*),parameter :: subname = '(mosart_tspatialunit_type_init) ' 126 | !-------------------------------------------------------------------------- 127 | 128 | rc = ESMF_SUCCESS 129 | 130 | ! Read in routing parameters 131 | call ncd_pio_openfile (ncid, trim(frivinp), 0) 132 | call pio_seterrorhandling(ncid, PIO_INTERNAL_ERROR) 133 | 134 | ! Setup iodesc based on frac dids 135 | ier = pio_inq_varid(ncid, name='frac', vardesc=vardesc) 136 | ier = pio_inq_vardimid(ncid, vardesc, dids) 137 | ier = pio_inq_dimlen(ncid, dids(1),dsizes(1)) 138 | ier = pio_inq_dimlen(ncid, dids(2),dsizes(2)) 139 | call pio_initdecomp(pio_subsystem, pio_double, dsizes, compDOF, iodesc_dbl) 140 | call pio_initdecomp(pio_subsystem, pio_int , dsizes, compDOF, iodesc_int) 141 | 142 | allocate(this%euler_calc(ntracers)) 143 | do n = 1,ntracers 144 | call shr_string_listGetName(mosart_euler_calc, n, ctemp) 145 | if (trim(ctemp) == 'T') then 146 | this%euler_calc = .true. 147 | else if (trim(ctemp) == 'F') then 148 | this%euler_calc = .false. 149 | else 150 | call shr_sys_abort(trim(subname)//' mosart_euler_calc can only be T or F') 151 | end if 152 | end do 153 | 154 | ! TODO: Will be reworked after addition of extra tracers 155 | this%euler_calc = .true. 156 | 157 | allocate(this%frac(begr:endr)) 158 | ier = pio_inq_varid(ncid, name='frac', vardesc=vardesc) 159 | call pio_read_darray(ncid, vardesc, iodesc_dbl, this%frac, ier) 160 | if (mainproc) then 161 | write(iulog,FORMR) trim(subname),' read frac ',minval(this%frac),maxval(this%frac) 162 | end if 163 | 164 | ! read fdir, convert to mask 165 | ! fdir <0 ocean, 0=outlet, >0 land 166 | ! tunit mask is 0=ocean, 1=land, 2=outlet for mosart calcs 167 | 168 | allocate(this%mask(begr:endr)) 169 | ier = pio_inq_varid(ncid, name='fdir', vardesc=vardesc) 170 | call pio_read_darray(ncid, vardesc, iodesc_int, this%mask, ier) 171 | if (mainproc) then 172 | write(iulog,'(2A,2i10)') trim(subname),' read fdir mask ',minval(this%mask),maxval(this%mask) 173 | end if 174 | 175 | do n = begr, endr 176 | if (this%mask(n) < 0) then 177 | this%mask(n) = 0 178 | elseif (this%mask(n) == 0) then 179 | this%mask(n) = 2 180 | if (abs(this%frac(n)-1.0_r8)>1.0e-9) then 181 | write(iulog,*) subname,' ERROR frac ne 1.0',n,this%frac(n) 182 | call shr_sys_abort(subname//' ERROR frac ne 1.0') 183 | endif 184 | elseif (this%mask(n) > 0) then 185 | this%mask(n) = 1 186 | if (abs(this%frac(n)-1.0_r8)>1.0e-9) then 187 | write(iulog,*) subname,' ERROR frac ne 1.0',n,this%frac(n) 188 | call shr_sys_abort(subname//' ERROR frac ne 1.0') 189 | endif 190 | else 191 | call shr_sys_abort(subname//' this mask error') 192 | endif 193 | enddo 194 | 195 | allocate(this%ID0(begr:endr)) 196 | ier = pio_inq_varid(ncid, name='ID', vardesc=vardesc) 197 | call pio_read_darray(ncid, vardesc, iodesc_int, this%ID0, ier) 198 | if (mainproc) write(iulog,'(2A,2i10)') trim(subname),' read ID0 ',minval(this%ID0),maxval(this%ID0) 199 | 200 | allocate(this%dnID(begr:endr)) 201 | ier = pio_inq_varid(ncid, name='dnID', vardesc=vardesc) 202 | call pio_read_darray(ncid, vardesc, iodesc_int, this%dnID, ier) 203 | if (mainproc) write(iulog,'(2A,2i10)') trim(subname),' read dnID ',minval(this%dnID),maxval(this%dnID) 204 | 205 | ! RESET ID0 and dnID indices using the IDkey to be consistent with standard gindex order 206 | do n=begr, endr 207 | this%ID0(n) = IDkey(this%ID0(n)) 208 | if (this%dnID(n) > 0 .and. this%dnID(n) <= nlon*nlat) then 209 | if (IDkey(this%dnID(n)) > 0 .and. IDkey(this%dnID(n)) <= nlon*nlat) then 210 | this%dnID(n) = IDkey(this%dnID(n)) 211 | else 212 | write(iulog,*) subname,' ERROR bad IDkey for this%dnID',n,this%dnID(n),IDkey(this%dnID(n)) 213 | call shr_sys_abort(subname//' ERROR bad IDkey for this%dnID') 214 | endif 215 | endif 216 | enddo 217 | 218 | allocate(this%area(begr:endr)) 219 | ier = pio_inq_varid(ncid, name='area', vardesc=vardesc) 220 | call pio_read_darray(ncid, vardesc, iodesc_dbl, this%area, ier) 221 | if (mainproc) write(iulog,FORMR) trim(subname),' read area ',minval(this%area),maxval(this%area) 222 | 223 | do n=begr, endr 224 | if (this%area(n) < 0._r8) this%area(n) = area(n) 225 | if (this%area(n) /= area(n)) then 226 | write(iulog,*) subname,' ERROR area mismatch',this%area(n),area(n) 227 | call shr_sys_abort(subname//' ERROR area mismatch') 228 | endif 229 | enddo 230 | 231 | allocate(this%areaTotal(begr:endr)) 232 | ier = pio_inq_varid(ncid, name='areaTotal', vardesc=vardesc) 233 | call pio_read_darray(ncid, vardesc, iodesc_dbl, this%areaTotal, ier) 234 | if (mainproc) write(iulog,FORMR) trim(subname),' read areaTotal ',minval(this%areaTotal),maxval(this%areaTotal) 235 | 236 | allocate(this%rlenTotal(begr:endr)) 237 | this%rlenTotal = 0._r8 238 | 239 | allocate(this%nh(begr:endr)) 240 | ier = pio_inq_varid(ncid, name='nh', vardesc=vardesc) 241 | call pio_read_darray(ncid, vardesc, iodesc_dbl, this%nh, ier) 242 | if (mainproc) write(iulog,FORMR) trim(subname),' read nh ',minval(this%nh),maxval(this%nh) 243 | 244 | allocate(this%hslp(begr:endr)) 245 | ier = pio_inq_varid(ncid, name='hslp', vardesc=vardesc) 246 | call pio_read_darray(ncid, vardesc, iodesc_dbl, this%hslp, ier) 247 | if (mainproc) write(iulog,FORMR) trim(subname),' read hslp ',minval(this%hslp),maxval(this%hslp) 248 | 249 | allocate(this%hslpsqrt(begr:endr)) 250 | this%hslpsqrt = 0._r8 251 | 252 | allocate(this%gxr(begr:endr)) 253 | ier = pio_inq_varid(ncid, name='gxr', vardesc=vardesc) 254 | call pio_read_darray(ncid, vardesc, iodesc_dbl, this%gxr, ier) 255 | if (mainproc) write(iulog,FORMR) trim(subname),' read gxr ',minval(this%gxr),maxval(this%gxr) 256 | 257 | allocate(this%hlen(begr:endr)) 258 | this%hlen = 0._r8 259 | 260 | allocate(this%tslp(begr:endr)) 261 | ier = pio_inq_varid(ncid, name='tslp', vardesc=vardesc) 262 | call pio_read_darray(ncid, vardesc, iodesc_dbl, this%tslp, ier) 263 | if (mainproc) write(iulog,FORMR) trim(subname),' read tslp ',minval(this%tslp),maxval(this%tslp) 264 | 265 | allocate(this%tslpsqrt(begr:endr)) 266 | this%tslpsqrt = 0._r8 267 | 268 | allocate(this%tlen(begr:endr)) 269 | this%tlen = 0._r8 270 | 271 | allocate(this%twidth(begr:endr)) 272 | ier = pio_inq_varid(ncid, name='twid', vardesc=vardesc) 273 | call pio_read_darray(ncid, vardesc, iodesc_dbl, this%twidth, ier) 274 | if (mainproc) write(iulog,FORMR) trim(subname),' read twidth ',minval(this%twidth),maxval(this%twidth) 275 | 276 | ! save twidth before adjusted below 277 | allocate(this%twidth0(begr:endr)) 278 | this%twidth0(begr:endr)=this%twidth(begr:endr) 279 | 280 | allocate(this%nt(begr:endr)) 281 | ier = pio_inq_varid(ncid, name='nt', vardesc=vardesc) 282 | call pio_read_darray(ncid, vardesc, iodesc_dbl, this%nt, ier) 283 | if (mainproc) write(iulog,FORMR) trim(subname),' read nt ',minval(this%nt),maxval(this%nt) 284 | 285 | allocate(this%rlen(begr:endr)) 286 | ier = pio_inq_varid(ncid, name='rlen', vardesc=vardesc) 287 | call pio_read_darray(ncid, vardesc, iodesc_dbl, this%rlen, ier) 288 | if (mainproc) write(iulog,FORMR) trim(subname),' read rlen ',minval(this%rlen),maxval(this%rlen) 289 | 290 | allocate(this%rslp(begr:endr)) 291 | ier = pio_inq_varid(ncid, name='rslp', vardesc=vardesc) 292 | call pio_read_darray(ncid, vardesc, iodesc_dbl, this%rslp, ier) 293 | if (mainproc) write(iulog,FORMR) trim(subname),' read rslp ',minval(this%rslp),maxval(this%rslp) 294 | 295 | allocate(this%rslpsqrt(begr:endr)) 296 | this%rslpsqrt = 0._r8 297 | 298 | allocate(this%rwidth(begr:endr)) 299 | ier = pio_inq_varid(ncid, name='rwid', vardesc=vardesc) 300 | call pio_read_darray(ncid, vardesc, iodesc_dbl, this%rwidth, ier) 301 | if (mainproc) write(iulog,FORMR) trim(subname),' read rwidth ',minval(this%rwidth),maxval(this%rwidth) 302 | 303 | allocate(this%rwidth0(begr:endr)) 304 | ier = pio_inq_varid(ncid, name='rwid0', vardesc=vardesc) 305 | call pio_read_darray(ncid, vardesc, iodesc_dbl, this%rwidth0, ier) 306 | if (mainproc) write(iulog,FORMR) trim(subname),' read rwidth0 ',minval(this%rwidth0),maxval(this%rwidth0) 307 | 308 | allocate(this%rdepth(begr:endr)) 309 | ier = pio_inq_varid(ncid, name='rdep', vardesc=vardesc) 310 | call pio_read_darray(ncid, vardesc, iodesc_dbl, this%rdepth, ier) 311 | if (mainproc) write(iulog,FORMR) trim(subname),' read rdepth ',minval(this%rdepth),maxval(this%rdepth) 312 | 313 | allocate(this%nr(begr:endr)) 314 | ier = pio_inq_varid(ncid, name='nr', vardesc=vardesc) 315 | call pio_read_darray(ncid, vardesc, iodesc_dbl, this%nr, ier) 316 | if (mainproc) write(iulog,FORMR) trim(subname),' read nr ',minval(this%nr),maxval(this%nr) 317 | 318 | allocate(this%nUp(begr:endr)) 319 | this%nUp = 0 320 | allocate(this%iUp(begr:endr,8)) 321 | this%iUp = 0 322 | allocate(this%indexDown(begr:endr)) 323 | this%indexDown = 0 324 | 325 | ! control parameters and some other derived parameters 326 | ! estimate derived input variables 327 | 328 | ! add minimum value to rlen (length of main channel); rlen values can 329 | ! be too small, leading to tlen values that are too large 330 | 331 | do n=begr,endr 332 | rlen_min = sqrt(this%area(n)) 333 | if(this%rlen(n) < rlen_min) then 334 | this%rlen(n) = rlen_min 335 | end if 336 | end do 337 | 338 | do n=begr,endr 339 | if(this%Gxr(n) > 0._r8) then 340 | this%rlenTotal(n) = this%area(n)*this%Gxr(n) 341 | end if 342 | end do 343 | 344 | do n=begr,endr 345 | if(this%rlen(n) > this%rlenTotal(n)) then 346 | this%rlenTotal(n) = this%rlen(n) 347 | end if 348 | end do 349 | 350 | do n=begr,endr 351 | 352 | if(this%rlen(n) > 0._r8) then 353 | this%hlen(n) = this%area(n) / this%rlenTotal(n) / 2._r8 354 | 355 | ! constrain hlen (hillslope length) values based on cell area 356 | hlen_max = max(1000.0_r8, sqrt(this%area(n))) 357 | if(this%hlen(n) > hlen_max) then 358 | this%hlen(n) = hlen_max ! allievate the outlier in drainag\e density estimation. TO DO 359 | end if 360 | 361 | this%tlen(n) = this%area(n) / this%rlen(n) / 2._r8 - this%hlen(n) 362 | 363 | if (this%twidth(n) < 0._r8) then 364 | this%twidth(n) = 0._r8 365 | end if 366 | if ( this%tlen(n) > 0._r8 .and. & 367 | (this%rlenTotal(n)-this%rlen(n))/this%tlen(n) > 1._r8 ) then 368 | this%twidth(n) = c_twid(n)*this%twidth(n) * & 369 | ((this%rlenTotal(n)-this%rlen(n))/this%tlen(n)) 370 | end if 371 | if (this%tlen(n) > 0._r8 .and. this%twidth(n) <= 0._r8) then 372 | this%twidth(n) = 0._r8 373 | end if 374 | else 375 | this%hlen(n) = 0._r8 376 | this%tlen(n) = 0._r8 377 | this%twidth(n) = 0._r8 378 | end if 379 | if(this%rslp(n) <= 0._r8) then 380 | this%rslp(n) = 0.0001_r8 381 | end if 382 | if(this%tslp(n) <= 0._r8) then 383 | this%tslp(n) = 0.0001_r8 384 | end if 385 | if(this%hslp(n) <= 0._r8) then 386 | this%hslp(n) = 0.005_r8 387 | end if 388 | 389 | this%rslpsqrt(n) = sqrt(this%rslp(n)) 390 | this%tslpsqrt(n) = sqrt(this%tslp(n)) 391 | this%hslpsqrt(n) = sqrt(this%hslp(n)) 392 | end do 393 | 394 | call pio_freedecomp(ncid, iodesc_dbl) 395 | call pio_freedecomp(ncid, iodesc_int) 396 | call pio_closefile(ncid) 397 | 398 | ! Create srcfield and dstfield - needed for mapping 399 | this%srcfield = ESMF_FieldCreate(EMesh, ESMF_TYPEKIND_R8, meshloc=ESMF_MESHLOC_ELEMENT, & 400 | ungriddedLBound=(/1/), ungriddedUBound=(/ntracers/), gridToFieldMap=(/2/), rc=rc) 401 | if (chkerr(rc,__LINE__,u_FILE_u)) return 402 | 403 | this%dstfield = ESMF_FieldCreate(EMesh, ESMF_TYPEKIND_R8, meshloc=ESMF_MESHLOC_ELEMENT, & 404 | ungriddedLBound=(/1/), ungriddedUBound=(/ntracers/), gridToFieldMap=(/2/), rc=rc) 405 | if (chkerr(rc,__LINE__,u_FILE_u)) return 406 | 407 | ! Create route handles 408 | call this%set_routehandles(begr, endr, gindex, outletg, rc) 409 | if (chkerr(rc,__LINE__,u_FILE_u)) return 410 | 411 | ! Compute areatotal2 412 | ! this basically advects upstream areas downstream and 413 | ! adds them up as it goes until all upstream areas are accounted for 414 | allocate(this%areatotal2(begr:endr)) 415 | call this%set_areatotal2(begr, endr, nlon, nlat, area, rc) 416 | if (chkerr(rc,__LINE__,u_FILE_u)) return 417 | 418 | ! Determine subcycling time steps 419 | allocate(this%numDT_r(begr:endr)) 420 | allocate(this%numDT_t(begr:endr)) 421 | allocate(this%phi_r(begr:endr)) 422 | allocate(this%phi_t(begr:endr)) 423 | call this%set_subtimesteps(begr, endr, DLevelR) 424 | 425 | end subroutine Init 426 | 427 | !----------------------------------------------------------------------- 428 | 429 | subroutine set_routehandles(this, begr, endr, gindex, outletg, rc) 430 | 431 | ! Arguments 432 | class(Tspatialunit_type) :: this 433 | integer , intent(in) :: begr, endr 434 | integer , intent(in) :: gindex(begr:endr) 435 | integer , intent(in) :: outletg(begr:endr) 436 | integer , intent(out) :: rc 437 | 438 | ! Local variables 439 | integer :: nn, n, cnt, nr, nt 440 | real(r8), pointer :: src_direct(:,:) 441 | real(r8), pointer :: dst_direct(:,:) 442 | real(r8), pointer :: src_eroutUp(:,:) 443 | real(r8), pointer :: dst_eroutUp(:,:) 444 | real(r8), allocatable :: factorList(:) 445 | integer , allocatable :: factorIndexList(:,:) 446 | integer :: srcTermProcessing_Value = 0 447 | !-------------------------------------------------------------------------- 448 | 449 | rc = ESMF_SUCCESS 450 | 451 | ! --------------------------------------- 452 | ! Calculate map for direct to outlet mapping 453 | ! --------------------------------------- 454 | 455 | ! Set up pointer arrays into srcfield and dstfield 456 | call ESMF_FieldGet(this%srcfield, farrayPtr=src_direct, rc=rc) 457 | if (chkerr(rc,__LINE__,u_FILE_u)) return 458 | call ESMF_FieldGet(this%dstfield, farrayPtr=dst_direct, rc=rc) 459 | if (chkerr(rc,__LINE__,u_FILE_u)) return 460 | src_direct(:,:) = 0._r8 461 | dst_direct(:,:) = 0._r8 462 | 463 | ! The route handle rh_direct will then be used in mosart_run 464 | cnt = endr - begr + 1 465 | allocate(factorList(cnt)) 466 | allocate(factorIndexList(2,cnt)) 467 | cnt = 0 468 | do nr = begr,endr 469 | cnt = cnt + 1 470 | if (outletg(nr) > 0) then 471 | factorList(cnt) = 1.0_r8 472 | factorIndexList(1,cnt) = gindex(nr) 473 | factorIndexList(2,cnt) = outletg(nr) 474 | else 475 | factorList(cnt) = 1.0_r8 476 | factorIndexList(1,cnt) = gindex(nr) 477 | factorIndexList(2,cnt) = gindex(nr) 478 | endif 479 | enddo 480 | 481 | call ESMF_FieldSMMStore(this%srcField, this%dstField, this%rh_direct, factorList, factorIndexList, & 482 | ignoreUnmatchedIndices=.true., srcTermProcessing=srcTermProcessing_Value, rc=rc) 483 | if (chkerr(rc,__LINE__,u_FILE_u)) return 484 | 485 | deallocate(factorList) 486 | deallocate(factorIndexList) 487 | 488 | if (mainproc) write(iulog,*) " Done initializing rh_direct " 489 | 490 | ! --------------------------------------- 491 | ! Compute map rh_eroutUp 492 | ! --------------------------------------- 493 | 494 | ! Set up pointer arrays into srcfield and dstfield 495 | call ESMF_FieldGet(this%srcfield, farrayPtr=src_eroutUp, rc=rc) 496 | if (chkerr(rc,__LINE__,u_FILE_u)) return 497 | call ESMF_FieldGet(this%dstfield, farrayPtr=dst_eroutUp, rc=rc) 498 | if (chkerr(rc,__LINE__,u_FILE_u)) return 499 | src_eroutUp(:,:) = 0._r8 500 | dst_eroutUp(:,:) = 0._r8 501 | 502 | cnt = 0 503 | do nr = begr,endr 504 | if (this%dnID(nr) > 0) then 505 | cnt = cnt + 1 506 | end if 507 | end do 508 | allocate(factorList(cnt)) 509 | allocate(factorIndexList(2,cnt)) 510 | cnt = 0 511 | do nr = begr,endr 512 | if (this%dnID(nr) > 0) then 513 | cnt = cnt + 1 514 | factorList(cnt) = 1.0_r8 515 | factorIndexList(1,cnt) = this%ID0(nr) 516 | factorIndexList(2,cnt) = this%dnID(nr) 517 | endif 518 | enddo 519 | if (mainproc) write(iulog,*) " Done initializing rh_eroutUp" 520 | 521 | call ESMF_FieldSMMStore(this%srcfield, this%dstfield, this%rh_eroutUp, factorList, factorIndexList, & 522 | ignoreUnmatchedIndices=.true., srcTermProcessing=srcTermProcessing_Value, rc=rc) 523 | if (chkerr(rc,__LINE__,u_FILE_u)) return 524 | 525 | deallocate(factorList) 526 | deallocate(factorIndexList) 527 | 528 | end subroutine set_routehandles 529 | 530 | !----------------------------------------------------------------------- 531 | 532 | subroutine set_areatotal2(this, begr, endr, nlon, nlat, area, rc) 533 | 534 | ! Arguments 535 | class(Tspatialunit_type) :: this 536 | integer , intent(in) :: begr, endr 537 | integer , intent(in) :: nlon,nlat 538 | real(r8) , intent(in) :: area(begr:endr) 539 | integer , intent(out) :: rc 540 | 541 | ! Local variables 542 | integer :: nr, cnt, tcnt ! indices 543 | real(r8) :: areatot_prev, areatot_tmp, areatot_new 544 | real(r8), pointer :: src_direct(:,:) 545 | real(r8), pointer :: dst_direct(:,:) 546 | real(r8), pointer :: src_eroutUp(:,:) 547 | real(r8), pointer :: dst_eroutUp(:,:) 548 | character(len=*),parameter :: subname = '(mosart_tspatialunit_type_set_areatotal2) ' 549 | ! -------------------------------------------------------------- 550 | 551 | rc = ESMF_SUCCESS 552 | 553 | ! --------------------------------------- 554 | ! compute areatot from area using dnID 555 | ! --------------------------------------- 556 | 557 | ! Set up pointer arrays into srcfield and dstfield 558 | call ESMF_FieldGet(this%srcfield, farrayPtr=src_eroutUp, rc=rc) 559 | if (chkerr(rc,__LINE__,u_FILE_u)) return 560 | call ESMF_FieldGet(this%dstfield, farrayPtr=dst_eroutUp, rc=rc) 561 | if (chkerr(rc,__LINE__,u_FILE_u)) return 562 | src_eroutUp(:,:) = 0._r8 563 | dst_eroutUp(:,:) = 0._r8 564 | 565 | ! this basically advects upstream areas downstream and 566 | ! adds them up as it goes until all upstream areas are accounted for 567 | 568 | this%areatotal2(:) = 0._r8 569 | 570 | ! initialize dst_eroutUp to local area and add that to areatotal2 571 | cnt = 0 572 | dst_eroutUp(:,:) = 0._r8 573 | do nr = begr,endr 574 | cnt = cnt + 1 575 | dst_eroutUp(1,cnt) = area(nr) 576 | this%areatotal2(nr) = area(nr) 577 | enddo 578 | 579 | tcnt = 0 580 | areatot_prev = -99._r8 581 | areatot_new = -50._r8 582 | do while (areatot_new /= areatot_prev .and. tcnt < nlon*nlat) 583 | 584 | tcnt = tcnt + 1 585 | 586 | ! copy dst_eroutUp to src_eroutUp for next downstream step 587 | src_eroutUp(:,:) = 0._r8 588 | cnt = 0 589 | do nr = begr,endr 590 | cnt = cnt + 1 591 | src_eroutUp(1,cnt) = dst_eroutUp(1,cnt) 592 | enddo 593 | 594 | dst_eroutUp(:,:) = 0._r8 595 | call ESMF_FieldSMM(this%srcfield, this%dstField, this%rh_eroutUp, termorderflag=ESMF_TERMORDER_SRCSEQ, rc=rc) 596 | if (chkerr(rc,__LINE__,u_FILE_u)) return 597 | 598 | ! add dst_eroutUp to areatot and compute new global sum 599 | cnt = 0 600 | areatot_prev = areatot_new 601 | areatot_tmp = 0._r8 602 | do nr = begr,endr 603 | cnt = cnt + 1 604 | this%areatotal2(nr) = this%areatotal2(nr) + dst_eroutUp(1,cnt) 605 | areatot_tmp = areatot_tmp + this%areatotal2(nr) 606 | enddo 607 | call shr_mpi_sum(areatot_tmp, areatot_new, mpicom_rof, 'areatot_new', all=.true.) 608 | 609 | if (mainproc) then 610 | write(iulog,*) trim(subname),' areatot calc ',tcnt,areatot_new 611 | endif 612 | enddo 613 | 614 | if (areatot_new /= areatot_prev) then 615 | write(iulog,*) trim(subname),' MOSART ERROR: areatot incorrect ',areatot_new, areatot_prev 616 | call shr_sys_abort(trim(subname)//' MOSART ERROR areatot incorrect') 617 | endif 618 | 619 | end subroutine set_areatotal2 620 | 621 | !----------------------------------------------------------------------- 622 | 623 | subroutine set_subtimesteps(this, begr, endr, DLevelR) 624 | 625 | ! Set the sub-time-steps for channel routing 626 | 627 | ! Arguments 628 | class(Tspatialunit_type) :: this 629 | integer, intent(in) :: begr, endr 630 | integer, intent(in) :: DLevelR 631 | 632 | ! Local variables 633 | integer :: nr !local index 634 | integer :: numDT_r, numDT_t 635 | character(len=*),parameter :: subname = '(mosart_tspatialunit_type_subtimestep) ' 636 | ! -------------------------------------------------------------- 637 | 638 | this%numDT_r(:) = 1 639 | this%numDT_t(:) = 1 640 | this%phi_r(:) = 0._r8 641 | this%phi_t(:) = 0._r8 642 | 643 | do nr = begr,endr 644 | if (this%mask(nr) > 0 .and. this%rlen(nr) > 0._r8) then 645 | this%phi_r(nr) = this%areaTotal2(nr)*sqrt(this%rslp(nr))/(this%rlen(nr)*this%rwidth(nr)) 646 | if (this%phi_r(nr) >= 10._r8) then 647 | this%numDT_r(nr) = (this%numDT_r(nr)*log10(this%phi_r(nr))*DLevelR) + 1 648 | else 649 | this%numDT_r(nr) = this%numDT_r(nr)*1.0_r8*DLevelR + 1 650 | end if 651 | end if 652 | if (this%numDT_r(nr) < 1) this%numDT_r(nr) = 1 653 | 654 | if (this%tlen(nr) > 0._r8) then 655 | this%phi_t(nr) = this%area(nr)*sqrt(this%tslp(nr))/(this%tlen(nr)*this%twidth(nr)) 656 | if (this%phi_t(nr) >= 10._r8) then 657 | this%numDT_t(nr) = (this%numDT_t(nr)*log10(this%phi_t(nr))*DLevelR) + 1 658 | else 659 | this%numDT_t(nr) = (this%numDT_t(nr)*1.0*DLevelR) + 1 660 | end if 661 | end if 662 | if (this%numDT_t(nr) < 1) this%numDT_t(nr) = 1 663 | end do 664 | 665 | call shr_mpi_max(maxval(this%numDT_r),numDT_r,mpicom_rof,'numDT_r',all=.false.) 666 | call shr_mpi_max(maxval(this%numDT_t),numDT_t,mpicom_rof,'numDT_t',all=.false.) 667 | if (mainproc) then 668 | write(iulog,*) subname,' DLevelR = ',DlevelR 669 | write(iulog,*) subname,' numDT_r = ',minval(this%numDT_r),maxval(this%numDT_r) 670 | write(iulog,*) subname,' numDT_r max = ',numDT_r 671 | write(iulog,*) subname,' numDT_t = ',minval(this%numDT_t),maxval(this%numDT_t) 672 | write(iulog,*) subname,' numDT_t max = ',numDT_t 673 | endif 674 | 675 | end subroutine set_subtimesteps 676 | 677 | end module mosart_tspatialunit_type 678 | -------------------------------------------------------------------------------- /src/riverroute/mosart_tstatusflux_type.F90: -------------------------------------------------------------------------------- 1 | module mosart_tstatusflux_type 2 | 3 | ! status and flux variables 4 | 5 | use shr_kind_mod, only : r8 => shr_kind_r8, CL => SHR_KIND_CL 6 | 7 | implicit none 8 | private 9 | 10 | public :: TstatusFlux_type 11 | type TstatusFlux_type 12 | ! hillsloope 13 | !! states 14 | real(r8), pointer :: wh(:,:) ! storage of surface water, [m] 15 | real(r8), pointer :: dwh(:,:) ! change of water storage, [m/s] 16 | real(r8), pointer :: yh(:,:) ! depth of surface water, [m] 17 | real(r8), pointer :: wsat(:,:) ! storage of surface water within saturated area at hillslope [m] 18 | real(r8), pointer :: wunsat(:,:) ! storage of surface water within unsaturated area at hillslope [m] 19 | real(r8), pointer :: qhorton(:,:) ! Infiltration excess runoff generated from hillslope, [m/s] NOT_USED 20 | real(r8), pointer :: qdunne(:,:) ! Saturation excess runoff generated from hillslope, [m/s] NOT_USED 21 | real(r8), pointer :: qsur(:,:) ! Surface runoff generated from hillslope, [m/s] 22 | real(r8), pointer :: qsub(:,:) ! Subsurface runoff generated from hillslope, [m/s] 23 | real(r8), pointer :: qgwl(:,:) ! gwl runoff term from glacier, wetlands and lakes, [m/s] 24 | !! fluxes 25 | real(r8), pointer :: ehout(:,:) ! overland flow from hillslope into the sub-channel, [m/s] 26 | real(r8), pointer :: asat(:,:) ! saturated area fraction from hillslope, [-] 27 | real(r8), pointer :: esat(:,:) ! evaporation from saturated area fraction at hillslope, [m/s] 28 | 29 | ! subnetwork channel 30 | !! states 31 | real(r8), pointer :: tarea(:,:) ! area of channel water surface, [m2] 32 | real(r8), pointer :: wt(:,:) ! storage of surface water, [m3] 33 | real(r8), pointer :: dwt(:,:) ! change of water storage, [m3] 34 | real(r8), pointer :: yt(:,:) ! water depth, [m] 35 | real(r8), pointer :: mt(:,:) ! cross section area, [m2] 36 | real(r8), pointer :: rt(:,:) ! hydraulic radii, [m] 37 | real(r8), pointer :: pt(:,:) ! wetness perimeter, [m] 38 | real(r8), pointer :: vt(:,:) ! flow velocity, [m/s] 39 | real(r8), pointer :: tt(:,:) ! mean travel time of the water within the channel, [s] NOT_USED 40 | !! fluxes 41 | real(r8), pointer :: etin(:,:) ! lateral inflow from hillslope, including surface and subsurface runoff generation components, [m3/s] 42 | real(r8), pointer :: etout(:,:) ! discharge from sub-network into the main reach, [m3/s] 43 | 44 | ! main channel 45 | !! states 46 | real(r8), pointer :: rarea(:,:) ! area of channel water surface, [m2] 47 | real(r8), pointer :: wr(:,:) ! storage of surface water, [m3] 48 | real(r8), pointer :: dwr(:,:) ! change of water storage, [m3] 49 | real(r8), pointer :: yr(:,:) ! water depth. [m] 50 | real(r8), pointer :: mr(:,:) ! cross section area, [m2] 51 | real(r8), pointer :: rr(:,:) ! hydraulic radius, [m] 52 | real(r8), pointer :: pr(:,:) ! wetness perimeter, [m] 53 | real(r8), pointer :: vr(:,:) ! flow velocity, [m/s] 54 | real(r8), pointer :: tr(:,:) ! mean travel time of the water within the channel, [s] NOT_USED 55 | !! exchange fluxes 56 | real(r8), pointer :: erlateral(:,:) ! lateral flow from hillslope, including surface and subsurface runoff generation components, [m3/s] 57 | real(r8), pointer :: erin(:,:) ! inflow from upstream links, [m3/s] 58 | real(r8), pointer :: erout(:,:) ! outflow into downstream links, [m3/s] 59 | real(r8), pointer :: erout_prev(:,:) ! outflow into downstream links from previous timestep, [m3/s] 60 | real(r8), pointer :: eroutUp(:,:) ! outflow sum of upstream gridcells, instantaneous (m3/s) 61 | real(r8), pointer :: eroutUp_avg(:,:) ! outflow sum of upstream gridcells, average [m3/s] 62 | real(r8), pointer :: erlat_avg(:,:) ! erlateral average [m3/s] 63 | real(r8), pointer :: flow(:,:) ! streamflow from the outlet of the reach, [m3/s] 64 | real(r8), pointer :: erin1(:,:) ! inflow from upstream links during previous step, used for Muskingum method, [m3/s] NOT_USED 65 | real(r8), pointer :: erin2(:,:) ! inflow from upstream links during current step, used for Muskingum method, [m3/s] NOT_USED 66 | real(r8), pointer :: ergwl(:,:) ! flux item for the adjustment of water balance residual in glacie, wetlands and lakes dynamics [m3/s] NOT_USED 67 | 68 | !! for Runge-Kutta algorithm NOT_USED 69 | real(r8), pointer :: wrtemp(:,:) ! temporary storage item, for 4th order Runge-Kutta algorithm; 70 | real(r8), pointer :: erintemp(:,:) 71 | real(r8), pointer :: erouttemp(:,:) 72 | real(r8), pointer :: k1(:,:) 73 | real(r8), pointer :: k2(:,:) 74 | real(r8), pointer :: k3(:,:) 75 | real(r8), pointer :: k4(:,:) 76 | contains 77 | procedure, public :: Init 78 | end type TstatusFlux_type 79 | 80 | contains 81 | 82 | subroutine Init(this, begr, endr, ntracers) 83 | class(TstatusFlux_type) :: this 84 | integer, intent(in) :: begr, endr, ntracers 85 | 86 | ! Initialize water states and fluxes 87 | allocate (this%wh(begr:endr,ntracers)) 88 | this%wh = 0._r8 89 | allocate (this%dwh(begr:endr,ntracers)) 90 | this%dwh = 0._r8 91 | allocate (this%yh(begr:endr,ntracers)) 92 | this%yh = 0._r8 93 | allocate (this%qsur(begr:endr,ntracers)) 94 | this%qsur = 0._r8 95 | allocate (this%qsub(begr:endr,ntracers)) 96 | this%qsub = 0._r8 97 | allocate (this%qgwl(begr:endr,ntracers)) 98 | this%qgwl = 0._r8 99 | allocate (this%ehout(begr:endr,ntracers)) 100 | this%ehout = 0._r8 101 | allocate (this%tarea(begr:endr,ntracers)) 102 | this%tarea = 0._r8 103 | allocate (this%wt(begr:endr,ntracers)) 104 | this%wt= 0._r8 105 | allocate (this%dwt(begr:endr,ntracers)) 106 | this%dwt = 0._r8 107 | allocate (this%yt(begr:endr,ntracers)) 108 | this%yt = 0._r8 109 | allocate (this%mt(begr:endr,ntracers)) 110 | this%mt = 0._r8 111 | allocate (this%rt(begr:endr,ntracers)) 112 | this%rt = 0._r8 113 | allocate (this%pt(begr:endr,ntracers)) 114 | this%pt = 0._r8 115 | allocate (this%vt(begr:endr,ntracers)) 116 | this%vt = 0._r8 117 | allocate (this%tt(begr:endr,ntracers)) 118 | this%tt = 0._r8 119 | allocate (this%etin(begr:endr,ntracers)) 120 | this%etin = 0._r8 121 | allocate (this%etout(begr:endr,ntracers)) 122 | this%etout = 0._r8 123 | allocate (this%rarea(begr:endr,ntracers)) 124 | this%rarea = 0._r8 125 | allocate (this%wr(begr:endr,ntracers)) 126 | this%wr = 0._r8 127 | allocate (this%dwr(begr:endr,ntracers)) 128 | this%dwr = 0._r8 129 | allocate (this%yr(begr:endr,ntracers)) 130 | this%yr = 0._r8 131 | allocate (this%mr(begr:endr,ntracers)) 132 | this%mr = 0._r8 133 | allocate (this%rr(begr:endr,ntracers)) 134 | this%rr = 0._r8 135 | allocate (this%pr(begr:endr,ntracers)) 136 | this%pr = 0._r8 137 | allocate (this%vr(begr:endr,ntracers)) 138 | this%vr = 0._r8 139 | allocate (this%tr(begr:endr,ntracers)) 140 | this%tr = 0._r8 141 | allocate (this%erlateral(begr:endr,ntracers)) 142 | this%erlateral = 0._r8 143 | allocate (this%erin(begr:endr,ntracers)) 144 | this%erin = 0._r8 145 | allocate (this%erout(begr:endr,ntracers)) 146 | this%erout = 0._r8 147 | allocate (this%erout_prev(begr:endr,ntracers)) 148 | this%erout_prev = 0._r8 149 | allocate (this%eroutUp(begr:endr,ntracers)) 150 | this%eroutUp = 0._r8 151 | allocate (this%eroutUp_avg(begr:endr,ntracers)) 152 | this%eroutUp_avg = 0._r8 153 | allocate (this%erlat_avg(begr:endr,ntracers)) 154 | this%erlat_avg = 0._r8 155 | allocate (this%ergwl(begr:endr,ntracers)) 156 | this%ergwl = 0._r8 157 | allocate (this%flow(begr:endr,ntracers)) 158 | this%flow = 0._r8 159 | 160 | end subroutine Init 161 | 162 | end module mosart_tstatusflux_type 163 | -------------------------------------------------------------------------------- /src/riverroute/mosart_vars.F90: -------------------------------------------------------------------------------- 1 | module mosart_vars 2 | 3 | use shr_kind_mod , only : r8 => shr_kind_r8, CL => SHR_KIND_CL, CS => shr_kind_CS 4 | use shr_const_mod , only : SHR_CONST_CDAY,SHR_CONST_REARTH 5 | use shr_sys_mod , only : shr_sys_abort 6 | use ESMF , only : ESMF_VM 7 | 8 | implicit none 9 | public 10 | 11 | ! MPI 12 | logical :: mainproc ! proc 0 logical for printing msgs 13 | integer :: iam ! processor number 14 | integer :: npes ! number of processors for mosart 15 | integer :: mpicom_rof ! communicator group for mosart 16 | logical :: barrier_timers = .false. ! barrier timers 17 | type(ESMF_VM) :: vm ! ESMF VM 18 | 19 | ! Constants 20 | integer , parameter :: iundef = -9999999 21 | integer , parameter :: rundef = -9999999._r8 22 | real(r8) , parameter :: secspday = SHR_CONST_CDAY ! Seconds per day 23 | integer , parameter :: isecspday = secspday ! Integer seconds per day 24 | real(r8) , parameter :: spval = 1.e36_r8 ! special value for real data 25 | integer , parameter :: ispval = -9999 ! special value for int data 26 | 27 | real(r8) :: re = SHR_CONST_REARTH*0.001_r8 ! radius of earth (km) 28 | 29 | ! Run startup 30 | integer , parameter :: nsrStartup = 0 ! Startup from initial conditions 31 | integer , parameter :: nsrContinue = 1 ! Continue from restart files 32 | integer , parameter :: nsrBranch = 2 ! Branch from restart files 33 | integer :: nsrest = iundef ! Type of run 34 | 35 | ! Namelist variables 36 | character(len=CL) :: frivinp ! MOSART input data file name 37 | logical :: ice_runoff ! true => runoff is split into liquid and ice, otherwise just liquid 38 | character(len=CS) :: decomp_option ! decomp option 39 | character(len=CS) :: bypass_routing_option ! bypass routing model method 40 | character(len=CS) :: qgwl_runoff_option ! method for handling qgwl runoff 41 | integer :: budget_frq = -24 ! budget check frequency 42 | 43 | ! Metadata variables used in history and restart generation 44 | character(len=CL) :: caseid = ' ' ! case id 45 | character(len=CL) :: ctitle = ' ' ! case title 46 | character(len=CL) :: hostname = ' ' ! Hostname of machine running on 47 | character(len=CL) :: username = ' ' ! username of user running program 48 | character(len=CL) :: version = " " ! version of program 49 | character(len=CL) :: conventions = "CF-1.0" ! dataset conventions 50 | character(len=CL) :: model_doi_url ! Web address of the Digital Object Identifier (DOI) for this model version 51 | character(len=CL) :: source = "Model for Scale Adaptive River Transport MOSART1.0" ! description of this source 52 | 53 | ! Stdout 54 | integer :: iulog = 6 ! "stdout" log file unit number, default is 6 55 | 56 | ! Instance control 57 | integer :: inst_index 58 | character(len=CS) :: inst_name 59 | character(len=CS) :: inst_suffix 60 | 61 | end module mosart_vars 62 | --------------------------------------------------------------------------------