• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

payu-org / payu / 12288631034

12 Dec 2024 02:24AM UTC coverage: 58.979% (+0.5%) from 58.509%
12288631034

Pull #539

github

web-flow
Merge 9135f89bd into da047828f
Pull Request #539: Check CICE4 restart file dates

57 of 62 new or added lines in 3 files covered. (91.94%)

32 existing lines in 2 files now uncovered.

2910 of 4934 relevant lines covered (58.98%)

1.77 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

71.7
/payu/models/access.py
1
# coding: utf-8
2
"""
3✔
3
The payu interface for the ACCESS coupled climate model
4
-------------------------------------------------------------------------------
5
Contact: Marshall Ward <marshall.ward@anu.edu.au>
6
-------------------------------------------------------------------------------
7
Distributed as part of Payu, Copyright 2011 Marshall Ward
8
Licensed under the Apache License, Version 2.0
9
http://www.apache.org/licenses/LICENSE-2.0
10
"""
11
from __future__ import print_function
3✔
12

13
# Standard Library
14
import errno
3✔
15
import os
3✔
16
import re
3✔
17
import shutil
3✔
18
import sys
3✔
19

20
# Extensions
21
import f90nml
3✔
22

23
# Local
24
from payu.fsops import make_symlink
3✔
25
from payu.models.model import Model
3✔
26
from payu.models.mom import get_restart_datetime_using_mom_submodel
3✔
27
import payu.calendar as cal
3✔
28

29

30
class Access(Model):
3✔
31

32
    def __init__(self, expt, name, config):
3✔
33
        super(Access, self).__init__(expt, name, config)
3✔
34

35
        self.model_type = 'access'
3✔
36

37
        for model in self.expt.models:
3✔
38
            if model.model_type == 'cice' or model.model_type == 'cice5':
3✔
39
                model.config_files = ['cice_in.nml',
3✔
40
                                      'input_ice.nml']
41
                model.optional_config_files = ['input_ice_gfdl.nml',
3✔
42
                                               'input_ice_monin.nml']
43

44
                model.ice_nml_fname = 'cice_in.nml'
3✔
45

46
                model.access_restarts = ['mice.nc']
3✔
47
                model.copy_restarts = True
3✔
48

49
                model.set_timestep = model.set_access_timestep
3✔
50

51
            if model.model_type == 'cice5':
3✔
52
                model.access_restarts.extend(['u_star.nc', 'sicemass.nc'])
×
53

54
            if model.model_type == 'cice':
3✔
55
                # The ACCESS build of CICE assumes that restart_dir is 'RESTART'
56
                model.get_ptr_restart_dir = lambda : '.'
3✔
57

58
                # Structure of model coupling namelist
59
                model.cpl_fname = 'input_ice.nml'
3✔
60
                model.cpl_group = 'coupling'
3✔
61
                model.start_date_nml_name = "restart_date.nml"
3✔
62
                # Experiment initialisation date
63
                model.init_date_key = "init_date"
3✔
64
                # Start date for new run
65
                model.inidate_key = "inidate"
3✔
66
                # Total time in seconds since initialisation date
67
                model.runtime0_key = 'runtime0'
3✔
68
                # Simulation length in seconds for new run
69
                model.runtime_key = "runtime"
3✔
70

71
            if model.model_type == 'matm':
3✔
72
                # Structure of model coupling namelist
73
                model.cpl_fname = 'input_atm.nml'
×
74
                model.cpl_group = 'coupling'
×
75
                model.start_date_nml_name = "restart_date.nml"
×
76
                # Experiment initialisation date
77
                model.init_date_key = "init_date"
×
78
                # Start date for new run
79
                model.inidate_key = "inidate"
×
80
                # Total time in seconds since initialisation date
81
                model.runtime0_key = 'truntime0'
×
82
                # Simulation length in seconds for new run
83
                model.runtime_key = "runtime"
×
84

85

86
    def setup(self):
3✔
87
        if not self.top_level_model:
3✔
88
            return
×
89

90
        # Keep track of this in order to set the oasis runtime.
91
        run_runtime = 0
3✔
92

93
        for model in self.expt.models:
3✔
94

95
            if model.model_type == 'cice' or model.model_type == 'cice5':
3✔
96

97
                # Horrible hack to make a link to o2i.nc in the
98
                # work/ice/RESTART directory
99
                f_name = 'o2i.nc'
3✔
100
                f_src = os.path.join(model.work_path, f_name)
3✔
101
                f_dst = os.path.join(model.work_restart_path, f_name)
3✔
102

103
                if os.path.isfile(f_src):
3✔
104
                    make_symlink(f_src, f_dst)
×
105

106
            if model.model_type == 'cice5':
3✔
107

108
                # Stage the supplemental input files
109
                if model.prior_restart_path:
×
110
                    for f_name in model.access_restarts:
×
111
                        f_src = os.path.join(model.prior_restart_path, f_name)
