trun.py - pism - [fork] customized build of PISM, the parallel ice sheet model (tillflux branch) (HTM) git clone git://src.adamsgaard.dk/pism (DIR) Log (DIR) Files (DIR) Refs (DIR) LICENSE --- trun.py (11649B) --- 1 #!/usr/bin/env python3 2 import MISMIP 3 4 # This scripts generates bash scripts that run MISMIP experiments and generates 5 # all the necessary input files. 6 # 7 # Run run.py > my_new_mismip.sh and use that. 8 9 try: 10 from netCDF4 import Dataset as NC 11 except: 12 print("netCDF4 is not installed!") 13 sys.exit(1) 14 15 import sys 16 17 # The "standard" preamble used in many PISM scripts: 18 preamble = ''' 19 if [ -n "${SCRIPTNAME:+1}" ] ; then 20 echo "[SCRIPTNAME=$SCRIPTNAME (already set)]" 21 echo "" 22 else 23 SCRIPTNAME="#(mismip.sh)" 24 fi 25 26 echo 27 echo "# ==================================================================================" 28 echo "# MISMIP experiments" 29 echo "# ==================================================================================" 30 echo 31 32 set -e # exit on error 33 34 NN=2 # default number of processors 35 if [ $# -gt 0 ] ; then # if user says "mismip.sh 8" then NN = 8 36 NN="$1" 37 fi 38 39 echo "$SCRIPTNAME NN = $NN" 40 41 # set MPIDO if using different MPI execution command, for example: 42 # $ export PISM_MPIDO="aprun -n " 43 if [ -n "${PISM_MPIDO:+1}" ] ; then # check if env var is already set 44 echo "$SCRIPTNAME PISM_MPIDO = $PISM_MPIDO (already set)" 45 else 46 PISM_MPIDO="mpiexec -n " 47 echo "$SCRIPTNAME PISM_MPIDO = $PISM_MPIDO" 48 fi 49 50 # check if env var PISM_DO was set (i.e. PISM_DO=echo for a 'dry' run) 51 if [ -n "${PISM_DO:+1}" ] ; then # check if env var DO is already set 52 echo "$SCRIPTNAME PISM_DO = $PISM_DO (already set)" 53 else 54 PISM_DO="" 55 fi 56 57 # prefix to pism (not to executables) 58 if [ -n "${PISM_BIN:+1}" ] ; then # check if env var is already set 59 echo "$SCRIPTNAME PISM_BIN = $PISM_BIN (already set)" 60 else 61 PISM_BIN="" # just a guess 62 echo "$SCRIPTNAME PISM_BIN = $PISM_BIN" 63 fi 64 ''' 65 66 67 class Experiment: 68 69 "A MISMIP experiment." 70 experiment = "" 71 mode = 1 72 model = 1 73 semianalytic = True 74 Mx = 151 75 My = 3 76 Mz = 15 77 initials = "ABC" 78 executable = "$PISM_DO $PISM_MPIDO $NN ${PISM_BIN}pismr" 79 80 def __init__(self, experiment, model=1, mode=1, Mx=None, Mz=15, semianalytic=True, 81 initials="ABC", executable=None): 82 self.model = model 83 self.mode = mode 84 self.experiment = experiment 85 self.initials = initials 86 self.semianalytic = semianalytic 87 88 if executable: 89 self.executable = executable 90 91 if mode == 3: 92 self.Mx = Mx 93 else: 94 self.Mx = 2 * MISMIP.N(self.mode) + 1 95 96 self.My = 3 97 98 if self.experiment == "2b": 99 self.Lz = 7000 100 else: 101 self.Lz = 6000 102 103 def physics_options(self, input_file, step): 104 "Options corresponding to modeling choices." 105 config_filename = self.config(step) 106 107 options = ["-energy none", # isothermal setup; allows selecting cold-mode flow laws 108 "-ssa_flow_law isothermal_glen", # isothermal setup 109 "-yield_stress constant", 110 "-tauc %e" % MISMIP.C(self.experiment), 111 "-pseudo_plastic", 112 "-gradient eta", 113 "-pseudo_plastic_q %e" % MISMIP.m(self.experiment), 114 "-pseudo_plastic_uthreshold %e" % MISMIP.secpera(), 115 "-front_retreat_file %s" % input_file, # prescribe the maximum ice extent 116 "-config_override %s" % config_filename, 117 "-ssa_method fd", 118 "-cfbc", # calving front boundary conditions 119 "-part_grid", # sub-grid front motion parameterization 120 "-ssafd_ksp_rtol 1e-7", 121 "-ys 0", 122 "-ye %d" % MISMIP.run_length(self.experiment, step), 123 "-options_left", 124 ] 125 126 if self.model == 1: 127 options.extend(["-stress_balance ssa"]) 128 else: 129 options.extend(["-stress_balance ssa+sia", 130 "-sia_flow_law isothermal_glen", # isothermal setup 131 ]) 132 133 return options 134 135 def config(self, step): 136 '''Generates a config file containing flags and parameters 137 for a particular experiment and step. 138 139 This takes care of flags and parameters that *cannot* be set using 140 command-line options. (We try to use command-line options whenever we can.) 141 ''' 142 143 filename = "MISMIP_conf_%s_A%s.nc" % (self.experiment, step) 144 145 nc = NC(filename, 'w', format="NETCDF3_CLASSIC") 146 147 var = nc.createVariable("pism_overrides", 'i') 148 149 attrs = {"ocean.always_grounded": "no", 150 "geometry.update.use_basal_melt_rate": "no", 151 "stress_balance.ssa.compute_surface_gradient_inward": "no", 152 "flow_law.isothermal_Glen.ice_softness": MISMIP.A(self.experiment, step), 153 "constants.ice.density": MISMIP.rho_i(), 154 "constants.sea_water.density": MISMIP.rho_w(), 155 "bootstrapping.defaults.geothermal_flux": 0.0, 156 "stress_balance.ssa.Glen_exponent": MISMIP.n(), 157 "constants.standard_gravity": MISMIP.g(), 158 "ocean.sub_shelf_heat_flux_into_ice": 0.0, 159 } 160 161 if self.model != 1: 162 attrs["stress_balance.sia.bed_smoother.range"] = 0.0 163 164 for name, value in attrs.items(): 165 var.setncattr(name, value) 166 167 nc.close() 168 169 return filename 170 171 def bootstrap_options(self, step): 172 boot_filename = "MISMIP_boot_%s_M%s_A%s.nc" % (self.experiment, self.mode, step) 173 174 import prepare 175 prepare.pism_bootstrap_file(boot_filename, self.experiment, step, self.mode, N=self.Mx, 176 semianalytical_profile=self.semianalytic) 177 178 options = ["-i %s -bootstrap" % boot_filename, 179 "-Mx %d" % self.Mx, 180 "-My %d" % self.My, 181 "-Mz %d" % self.Mz, 182 "-Lz %d" % self.Lz] 183 184 return options, boot_filename 185 186 def output_options(self, step): 187 output_file = self.output_filename(self.experiment, step) 188 extra_file = "ex_" + output_file 189 ts_file = "ts_" + output_file 190 191 options = ["-extra_file %s" % extra_file, 192 "-extra_times 0:50:3e4", 193 "-extra_vars thk,topg,velbar_mag,flux_mag,mask,dHdt,usurf,hardav,velbase_mag,nuH,tauc,taud,taub,flux_divergence,cell_grounded_fraction", 194 "-ts_file %s" % ts_file, 195 "-ts_times 0:50:3e4", 196 "-o %s" % output_file, 197 "-o_order zyx", 198 ] 199 200 return output_file, options 201 202 def output_filename(self, experiment, step): 203 return "%s%s_%s_M%s_A%s.nc" % (self.initials, self.model, experiment, self.mode, step) 204 205 def options(self, step, input_file=None): 206 '''Generates a string of PISM options corresponding to a MISMIP experiment.''' 207 208 if input_file is None: 209 input_options, input_file = self.bootstrap_options(step) 210 else: 211 input_options = ["-i %s" % input_file] 212 213 physics = self.physics_options(input_file, step) 214 215 output_file, output_options = self.output_options(step) 216 217 return output_file, (input_options + physics + output_options) 218 219 def run_step(self, step, input_file=None): 220 out, opts = self.options(step, input_file) 221 print('echo "# Step %s-%s"' % (self.experiment, step)) 222 print("%s %s" % (self.executable, ' '.join(opts))) 223 print('echo "Done."\n') 224 225 return out 226 227 def run(self, step=None): 228 print('echo "# Experiment %s"' % self.experiment) 229 230 if self.experiment in ('1a', '1b'): 231 # bootstrap 232 input_file = None 233 # steps 1 to 9 234 steps = list(range(1, 10)) 235 236 if self.experiment in ('2a', '2b'): 237 # start from step 9 of the corresponding experiment 1 238 input_file = self.output_filename(self.experiment.replace("2", "1"), 9) 239 # steps 8 to 1 240 steps = list(range(8, 0, -1)) 241 242 if self.experiment == '3a': 243 # bootstrap 244 input_file = None 245 # steps 1 to 13 246 steps = list(range(1, 14)) 247 248 if self.experiment == '3b': 249 # bootstrap 250 input_file = None 251 # steps 1 to 15 252 steps = list(range(1, 16)) 253 254 if step is not None: 255 input_file = None 256 steps = [step] 257 258 for step in steps: 259 input_file = self.run_step(step, input_file) 260 261 262 def run_mismip(initials, executable, semianalytic): 263 Mx = 601 264 models = (1, 2) 265 modes = (1, 2, 3) 266 experiments = ('1a', '1b', '2a', '2b', '3a', '3b') 267 268 print(preamble) 269 270 for model in models: 271 for mode in modes: 272 for experiment in experiments: 273 e = Experiment(experiment, 274 initials=initials, 275 executable=executable, 276 model=model, mode=mode, Mx=Mx, 277 semianalytic=semianalytic) 278 e.run() 279 280 281 if __name__ == "__main__": 282 from optparse import OptionParser 283 284 parser = OptionParser() 285 286 parser.usage = "%prog [options]" 287 parser.description = "Creates a script running MISMIP experiments." 288 parser.add_option("--initials", dest="initials", type="string", 289 help="Initials (3 letters)", default="ABC") 290 parser.add_option("-e", "--experiment", dest="experiment", type="string", 291 default='1a', 292 help="MISMIP experiments (one of '1a', '1b', '2a', '2b', '3a', '3b')") 293 parser.add_option("-s", "--step", dest="step", type="int", 294 help="MISMIP step number") 295 parser.add_option("-u", "--uniform_thickness", 296 action="store_false", dest="semianalytic", default=True, 297 help="Use uniform 10 m ice thickness") 298 parser.add_option("-a", "--all", 299 action="store_true", dest="all", default=False, 300 help="Run all experiments") 301 parser.add_option("-m", "--mode", dest="mode", type="int", default=1, 302 help="MISMIP grid mode") 303 parser.add_option("--Mx", dest="Mx", type="int", default=601, 304 help="Custom grid size; use with --mode=3") 305 parser.add_option("--model", dest="model", type="int", default=1, 306 help="Models: 1 - SSA only; 2 - SIA+SSA") 307 parser.add_option("--executable", dest="executable", type="string", 308 help="Executable to run, e.g. 'mpiexec -n 4 pismr'") 309 310 (opts, args) = parser.parse_args() 311 312 if opts.all: 313 run_mismip(opts.initials, opts.executable, opts.semianalytic) 314 exit(0) 315 316 def escape(arg): 317 if arg.find(" ") >= 0: 318 parts = arg.split("=") 319 return "%s=\"%s\"" % (parts[0], ' '.join(parts[1:])) 320 else: 321 return arg 322 323 arg_list = [escape(a) for a in sys.argv] 324 325 print("#!/bin/bash") 326 print("# This script was created by examples/mismip/run.py. The command was:") 327 print("# %s" % (' '.join(arg_list))) 328 329 if opts.executable is None: 330 print(preamble) 331 332 e = Experiment(opts.experiment, 333 initials=opts.initials, 334 executable=opts.executable, 335 model=opts.model, 336 mode=opts.mode, 337 Mx=opts.Mx, 338 semianalytic=opts.semianalytic) 339 340 if opts.step is not None: 341 e.run(opts.step) 342 else: 343 e.run()