def test(): ctx = PISM.Context() Mx = int(ctx.config.get_double("grid.Mx")) My = int(ctx.config.get_double("grid.My")) grid = PISM.IceGrid_Shallow(ctx.ctx, 1, 1, 0, 0, Mx, My, PISM.CELL_CORNER, PISM.NOT_PERIODIC) import pylab as plt plt.rcParams['figure.figsize'] = (8.0, 8.0) mt = MassTransport(grid) mt.reset() levels = np.linspace(0, 1, 11) t = 0 dt = 0.333 C = 1.0 for j in [1, 2, 4, 3]: plt.subplot(2, 2, j) mt.plot_thickness(levels, "time={}, V={}".format(t, volume(mt.geometry))) mt.step(dt, C) t += dt plt.show()
def _initGrid(self): halfWidth = 300.0e3 Lx = halfWidth Ly = halfWidth ctx = PISM.Context().ctx self.grid = PISM.IceGrid.Shallow(ctx, Lx, Ly, 0, 0, self.Mx, self.My, PISM.XY_PERIODIC)
def run_model(grid, orography): "Run the PISM implementation of the model to compare to the Python version." model = PISM.AtmosphereOrographicPrecipitation( grid, PISM.AtmosphereUniform(grid)) geometry = PISM.Geometry(grid) with PISM.vec.Access(nocomm=geometry.ice_thickness): for i, j in grid.points(): geometry.ice_thickness[i, j] = orography[j, i] geometry.bed_elevation.set(0.0) geometry.sea_level_elevation.set(0.0) geometry.ice_area_specific_volume.set(0.0) # compute surface elevation from ice thickness and bed elevation geometry.ensure_consistency(0) model.init(geometry) model.update(geometry, 0, 1) config = PISM.Context().config water_density = config.get_number("constants.fresh_water.density") # convert from kg / (m^2 s) to mm/s return model.mean_precipitation().numpy() / (1e-3 * water_density)
def epsg_test(): "Test EPSG to CF conversion." l = PISM.StringLogger(PISM.PETSc.COMM_WORLD, 2) system = PISM.Context().unit_system # test supported EPSG codes for code in [3413, 3031]: print("Trying code {}".format(code)) l.reset() # +init at the beginning v = PISM.epsg_to_cf(system, "+init=epsg:%d" % code) # +init not at the beginning of the string v = PISM.epsg_to_cf(system, "+units=m +init=epsg:%d" % code) # +init followed by more options v = PISM.epsg_to_cf(system, "+init=epsg:%d +units=m" % code) v.report_to_stdout(l, 2) print(l.get()) print("done.") # test that unsupported codes trigger an exception try: v = PISM.epsg_to_cf(system, "+init=epsg:3032") raise AssertionError( "should fail with 3032: only 3413 and 3031 are supported") except RuntimeError as e: print("unsupported codes trigger exceptions: {}".format(e)) # test that an invalid PROJ.4 string (e.g. an EPSG code is not a # number) triggers an exception try: v = PISM.epsg_to_cf(system, "+init=epsg:not-a-number +units=m") # raise AssertionError("an invalid PROJ.4 string failed to trigger an exception") except RuntimeError as e: print("invalid codes trigger exceptions: {}".format(e))
def createBasalWaterVec(grid, name='tillwat', desc="effective thickness of subglacial melt water", ghost_type=PISM.WITH_GHOSTS, stencil_width=None): """Returns an :cpp:class:`IceModelVec2S` with attributes setup for basal melt water thickness data. :param grid: The grid to associate with the vector. :param name: The intrinsic name to give the vector. :param ghost_type: One of ``PISM.WITH_GHOSTS`` or ``PISM.WITHOUT_GHOSTS`` indicating if the vector is ghosted. :param stencil_width: The size of the ghost stencil. Ignored if ``ghost_type`` is ``PISM.WITHOUT_GHOSTS``. If ``stencil_width`` is ``None`` and the vector is ghosted, the grid's maximum stencil width is used. """ stencil_width = _stencil_width(grid, ghost_type, stencil_width) tillwat = PISM.IceModelVec2S() tillwat.create(grid, name, ghost_type, stencil_width) tillwat.set_attrs("model_state", desc, "m", "") #// NB! Effective thickness of subglacial melt water *does* vary from 0 to hmelt_max meters only. tillwat.metadata().set_double("valid_min", 0.0) valid_max = PISM.Context().config.get_double("hydrology.tillwat_max") tillwat.metadata().set_double("valid_max", valid_max) return tillwat
def _initGrid(self): """Initialize grid size and periodicity. Called from :meth:`PISM.ssa.SSARun.setup`.""" # The implementation in PISM.ssa.SSAFromInputFile uses a non-periodic # grid only if the run is regional and "ssa_method=fem" in the config # file. For inversions, we always use an FEM type method, so for # regional inversions, we always use a non-periodic grid. periodicity = PISM.XY_PERIODIC (pstring, pflag) = PISM.optionsListWasSet('-periodicity', "Grid periodicity", 'x,y,xy,none', 'xy') if pflag: pdict = { 'x': PISM.X_PERIODIC, 'y': PISM.Y_PERIODIC, 'xy': PISM.XY_PERIODIC, 'none': PISM.NOT_PERIODIC } periodicity = pdict[pstring] else: periodicity = PISM.XY_PERIODIC if self.is_regional: periodicity = PISM.NOT_PERIODIC self.grid = PISM.IceGrid.FromFile(PISM.Context().ctx, self.input_filename, "enthalpy", periodicity)
def __init__(self, boot_file): SSARun.__init__(self) self.grid = None self.config = PISM.Context().config self.boot_file = boot_file self.phi_to_tauc = False self.is_regional = False
def max_error(spacing, wind_direction): # Set conversion time to zero (we could set fallout time to zero instead: it does not # matter which one is zero) wind_speed = 15 config = PISM.Context().config # set wind speed and direction config.set_number("atmosphere.orographic_precipitation.wind_speed", wind_speed) config.set_number("atmosphere.orographic_precipitation.wind_direction", wind_direction) # set conversion time to zero config.set_number("atmosphere.orographic_precipitation.conversion_time", 0.0) # eliminate the effect of airflow dynamics config.set_number( "atmosphere.orographic_precipitation.water_vapor_scale_height", 0.0) # eliminate the effect of the Coriolis force config.set_number("atmosphere.orographic_precipitation.coriolis_latitude", 0.0) # get constants needed to compute the exact solution tau = config.get_number("atmosphere.orographic_precipitation.fallout_time") Theta_m = config.get_number( "atmosphere.orographic_precipitation.moist_adiabatic_lapse_rate") rho_Sref = config.get_number( "atmosphere.orographic_precipitation.reference_density") gamma = config.get_number("atmosphere.orographic_precipitation.lapse_rate") Cw = rho_Sref * Theta_m / gamma if wind_direction == 90 or wind_direction == 270: # east or west grid = triangle_ridge_grid(dx=spacing) t = np.array(grid.x()) h = triangle_ridge(t) orography = np.tile(h, (grid.My(), 1)) P = run_model(grid, orography) P = P[grid.My() // 2, :] else: # north or south grid = triangle_ridge_grid(dy=spacing) t = np.array(grid.y()) h = triangle_ridge(t) orography = np.tile(h, (grid.Mx(), 1)).T P = run_model(grid, orography) P = P[:, grid.Mx() // 2] if wind_direction == 0 or wind_direction == 90: P_exact = triangle_ridge_exact(-t, wind_speed, Cw, tau) else: P_exact = triangle_ridge_exact(t, wind_speed, Cw, tau) return np.max(np.fabs(P - P_exact))
def __call__(self, inverse_solver, count, data): """ :param inverse_sovler: the solver (e.g. :class:`~InvSolver_Tikhonov`) we are listening to. :param count: the iteration number. :param data: dictionary of data related to the iteration. """ method = inverse_solver.method if method != 'sd' and method != 'nlcg' and method != 'ign': if not self.didWarning: PISM.verbPrintf( 1, PISM.Context().com, '\nWarning: unable to monitor adjoint for inverse method: %s\nOption -inv_monitor_adjoint ignored\n' % method) self.didWarning = True return fp = inverse_solver.forward_problem d = PISM.invert.sipletools.PISMLocalVector(data.d) r = PISM.invert.sipletools.PISMLocalVector(data.r) self.Td = fp.T(d, self.Td) self.TStarR = fp.TStar(r, out=self.TStarR) ip1 = fp.domainIP(d, self.TStarR) ip2 = fp.rangeIP(self.Td, r) logMessage("adjoint test: <Td,r>=%g <d,T^*r>=%g (percent error %g)", ip1, ip2, (abs(ip1 - ip2)) / max(abs(ip1), abs(ip2)))
def create_scalar_forcing(file_name, variable_name, units, values, times, time_bounds=None): "Create a dummy scalar forcing file (delta_T, etc)." ctx = PISM.Context() time_name = ctx.config.get_string("time.dimension_name") forcing = PISM.Timeseries(ctx.com, ctx.unit_system, variable_name, time_name) forcing.variable().set_string("units", units) if time_bounds is not None: for k in range(len(values)): # NB: ignores times bounds = np.array(time_bounds, dtype=np.float64) forcing.append(values[k], bounds[2 * k], bounds[2 * k + 1]) forcing.set_use_bounds(True) else: forcing.set_use_bounds(False) for k in range(len(values)): # NB: we are not using bounds, so it is OK to use times[k] for both endpoints t = np.array(times, dtype=np.float64) forcing.append(values[k], times[k], times[k]) output = PISM.util.prepare_output(file_name, append_time=False) if time_bounds is not None: output.write_attribute(time_name, "bounds", time_name + "_bounds") forcing.write(output)
def create_scalar_forcing(file_name, variable_name, units, values, times, time_bounds=None, time_name=None): "Create a dummy scalar forcing file (delta_T, etc)." ctx = PISM.Context() if time_name is None: time_name = ctx.config.get_string("time.dimension_name") bounds_name = time_name + "_bounds" if time_bounds is not None and times is None: # override times times = [] for k in range(len(values)): times.append(0.5 * (time_bounds[2 * k + 0] + time_bounds[2 * k + 1])) try: output = PISM.File(ctx.com, file_name, PISM.PISM_NETCDF3, PISM.PISM_READWRITE) except: output = PISM.File(ctx.com, file_name, PISM.PISM_NETCDF3, PISM.PISM_READWRITE_CLOBBER) output.define_dimension(time_name, len(times)) output.define_variable(time_name, PISM.PISM_DOUBLE, [time_name]) output.write_attribute(time_name, "long_name", "time") output.write_attribute(time_name, "axis", "T") output.write_attribute(time_name, "units", ctx.time.units_string()) output.write_attribute(time_name, "calendar", ctx.config.get_string("time.calendar")) output.define_variable(variable_name, PISM.PISM_DOUBLE, [time_name]) output.write_attribute(variable_name, "units", units) if time_bounds is not None: output.write_attribute(time_name, "bounds", bounds_name) output.define_dimension("bnds", 2) output.define_variable(bounds_name, PISM.PISM_DOUBLE, [time_name, "bnds"]) output.write_variable(bounds_name, [0, 0], [len(times), 2], np.array(time_bounds, dtype=np.float64).data) output.write_variable(time_name, [0], [len(times)], np.array(times, dtype=np.float64).data) output.write_variable(variable_name, [0], [len(values)], np.array(values, dtype=np.float64).data) output.close()
def _initGrid(self): Mx = self.Mx My = self.My Ly = 3 * L_schoof # 300.0 km half-width (L=40.0km in Schoof's choice of variables) Lx = max(60.0e3, ((Mx - 1) / 2.) * (2.0 * Ly / (My - 1))) self.grid = PISM.IceGrid.Shallow(PISM.Context().ctx, Lx, Ly, 0, 0, Mx, My, PISM.CELL_CORNER, PISM.NOT_PERIODIC)
def context_missing_attribute_test(): "Test the handling of missing attributes" ctx = PISM.Context() try: config = ctx.foo # there is no "foo", this should fail return False except AttributeError: return True
def _initGrid(self): self.grid = None halfWidth = 250.0e3 # 500.0 km length Lx = halfWidth Ly = halfWidth self.grid = PISM.IceGrid.Shallow(PISM.Context().ctx, Lx, Ly, 0, 0, self.Mx, self.My, PISM.CELL_CENTER, PISM.Y_PERIODIC)
def readOldLog(self): """If the :file:`.nc` file we are logging to already has a log, read it in to the log we are about to make so that we append to it rather than overwriting it.""" d = PISM.File(PISM.Context().com, self.filename, PISM.PISM_NETCDF3, PISM.PISM_READONLY) self.log += d.read_text_attribute("PISM_GLOBAL", self.attr) d.close()
def __init__(self, design_var): PISM.ssa.SSARun.__init__(self) assert(design_var in list(ssa_forward_problems.keys())) self.grid = None self.config = PISM.Context().config self.design_var = design_var self.design_var_param = createDesignVariableParam(self.config, self.design_var) self.is_regional = False
def __call__(self, message, verbosity): """Saves the message to our internal log string and writes the string out to the file.""" if verbosity <= 2: # FIXME: fixed verbosity threshold timestamp = time.strftime('%Y-%m-%d %H:%M:%S') self.log = "%s%s: %s" % (self.log, timestamp, message) d = PISM.PIO(PISM.Context().com, "netcdf3", self.filename, PISM.PISM_READWRITE) d.put_att_text("PISM_GLOBAL", self.attr, self.log) d.close()
def exact(ice_thickness_change): "Exact deflection corresponding to a given thickness change." config = PISM.Context().config ice_density = config.get_double("constants.ice.density") mantle_density = config.get_double("bed_deformation.mantle_density") return -(ice_density / mantle_density) * ice_thickness_change
def random_vec_test(): "Test methods creating random fields" grid = PISM.IceGrid_Shallow(PISM.Context().ctx, 1e6, 1e6, 0, 0, 61, 31, PISM.NOT_PERIODIC, PISM.CELL_CENTER) vec_scalar = PISM.vec.randVectorS(grid, 1.0) vec_vector = PISM.vec.randVectorV(grid, 2.0) vec_scalar_ghosted = PISM.vec.randVectorS(grid, 1.0, 2) vec_vector_ghosted = PISM.vec.randVectorV(grid, 2.0, 2)
def __call__(self, message, verbosity): """Saves the message to our internal log string and writes the string out to the file.""" if verbosity <= self.verbosity_threshold: timestamp = time.strftime('%Y-%m-%d %H:%M:%S') self.log = "%s%s: %s" % (self.log, timestamp, message) d = PISM.File(PISM.Context().com, self.filename, PISM.PISM_NETCDF3, PISM.PISM_READWRITE) d.redef() d.write_attribute("PISM_GLOBAL", self.attr, self.log) d.close()
def write(self, filename=None, attribute=None): """Save a copy of our log to the specified file and attribute.""" if filename is None: filename = self.filename if attribute is None: attribute = self.attr d = PISM.PIO(PISM.Context().com, "netcdf3", self.filename, PISM.PISM_READWRITE) d.put_att_text("PISM_GLOBAL", attribute, self.log) d.close()
def readOldLog(self): """If the :file:`.nc` file we are logging to already has a log, read it in to the log we are about to make so that we append to it rather than overwriting it.""" if PISM.Context().rank == 0: d = PISM.netCDF.Dataset(self.filename, 'a') if self.attr in d.ncattrs(): self.log += d.__getattr__(self.attr) d.close() self.com.barrier()
def options_test(): "Test command-line option handling" ctx = PISM.Context() o = PISM.PETSc.Options() M = PISM.optionsInt("-M", "description", default=100) M = PISM.optionsInt("-M", "description", default=None) S = PISM.optionsString("-S", "description", default="string") S = PISM.optionsString("-S", "description", default=None) R = PISM.optionsReal("-R", "description", default=1.5) R = PISM.optionsReal("-R", "description", default=None) o.setValue("-B", "on") B = PISM.optionsFlag("-B", "description", default=False) B = PISM.optionsFlag("B", "description", default=False) B = PISM.optionsFlag("-B", "description", default=None) o.setValue("-no_C", "on") C = PISM.optionsFlag("C", "description", default=None) D = PISM.optionsFlag("D", "description", default=None) D = PISM.optionsFlag("D", "description", default=True) o.setValue("-no_D", "on") o.setValue("-D", "on") try: # should throw RuntimeError D = PISM.optionsFlag("D", "description", default=None) return False except RuntimeError: pass o.setValue("-IA", "1,2,3") IA = PISM.optionsIntArray("-IA", "description", default=[1, 2]) IA = PISM.optionsIntArray("-IA", "description", default=None) IA2 = PISM.optionsIntArray("-IA2", "description", default=None) IA2 = PISM.optionsIntArray("-IA2", "description", default=[1, 2]) o.setValue("-RA", "1,2,3") RA = PISM.optionsRealArray("-RA", "description", default=[2, 3]) RA = PISM.optionsRealArray("-RA", "description", default=None) RA2 = PISM.optionsRealArray("-RA2", "description", default=[2, 3]) RA2 = PISM.optionsRealArray("-RA2", "description", default=None) o.setValue("-SA", "1,2,3") SA = PISM.optionsStringArray("-SA", "description", default="one,two") SA = PISM.optionsStringArray("-SA", "description", default=None) SA2 = PISM.optionsStringArray("-SA2", "description", default="two,three") SA2 = PISM.optionsStringArray("-SA2", "description", default=None) M = PISM.optionsList("-L", "description", choices="one,two", default="one") M = PISM.optionsList("-L", "description", choices="one,two", default=None)
def ssa_trivial_test(): "Test the SSA solver using a trivial setup." context = PISM.Context() L = 50.e3 # // 50km half-width H0 = 500 # // m dhdx = 0.005 # // pure number, slope of surface & bed nu0 = PISM.util.convert(30.0, "MPa year", "Pa s") tauc0 = 1.e4 # // 1kPa class TrivialSSARun(PISM.ssa.SSAExactTestCase): def _initGrid(self): self.grid = PISM.IceGrid.Shallow(context.ctx, L, L, 0, 0, self.Mx, self.My, PISM.CELL_CORNER, PISM.NOT_PERIODIC) def _initPhysics(self): self.modeldata.setPhysics(context.enthalpy_converter) def _initSSACoefficients(self): self._allocStdSSACoefficients() self._allocateBCs() vecs = self.modeldata.vecs vecs.land_ice_thickness.set(H0) vecs.surface_altitude.set(H0) vecs.bedrock_altitude.set(0.0) vecs.tauc.set(tauc0) # zero Dirichler B.C. everywhere vecs.vel_bc.set(0.0) vecs.vel_bc_mask.set(1.0) def _initSSA(self): # The following ensure that the strength extension is used everywhere se = self.ssa.strength_extension se.set_notional_strength(nu0 * H0) se.set_min_thickness(4000 * 10) # For the benefit of SSAFD on a non-periodic grid self.config.set_flag("ssa.compute_surface_gradient_inward", True) def exactSolution(self, i, j, x, y): return [0, 0] output_file = filename("ssa_trivial") try: Mx = 11 My = 11 test_case = TrivialSSARun(Mx, My) test_case.run(output_file) finally: os.remove(output_file)
def modeled_time_dependent(dics_radius, disc_thickness, t_end, L, Nx, dt): "Use the LingleClark class to compute plate deflection." Ny = Nx Mx = int(2 * Nx - 1) My = int(2 * Ny - 1) ctx = PISM.Context().ctx grid = PISM.IceGrid.Shallow(ctx, L, L, 0, 0, Mx, My, PISM.CELL_CORNER, PISM.NOT_PERIODIC) bed_model = PISM.LingleClark(grid) ice_thickness = PISM.IceModelVec2S(grid, "thk", PISM.WITHOUT_GHOSTS) bed = PISM.IceModelVec2S(grid, "topg", PISM.WITHOUT_GHOSTS) bed_uplift = PISM.IceModelVec2S(grid, "uplift", PISM.WITHOUT_GHOSTS) sea_level = PISM.IceModelVec2S(grid, "sea_level", PISM.WITHOUT_GHOSTS) # start with a flat bed, no ice, and no uplift bed.set(0.0) bed_uplift.set(0.0) ice_thickness.set(0.0) sea_level.set(-1000.0) bed_model.bootstrap(bed, bed_uplift, ice_thickness, sea_level) # add the disc load with PISM.vec.Access(nocomm=ice_thickness): for (i, j) in grid.points(): r = PISM.radius(grid, i, j) if r <= disc_radius: ice_thickness[i, j] = disc_thickness t = 0.0 while t < t_end: # make sure we don't step past t_end if t + dt > t_end: dt = t_end - t bed_model.step(ice_thickness, sea_level, dt) t += dt log.message(2, ".") log.message(2, "\n") # extract half of the x grid r = grid.x()[Nx - 1:] # extract values along the x direction (along the radius of the disc) z = bed_model.bed_elevation().numpy()[Ny - 1, Nx - 1:] return r, z
def write(self, filename=None, attribute=None): """Save a copy of our log to the specified file and attribute.""" if filename is None: filename = self.filename if attribute is None: attribute = self.attr d = PISM.File(PISM.Context().com, filename, PISM.PISM_NETCDF3, PISM.PISM_READWRITE) d.redef() d.write_attribute("PISM_GLOBAL", attribute, self.log) d.close()
def write(self, filename=None, attribute=None): """Save a copy of our log to the specified file and attribute.""" if filename is None: filename = self.filename if attribute is None: attribute = self.attr if PISM.Context().rank == 0: d = PISM.netCDF.Dataset(filename, 'a') d.__setattr__(attribute, self.log) d.close() self.com.barrier()
def pause(message_in=None, message_out=None): """Prints a message and waits for a key press. :param message_in: Message to display before waiting. :param message_out: Message to display after waiting.""" com = PISM.Context().com if not message_in is None: PISM.verbPrintf(1, com, message_in + "\n") _ = getkey() if not message_out is None: PISM.verbPrintf(1, com, message_out + "\n")
def modeled_time_dependent(dics_radius, disc_thickness, t_end, L, N, dt): "Use the LingleClark class to compute plate deflection." M = 2 * N - 1 ctx = PISM.Context().ctx grid = PISM.IceGrid.Shallow(ctx, L, L, 0, 0, M, M, PISM.CELL_CORNER, PISM.NOT_PERIODIC) bed_model = PISM.LingleClark(grid) ice_thickness = PISM.IceModelVec2S() ice_thickness.create(grid, "thk", PISM.WITHOUT_GHOSTS) bed = PISM.IceModelVec2S() bed.create(grid, "topg", PISM.WITHOUT_GHOSTS) bed_uplift = PISM.IceModelVec2S() bed_uplift.create(grid, "uplift", PISM.WITHOUT_GHOSTS) # start with a flat bed, no ice, and no uplift bed.set(0.0) bed_uplift.set(0.0) ice_thickness.set(0.0) bed_model.bootstrap(bed, bed_uplift, ice_thickness) # add the disc load with PISM.vec.Access(nocomm=ice_thickness): for (i, j) in grid.points(): r = PISM.radius(grid, i, j) if r <= disc_radius: ice_thickness[i, j] = disc_thickness t = 0.0 while t < t_end: # make sure we don't step past t_end if t + dt > t_end: dt = t_end - t bed_model.update(ice_thickness, t, dt) t += dt log.message(2, ".") log.message(2, "\n") p0 = PISM.vec.ToProcZero(grid) # extract half of the x grid r = grid.x()[N - 1:] # extract values along the x direction (along the radius of the disc) z = p0.communicate(bed_model.bed_elevation())[N - 1, N - 1:] return r, z
def write(self, output_filename): """Saves a history of misfits as :ncvar:`inv_ssa_misfit` :param output_filename: filename to save misfits to.""" if PISM.Context().rank == 0: nc = PISM.netCDF.Dataset(output_filename, 'a') # append nc.createDimension('inv_ssa_iter', len(self.misfit_history)) nc_misfit = nc.createVariable('inv_ssa_misfit', 'f8', dimensions=('inv_ssa_iter')) if self.misfit_type == "meansquare": nc_misfit.setncattr('_units', 'm/a') nc_misfit[:] = self.misfit_history[:] nc.close()