×
112
                        f_dst = os.path.join(model.work_input_path, f_name)
×
113

114
                        if os.path.isfile(f_src):
×
115
                            make_symlink(f_src, f_dst)
×
116

117
            if model.model_type in ('cice', 'matm'):
3✔
118

119
                # Update the supplemental OASIS namelists
120

121
                # cpl_nml is the coupling namelist copied from the control to
122
                # work directory.
123
                cpl_fpath = os.path.join(model.work_path, model.cpl_fname)
3✔
124
                cpl_nml = f90nml.read(cpl_fpath)
3✔
125
                cpl_group = cpl_nml[model.cpl_group]
3✔
126

127
                # Which calendar are we using, noleap or Gregorian.
128
                caltype = cpl_group['caltype']
3✔
129

130
                # Get timing information for the new run.
131
                if model.prior_restart_path and not self.expt.repeat_run:
3✔
132
                    # Read the start date from the restart date namelist.
133
                    start_date_fpath = os.path.join(
3✔
134
                        model.prior_restart_path,
135
                        model.start_date_nml_name
136
                    )
137

138
                    try:
3✔
139
                        start_date_nml = f90nml.read(start_date_fpath)[
3✔
140
                            model.cpl_group]
141
                    except FileNotFoundError:
×
142
                        print(
×
143
                            "Missing restart date file for model "
144
                            f"{model.model_type}",
145
                            file=sys.stderr
146
                        )
147
                        raise
×
148

149
                    # Experiment initialisation date
150
                    init_date = cal.int_to_date(
3✔
151
                        start_date_nml[model.init_date_key]
152
                    )
153

154
                    # Start date of new run
155
                    run_start_date = cal.int_to_date(
3✔
156
                        start_date_nml[model.inidate_key]
157
                    )
158

159
                    # run_start_date must be after initialisation date
160
                    if run_start_date < init_date:
3✔
161
                        msg = (
×
162
                            "Restart date 'inidate` in "
163
                            f"{model.start_date_nml_name} must not be "
164
                            "before initialisation date `init_date. "
165
                            "Values provided: \n"
166
                            f"inidate={start_date_nml[model.inidate_key]}\n"
167
                            f"init_date={start_date_nml[model.init_date_key]}"
168
                        )
169
                        raise ValueError(msg)
×
170

171
                    # Calculate the total number of seconds between the
172
                    # initialisation and new run start date,
173
                    # to use for the runtime0 field.
174
                    previous_runtime = cal.seconds_between_dates(
3✔
175
                        init_date,
176
                        run_start_date,
177
                        caltype
178
                    )
179

180
                else:
181
                    init_date = cal.int_to_date(
×
182
                        cpl_group[model.init_date_key]
183
                    )
184
                    previous_runtime = 0
×
185
                    run_start_date = init_date
×
186

187
                # Get new runtime for this run. We get this from either the
188
                # 'runtime' part of the payu config, or from the namelist
189
                if self.expt.runtime:
3✔
190
                    run_runtime = cal.runtime_from_date(
3✔
191
                        run_start_date,
192
                        self.expt.runtime['years'],
193
                        self.expt.runtime['months'],
194
                        self.expt.runtime['days'],
195
                        self.expt.runtime.get('seconds', 0),
196
                        caltype)
197
                else:
198
                    run_runtime = cpl_group[model.runtime_key]
×
199

200
                # Now write out new run start date and total runtime into the
201
                # work directory namelist.
202
                cpl_group[model.init_date_key] = cal.date_to_int(init_date)
3✔
203
                cpl_group[model.inidate_key] = cal.date_to_int(run_start_date)
3✔
204
                cpl_group[model.runtime0_key] = previous_runtime
3✔
205
                cpl_group[model.runtime_key] = int(run_runtime)
3✔
206

207
                if model.model_type == 'cice':
3✔
208
                    if self.expt.counter and not self.expt.repeat_run:
3✔
209
                        cpl_group['jobnum'] = (
×
210
                            1 + self.expt.counter
211
                        )
212
                    else:
213
                        cpl_group['jobnum'] = 1
3✔
214

215
                nml_work_path = os.path.join(model.work_path, model.cpl_fname)
3✔
216

217
                # TODO: Does this need to be split into two steps?
218
                f90nml.write(cpl_nml, nml_work_path + '~')
3✔
219
                shutil.move(nml_work_path + '~', nml_work_path)
3✔
220

221
            if model.model_type == 'cice':
3✔
222
                if model.prior_restart_path and not self.expt.repeat_run:
3✔
223
                    # Set up and check the cice restart files.
224
                    model.overwrite_restart_ptr(run_start_date,
3✔
225
                                                previous_runtime,
226
                                                start_date_fpath)
227

228
        # Now change the oasis runtime. This needs to be done after the others.
229
        for model in self.expt.models:
3✔
230
            if model.model_type == 'oasis':
3✔
231
                namcouple = os.path.join(model.work_path, 'namcouple')
×
232

233
                s = ''
×
234
                with open(namcouple, 'r+') as f:
×
235
                    s = f.read()
×
236
                    m = re.search(r"^[ \t]*\$RUNTIME.*?^[ \t]*(\d+)", s,
×
237
                                  re.MULTILINE | re.DOTALL)
238
                    assert (m is not None)
×
239
                    s = s[:m.start(1)] + str(run_runtime) + s[m.end(1):]
×
240

241
                with open(namcouple, 'w') as f:
×
242
                    f.write(s)
×
243

244
    def archive(self):
3✔
245
        if not self.top_level_model:
3✔
246
            return
×
247

248
        cice5 = None
3✔
249
        mom = None
3✔
250

251
        for model in self.expt.models:
3✔
252
            if model.model_type in ('cice', 'matm'):
3✔
253
                # Write the simulation end date to the restart date
254
                # namelist.
255

256
                # Calculate the end date using information from the work
257
                # directory coupling namelist.
258
                work_cpl_fpath = os.path.join(model.work_path, model.cpl_fname)
3✔
259
                work_cpl_nml = f90nml.read(work_cpl_fpath)
3✔
260
                work_cpl_grp = work_cpl_nml[model.cpl_group]
3✔
261

262
                # Timing information on the completed run.
263
                exp_init_date_int = work_cpl_grp[model.init_date_key]
3✔
264
                run_start_date_int = work_cpl_grp[model.inidate_key]
3✔
265
                run_runtime = work_cpl_grp[model.runtime_key]
3✔
266
                run_caltype = work_cpl_grp["caltype"]
3✔
267

268
                # Calculate end date of completed run
269
                run_end_date = cal.date_plus_seconds(
3✔
270
                    cal.int_to_date(run_start_date_int),
271
                    run_runtime,
272
                    run_caltype
273
                )
274

275
                end_date_dict = {
3✔
276
                    model.cpl_group: {
277
                        model.init_date_key: exp_init_date_int,
278
                        model.inidate_key: cal.date_to_int(run_end_date)
279
                    }
280
                }
281

282
                # Write restart date to the restart directory
283
                end_date_path = os.path.join(model.restart_path,
3✔
284
                                             model.start_date_nml_name)
285
                f90nml.write(end_date_dict, end_date_path, force=True)
3✔
286

287
            if model.model_type == 'cice':
3✔
288

289
                # Copy supplemental restart files to RESTART path
290
                for f_name in model.access_restarts:
3✔
291
                    f_src = os.path.join(model.work_path, f_name)
3✔
292
                    f_dst = os.path.join(model.restart_path, f_name)
3✔
293

294
                    if os.path.exists(f_src):
3✔
NEW
UNCOV
295
                        shutil.move(f_src, f_dst)
×
296

297
                # Copy "cice_in.nml" from work path to restart.
298
                work_ice_nml_path = os.path.join(
3✔
299
                                        model.work_path,
300
                                        model.ice_nml_fname
301
                )
302
                restart_ice_nml_path = os.path.join(
3✔
303
                                        model.restart_path,
304
                                        model.ice_nml_fname
305
                )
306

307
                if os.path.exists(work_ice_nml_path):
3✔
NEW
UNCOV
308
                    shutil.copy2(work_ice_nml_path, restart_ice_nml_path)
×
309

310
                # Check that run produced iced.YYYYMMDD restart file matching
311
                # run end date.
312
                model.find_matching_iced(model.restart_path, run_end_date)
3✔
313

314
            if model.model_type == 'cice5':
3✔
UNCOV
315
                cice5 = model
×
316
            elif model.model_type == 'mom':
3✔
317
                mom = model
×
318

319
        # Copy restart from ocean into ice area.
320
        if cice5 is not None and mom is not None:
3✔
UNCOV
321
            o2i_src = os.path.join(mom.work_path, 'o2i.nc')
×
UNCOV
322
            o2i_dst = os.path.join(cice5.restart_path, 'o2i.nc')
×
UNCOV
323
            shutil.copy2(o2i_src, o2i_dst)
×
324

325
    def get_restart_datetime(self, restart_path):
3✔
326
        """Given a restart path, parse the restart files and
327
        return a cftime datetime (for date-based restart pruning)"""
UNCOV
328
        return get_restart_datetime_using_mom_submodel(
×
329
            model=self, 
330
            restart_path=restart_path
331
        )
332

333
    def set_model_pathnames(self):
3✔
334
        pass
3✔
335

336
    def set_local_pathnames(self):
3✔
337
        pass
3✔
338

339
    def set_input_paths(self):
3✔
340
        pass
3✔
341

342
    def set_model_output_paths(self):
3✔
343
        pass
3✔
344

345
    def collate(self):
3✔
UNCOV
346
        pass
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc