def errors(plot_results=True, T_final_years=1000.0, dt_years=100, Mz=101): """Test the bedrock temperature solver with Neumann B.C. at the base and Dirichlet B.C. at the top surface. """ T_final = convert(T_final_years, "years", "seconds") dt = convert(dt_years, "years", "seconds") Lz = 1000.0 dz = Lz / (Mz - 1.0) column = PISM.BedrockColumn("btu", ctx.config, dz, int(Mz)) z = np.linspace(-Lz, 0, Mz) T_base = 240.0 # Kelvin T_surface = 260.0 # Kelvin dT_base = (T_surface - T_base) / Lz T_steady = T_base + dT_base * (z - (-Lz)) Q_base = -K * dT_base T_exact = exact(Lz, dT_base, T_surface) t = 0.0 # initial condition x = T_exact(z, t) while t < T_final: x = column.solve(dt, Q_base, T_surface, x) t += dt T_exact_final = T_exact(z, t) if plot_results: t_years = convert(t, "seconds", "years") plt.figure() plt.xlabel("z, meters") plt.ylabel("T, K") plt.step(z, T_exact(z, 0), color="blue", label="initial condition") plt.step(z, T_exact_final, color="green", label="exact solution") plt.step(z, T_steady, "--", color="black", label="steady state profile") plt.grid(True) plt.step(z, x, label="T={} years".format(t_years), color="red") plt.legend(loc="best") errors = T_exact(z, t) - x max_error = np.max(np.fabs(errors)) avg_error = np.average(np.fabs(errors)) return max_error, avg_error
def setUp(self): self.grid = shallow_grid() self.geometry = PISM.Geometry(self.grid) self.model = surface_simple(self.grid) self.filename = "surface_force_to_thickness_input.nc" self.output_filename = "surface_force_to_thickness_output.nc" self.H = 1000.0 self.dH = 1000.0 self.geometry.ice_thickness.set(self.H) # save ice thickness to a file to use as the target thickness PISM.util.prepare_output(self.filename) self.geometry.ice_thickness.write(self.filename) ftt_mask = PISM.IceModelVec2S(self.grid, "ftt_mask", PISM.WITHOUT_GHOSTS) ftt_mask.set(1.0) ftt_mask.write(self.filename) alpha = 10.0 ice_density = config.get_number("constants.ice.density") self.dSMB = -ice_density * alpha * self.dH config.set_string("surface.force_to_thickness_file", self.filename) config.set_number("surface.force_to_thickness.alpha", convert(alpha, "1/s", "1/year"))
def write(self, filename): """Saves all of :attr:`modeldata`'s vecs (and the solution) to an output file.""" grid = self.grid vecs = self.modeldata.vecs pio = util.prepare_output(filename) pio.close() # Save time & command line util.writeProvenance(filename) vel_ssa = self.ssa.velocity() vecs.add(vel_ssa) velbar_mag = model.createCBarVec(self.grid) velbar_mag.set_to_magnitude(vel_ssa) velbar_mag.mask_by(vecs.thk, util.convert(-0.01, "m/year", "m/second")) vecs.add(velbar_mag) taud = PISM.SSA_taud(self.ssa).compute() vecs.add(taud) try: nuH = PISM.SSAFD_nuH(self.ssa).compute() vecs.add(nuH) except: pass taud_mag = PISM.SSA_taud_mag(self.ssa).compute() vecs.add(taud_mag) vecs.writeall(filename)
def exactSolution(self, i, j, x, y): tauc_threshold_velocity = self.config.get_double("basal_resistance.pseudo_plastic.u_threshold", "m/second") v0 = convert(100, "m/year", "m/second") alpha = math.sqrt((tauc0 / tauc_threshold_velocity) / (4 * nu0 * H0)) return [v0 * math.exp(-alpha * (x - L)), 0]
def create2dVelocityVec(grid, name="", desc="", intent="", ghost_type=PISM.WITH_GHOSTS, stencil_width=None): """Returns an :cpp:class:`IceModelVec2V` with attributes setup for horizontal velocity 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) vel = PISM.IceModelVec2V() vel.create(grid, name, ghost_type, stencil_width) vel.set_attrs(intent, "%s%s" % ("X-component of the ", desc), "m s-1", "", 0) vel.set_attrs(intent, "%s%s" % ("Y-component of the ", desc), "m s-1", "", 1) vel.metadata(0).set_string("glaciological_units", "m year-1") vel.metadata(1).set_string("glaciological_units", "m year-1") huge_vel = convert(1e10, "m/year", "m/second") attrs = [("valid_min", -huge_vel), ("valid_max", huge_vel), ("_FillValue", 2 * huge_vel)] for a in attrs: for component in [0, 1]: vel.metadata(component).set_double(a[0], a[1]) vel.set(2 * huge_vel) return vel
def test_elevation_change_shift(self): "Modifier elevation_change: shift" config.set_string("surface.elevation_change.smb.method", "shift") model = surface_simple(self.grid) modifier = PISM.SurfaceElevationChange(self.grid, model) modifier.init(self.geometry) # change surface elevation self.geometry.ice_surface_elevation.shift(self.dz) # check changes in outputs modifier.update(self.geometry, 0, 1) ice_density = config.get_number("constants.ice.density") dSMB = self.dz * ice_density * convert( -self.dSMBdz, "kg m-2 year-1 / km", "kg m-2 s-1 / m") # shifting SMB by dSMB reduced accumulation to zero dA = 0.0 - sample(model.accumulation()) dM = dA - dSMB dR = dM check_modifier(model, modifier, T=self.dT, SMB=dSMB, accumulation=dA, melt=dM, runoff=dR) write_state(modifier, self.output_filename) probe_interface(modifier)
def initialize_uplift(uplift): "Initialize the uplift field." grid = uplift.grid() peak_uplift = convert(10, "mm/year", "m/second") with PISM.vec.Access(nocomm=[uplift]): for (i, j) in grid.points(): r = PISM.radius(grid, i, j) if r < 1.5 * R0: uplift[i, j] = peak_uplift * (cos(pi * (r / (1.5 * R0))) + 1.0) / 2.0 else: uplift[i, j] = 0.0
def _initSSA(self): # Test J has a viscosity that is independent of velocity. So we force a # constant viscosity by settting the strength_extension # thickness larger than the given ice thickness. (max = 770m). nu0 = convert(30.0, "MPa year", "Pa s") H0 = 500.0 # 500 m typical thickness ssa = self.ssa ssa.strength_extension.set_notional_strength(nu0 * H0) ssa.strength_extension.set_min_thickness(800.)
def set_constants(config): # Set up the sliding law so that tauc == beta**2: config.set_flag("basal_resistance.pseudo_plastic.enabled", True) config.set_number("basal_resistance.pseudo_plastic.q", 1.0) config.set_number("basal_resistance.pseudo_plastic.u_threshold", convert(1.0, "m / s", "m / year")) # Set flow law parameters config.set_string("stress_balance.blatter.flow_law", "isothermal_glen") config.set_number("stress_balance.blatter.Glen_exponent", 3.0) config.set_number("flow_law.isothermal_Glen.ice_softness", convert(1e-16, "Pa-3 year-1", "Pa-3 s-1")) # Set constants: config.set_number("constants.ice.density", 910.0) config.set_number("constants.standard_gravity", 9.81) # Support compression config.set_string("output.format", "netcdf4_serial")
def setUp(self): self.filename = "surface_reference_surface.nc" self.output_filename = "surface_lapse_rates_output.nc" self.grid = shallow_grid() self.dTdz = 1.0 # 1 Kelvin per km self.dSMBdz = 2.0 # m year-1 per km self.dz = 1500.0 # m self.geometry = PISM.Geometry(self.grid) # save current surface elevation to use it as a "reference" surface elevation self.geometry.ice_surface_elevation.dump(self.filename) config.set_string("surface.elevation_change.file", self.filename) config.set_number("surface.elevation_change.temperature_lapse_rate", self.dTdz) config.set_number("surface.elevation_change.smb.lapse_rate", self.dSMBdz) self.dT = self.dz * convert(-self.dTdz, "Kelvin / km", "Kelvin / m")
def rangeVector(self): """Constructs a brand new vector from the range (i.e. state) vector space""" v = PISM.IceModelVec2V() v.create(self.grid, "", True, WIDE_STENCIL) # Add appropriate meta data. intent = "?inverse?" # FIXME desc = "SSA velocity computed by inversion" v.set_attrs(intent, "%s%s" % ("X-component of the ", desc), "m s-1", "m year-1", "", 0) v.set_attrs(intent, "%s%s" % ("Y-component of the ", desc), "m s-1", "m year-1", "", 1) huge_vel = convert(1e6, "m/year", "m/second") attrs = [("valid_min", -huge_vel), ("valid_max", huge_vel), ("_FillValue", 2 * huge_vel)] for a in attrs: for component in range(2): v.metadata(component).set_number(a[0], a[1]) return PISMLocalVector(v)
def setup(): global grid # "inputs" does not own its elements, so we need to make sure # these don't expire when setup() returns global basal_melt_rate, ice_thickness, inputs, surface_temp global climatic_mass_balance, basal_heat_flux, shelf_base_temp, cell_type global u, v, w, strain_heating3 grid = create_dummy_grid() zero = PISM.IceModelVec2S() zero.create(grid, "zero", PISM.WITHOUT_GHOSTS) zero.set(0.0) cell_type = PISM.IceModelVec2CellType() cell_type.create(grid, "mask", PISM.WITHOUT_GHOSTS) cell_type.set(PISM.MASK_GROUNDED) basal_heat_flux = PISM.IceModelVec2S() basal_heat_flux.create(grid, "bheatflx", PISM.WITHOUT_GHOSTS) basal_heat_flux.set(convert(10, "mW m-2", "W m-2")) ice_thickness = PISM.model.createIceThicknessVec(grid) ice_thickness.set(4000.0) # TemperatureModel needs ice_thickness to set enthalpy in restart(...) grid.variables().add(ice_thickness) shelf_base_temp = PISM.IceModelVec2S() shelf_base_temp.create(grid, "shelfbtemp", PISM.WITHOUT_GHOSTS) shelf_base_temp.set(260.0) surface_temp = PISM.IceModelVec2S() surface_temp.create(grid, "surface_temp", PISM.WITHOUT_GHOSTS) surface_temp.set(260.0) strain_heating3 = PISM.IceModelVec3() strain_heating3.create(grid, "sigma", PISM.WITHOUT_GHOSTS) u = PISM.IceModelVec3() u.create(grid, "u", PISM.WITHOUT_GHOSTS) v = PISM.IceModelVec3() v.create(grid, "v", PISM.WITHOUT_GHOSTS) w = PISM.IceModelVec3() w.create(grid, "w", PISM.WITHOUT_GHOSTS) ice_thickness.set(4000.0) u.set(0.0) v.set(0.0) w.set(0.0) basal_melt_rate = zero climatic_mass_balance = zero inputs = PISM.EnergyModelInputs() inputs.cell_type = cell_type inputs.basal_frictional_heating = zero inputs.basal_heat_flux = basal_heat_flux inputs.ice_thickness = ice_thickness inputs.surface_liquid_fraction = zero inputs.shelf_base_temp = shelf_base_temp inputs.surface_temp = surface_temp inputs.till_water_thickness = zero inputs.strain_heating3 = strain_heating3 inputs.u3 = u inputs.v3 = v inputs.w3 = w
inputs = PISM.EnergyModelInputs() inputs.cell_type = cell_type inputs.basal_frictional_heating = zero inputs.basal_heat_flux = basal_heat_flux inputs.ice_thickness = ice_thickness inputs.surface_liquid_fraction = zero inputs.shelf_base_temp = shelf_base_temp inputs.surface_temp = surface_temp inputs.till_water_thickness = zero inputs.strain_heating3 = strain_heating3 inputs.u3 = u inputs.v3 = v inputs.w3 = w dt = convert(1, "years", "seconds") def use_model(model): print("* Performing a time step...") model.update(0, dt, inputs) try: model.update(0, dt) raise Exception("this should fail") except RuntimeError: pass try: model.max_timestep(0) raise Exception("this should fail") except RuntimeError:
def __call__(self, inverse_solver, count, data): if not self.l2_weight_init: vecs = inverse_solver.ssarun.modeldata.vecs if vecs.has('vel_misfit_weight'): self.l2_weight = self.toproczero(vecs.vel_misfit_weight) self.l2_weight_init = True method = inverse_solver.method r = self.toproczero(data.residual) Td = None if 'T_zeta_step' in data: Td = self.toproczero(data.T_zeta_step) TStarR = None if 'TStar_residual' in data: TStarR = self.toproczero(data.TStar_residual) d = None if 'zeta_step' in data: d = self.toproczero(data.zeta_step) zeta = self.toproczero(data.zeta) secpera = convert(1.0, "year", "second") if self.grid.rank() == 0: import matplotlib.pyplot as pp pp.figure(self.figure()) l2_weight = self.l2_weight pp.clf() V = self.Vmax pp.subplot(2, 3, 1) if l2_weight is not None: rx = l2_weight * r[0, :, :] * secpera else: rx = r[0, :, :] * secpera rx = np.maximum(rx, -V) rx = np.minimum(rx, V) pp.imshow(rx, origin='lower', interpolation='nearest') pp.colorbar() pp.title('r_x') pp.jet() pp.subplot(2, 3, 4) if l2_weight is not None: ry = l2_weight * r[1, :, :] * secpera else: ry = r[1, :, :] * secpera ry = np.maximum(ry, -V) ry = np.minimum(ry, V) pp.imshow(ry, origin='lower', interpolation='nearest') pp.colorbar() pp.title('r_y') pp.jet() if method == 'ign': pp.subplot(2, 3, 2) Tdx = Td[0, :, :] * secpera pp.imshow(Tdx, origin='lower', interpolation='nearest') pp.colorbar() pp.title('Td_x') pp.jet() pp.subplot(2, 3, 5) Tdy = Td[1, :, :] * secpera pp.imshow(Tdy, origin='lower', interpolation='nearest') pp.colorbar() pp.title('Td_y') pp.jet() elif method == 'sd' or method == 'nlcg': pp.subplot(2, 3, 2) pp.imshow(TStarR, origin='lower', interpolation='nearest') pp.colorbar() pp.title('TStarR') pp.jet() if d is not None: d *= -1 pp.subplot(2, 3, 3) pp.imshow(d, origin='lower', interpolation='nearest') # colorbar does a divide by zero if 'd' is all zero, # as it will be at the start of iteration zero. # The warning message is a distraction, so we suppress it. import warnings with warnings.catch_warnings(): warnings.simplefilter("ignore") pp.colorbar() pp.jet() pp.title('-zeta_step') pp.subplot(2, 3, 6) pp.imshow(zeta, origin='lower', interpolation='nearest') pp.colorbar() pp.jet() pp.title('zeta') pp.ion() pp.draw() pp.show()
# # You should have received a copy of the GNU General Public License # along with PISM; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA import PISM from PISM.util import convert import math context = PISM.Context() L = 50.e3 # // 50km half-width H0 = 500 # // m dhdx = 0.005 # // pure number, slope of surface & bed nu0 = convert(30.0, "MPa year", "Pa s") tauc0 = 1.e4 # // 1kPa class test_linear(PISM.ssa.SSAExactTestCase): def _initGrid(self): self.grid = PISM.IceGrid.Shallow(PISM.Context().ctx, L, L, 0, 0, self.Mx, self.My, PISM.CELL_CORNER, PISM.NOT_PERIODIC) def _initPhysics(self): config = self.config config.set_boolean("basal_resistance.pseudo_plastic.enabled", True) config.set_double("basal_resistance.pseudo_plastic.q", 1.0)
def setup(): global grid # "inputs" does not own its elements, so we need to make sure # these don't expire when setup() returns global basal_melt_rate, ice_thickness, inputs, surface_temp global climatic_mass_balance, basal_heat_flux, shelf_base_temp, cell_type global u, v, w, strain_heating3 grid = create_dummy_grid() zero = PISM.IceModelVec2S(grid, "zero", PISM.WITHOUT_GHOSTS) zero.set(0.0) cell_type = PISM.IceModelVec2CellType(grid, "mask", PISM.WITHOUT_GHOSTS) cell_type.set(PISM.MASK_GROUNDED) basal_heat_flux = PISM.IceModelVec2S(grid, "bheatflx", PISM.WITHOUT_GHOSTS) basal_heat_flux.set(convert(10, "mW m-2", "W m-2")) ice_thickness = PISM.model.createIceThicknessVec(grid) ice_thickness.set(4000.0) # TemperatureModel needs ice_thickness to set enthalpy in restart(...) grid.variables().add(ice_thickness) shelf_base_temp = PISM.IceModelVec2S(grid, "shelfbtemp", PISM.WITHOUT_GHOSTS) shelf_base_temp.set(260.0) surface_temp = PISM.IceModelVec2S(grid, "surface_temp", PISM.WITHOUT_GHOSTS) surface_temp.set(260.0) strain_heating3 = PISM.IceModelVec3(grid, "sigma", PISM.WITHOUT_GHOSTS) u = PISM.IceModelVec3(grid, "u", PISM.WITHOUT_GHOSTS) v = PISM.IceModelVec3(grid, "v", PISM.WITHOUT_GHOSTS) w = PISM.IceModelVec3(grid, "w", PISM.WITHOUT_GHOSTS) ice_thickness.set(4000.0) u.set(0.0) v.set(0.0) w.set(0.0) basal_melt_rate = zero climatic_mass_balance = zero inputs = PISM.EnergyModelInputs() inputs.cell_type = cell_type inputs.basal_frictional_heating = zero inputs.basal_heat_flux = basal_heat_flux inputs.ice_thickness = ice_thickness inputs.surface_liquid_fraction = zero inputs.shelf_base_temp = shelf_base_temp inputs.surface_temp = surface_temp inputs.till_water_thickness = zero inputs.volumetric_heating_rate = strain_heating3 inputs.u3 = u inputs.v3 = v inputs.w3 = w
vel_sia_observed.metadata(1).set_name('v_sia_observed') vel_sia_observed.metadata(1).set_string('long_name', "y-component of the 'observed' SIA velocities") vel_surface_observed = PISM.model.create2dVelocityVec(grid, "_surface_observed", "observed surface velocities", stencil_width=1) vel_surface_observed.copy_from(vel_sia_observed) vel_surface_observed.add(1., vel_ssa_observed) vecs.markForWriting(vel_surface_observed) final_velocity = vel_surface_observed # Add the misfit weight. if misfit_weight_type == "fast": misfit_weight = fastIceMisfitWeight(modeldata, vel_ssa, convert(fast_ice_speed, "m/year", "m/second")) else: misfit_weight = groundedIceMisfitWeight(modeldata) modeldata.vecs.add(misfit_weight, writing=True) if not noise is None: u_noise = PISM.vec.randVectorV(grid, noise / math.sqrt(2), final_velocity.stencil_width()) final_velocity.add(convert(1.0, "m/year", "m/second"), u_noise) pio = PISM.util.prepare_output(output_file_name) pio.close() vecs.write(output_file_name) # Save time & command line
-snes_monitor \ -ksp_monitor This command uses "aggressive" coarsening (factor of 4) and 2 multigrid levels (5 and 2 nodes in the vertical direction). To use AMG on the coarse level, add "-mg_coarse_pc_type gamg". """ import numpy as np import PISM import PISM.testing from PISM.util import convert seconds_per_year = convert(1.0, "year", "second") ctx = PISM.Context() config = ctx.config tests = {"A": PISM.HOM_A, "B": PISM.HOM_B, "C": PISM.HOM_C, "D": PISM.HOM_D} def surface_AB(x, y, L): alpha = 0.5 * (np.pi / 180.0) # 0.5 degrees return -x * np.tan(alpha) def surface_C(x, y, L): alpha = 0.1 * (np.pi / 180.0) # 0.1 degrees return -x * np.tan(alpha)
def run(T_final_years=10.0, dt_days=1, Lz=1000, Mz=101, R=20, omega=0.005): """Run the one-column cryohydrologic warming setup""" T_final = convert(T_final_years, "years", "seconds") dt = convert(dt_days, "days", "seconds") ice = EnthalpyColumn("energy.enthalpy", Mz, dt, Lz=Lz) ch = EnthalpyColumn("energy.ch_warming", Mz, dt, Lz=Lz) H = ice.Lz z = np.array(ice.sys.z()) P = pressure(H - z) z_coarse = np.array(ice.grid.z()) P_coarse = pressure(H - z_coarse) T_mean_annual = 268.15 # mean annual temperature, Kelvin T_amplitude = 6 # surface temperature aplitude, Kelvin summer_peak_day = 365/2 G = 0.0 # geothermal flux, W/m^2 E_initial = E_steady_state(H, z_coarse, T_mean_annual, G, k) with PISM.vec.Access(nocomm=[ice.enthalpy, ice.strain_heating, ice.u, ice.v, ice.w, ch.enthalpy, ch.strain_heating, ch.u, ch.v, ch.w]): # set initial state for the ice enthalpy ice.enthalpy.set_column(1, 1, E_initial) # set initial state for the CH system enthalpy ch.enthalpy.set_column(1, 1, E_initial) times = [] T_ice = [] T_ch = [] W_ice = [] W_ch = [] t = 0.0 while t < T_final: times.append(t) # compute the heat flux from the CH system into the ice T_s = T_surface(t, T_mean_annual, T_amplitude, summer_peak_day) T_column_ice = temperature(ice.enthalpy.get_column_vector(1, 1), P_coarse) T_column_ch = temperature(ch.enthalpy.get_column_vector(1, 1), P_coarse) if R > 0: Q = ch_heat_flux(T_column_ice, T_column_ch, k, R) else: Q = np.zeros_like(P_coarse) # add it to the strain heating term ice.strain_heating.set_column(1, 1, Q) ch.strain_heating.set_column(1, 1, -Q) if T_s > T_melting: E_s = EC.enthalpy(T_melting, 0.0, 0.0) else: E_s = EC.enthalpy(T_s, 0.0, 0.0) # set boundary conditions and update the ice column ice.init() ice.sys.set_surface_dirichlet_bc(E_s) ice.sys.set_basal_heat_flux(G) x = ice.sys.solve() T_ice.append(temperature(x, P)) W_ice.append(water_fraction(x, P)) ice.sys.fine_to_coarse(x, 1, 1, ice.enthalpy) if T_s > T_melting: E_s = EC.enthalpy(T_melting, omega, 0.0) # Re-set enthalpy in the CH system during the melt season ch.enthalpy.set_column(1, 1, enthalpy(melting_temperature(P), omega, P)) else: E_s = EC.enthalpy(T_s, 0.0, 0.0) # set boundary conditions and update the CH column ch.init() ch.sys.set_surface_dirichlet_bc(E_s) ch.sys.set_basal_heat_flux(G) x = ch.sys.solve() T_ch.append(temperature(x, P)) W_ch.append(water_fraction(x, P)) ch.sys.fine_to_coarse(x, 1, 1, ch.enthalpy) t += dt return z, np.array(times), np.array(T_ice), np.array(W_ice), np.array(T_ch), np.array(W_ch)
'long_name', "y-component of the 'observed' SIA velocities") vel_surface_observed = PISM.model.create2dVelocityVec( grid, "_surface_observed", "observed surface velocities", stencil_width=1) vel_surface_observed.copy_from(vel_sia_observed) vel_surface_observed.add(1., vel_ssa_observed) vecs.markForWriting(vel_surface_observed) final_velocity = vel_surface_observed # Add the misfit weight. if misfit_weight_type == "fast": misfit_weight = fastIceMisfitWeight( modeldata, vel_ssa, convert(fast_ice_speed, "m/year", "m/second")) else: misfit_weight = groundedIceMisfitWeight(modeldata) modeldata.vecs.add(misfit_weight, writing=True) if not noise is None: u_noise = PISM.vec.randVectorV(grid, noise / math.sqrt(2), final_velocity.stencil_width()) final_velocity.add(convert(1.0, "m/year", "m/second"), u_noise) pio = PISM.util.prepare_output(output_file_name) pio.close() vecs.write(output_file_name) # Save time & command line
* re-initializing * one more 1000 year step Used as a regression test for PISM.LingleClark. """ import PISM from PISM.util import convert import pylab as plt import numpy as np import os ctx = PISM.Context() # disc load parameters disc_radius = convert(1000, "km", "m") disc_thickness = 1000.0 # meters # domain size Lx = 2 * disc_radius Ly = Lx N = 101 dt = convert(1000.0, "years", "seconds") def allocate_storage(grid): ice_thickness = PISM.IceModelVec2S(grid, "thk", PISM.WITHOUT_GHOSTS) ice_thickness.metadata().set_string("standard_name", "land_ice_thickness") 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)
Testing program for PISM's implementations of the SSA. Does a time-independent calculation. Does not run IceModel or a derived class thereof. Uses the van der Veen flow-line shelf geometry. Also may be used in a PISM software (regression) test. """ usage = \ """ usage of SSA_TEST_CFBC: run ssa_test_cfbc -Mx <number> -My <number> """ context = PISM.Context() H0 = 600. # meters V0 = convert(300, "m/year", "m/second") C = 2.45e-18 # "typical constant ice parameter" T = 400 # time used to compute the calving front location Q0 = V0 * H0 Hc1 = 4. * C / Q0 Hc2 = 1. / (H0**4) def H_exact(x): return (Hc1 * x + Hc2)**(-1 / 4.) def u_exact(x): return Q0 / H_exact(x)
def run(): context = PISM.Context() config = context.config com = context.com PISM.set_abort_on_sigint(True) WIDE_STENCIL = int(config.get_double("grid.max_stencil_width")) usage = \ """ pismi.py [-i IN.nc [-o OUT.nc]]/[-a INOUT.nc] [-inv_data inv_data.nc] [-inv_forward model] [-inv_design design_var] [-inv_method meth] where: -i IN.nc is input file in NetCDF format: contains PISM-written model state -o OUT.nc is output file in NetCDF format to be overwritten -a INOUT.nc is input/output file in NetCDF format to be appended to -inv_data inv_data.nc is data file containing extra inversion data (e.g. observed surface velocities) -inv_forward model forward model: only 'ssa' supported -inv_design design_var design variable name; one of 'tauc'/'hardav' for SSA inversions -inv_method meth algorithm for inversion [sd,nlcg,ign,tikhonov_lmvm] notes: * only one of -i/-a is allowed; both specify the input file * only one of -o/-a is allowed; both specify the output file * if -o is used, only the variables involved in inversion are written to the output file. * if -a is used, the varaibles involved in inversion are appended to the given file. No original variables in the file are changed. """ append_mode = False input_filename = config.get_string("input.file") if len(input_filename) == 0: input_filename = None append = PISM.OptionString("-a", "append file") append_filename = append.value() if append.is_set() else None output_filename = config.get_string("output.file_name") if len(output_filename) == 0: output_filename = None if (input_filename is None) and (append_filename is None): PISM.verbPrintf(1, com, "\nError: No input file specified. Use one of -i [file.nc] or -a [file.nc].\n") sys.exit(0) if (input_filename is not None) and (append_filename is not None): PISM.verbPrintf(1, com, "\nError: Only one of -i/-a is allowed.\n") sys.exit(0) if (output_filename is not None) and (append_filename is not None): PISM.verbPrintf(1, com, "\nError: Only one of -a/-o is allowed.\n") sys.edit(0) if append_filename is not None: input_filename = append_filename output_filename = append_filename append_mode = True inv_data_filename = PISM.OptionString("-inv_data", "inverse data file", input_filename).value() do_plotting = PISM.OptionBool("-inv_plot", "perform visualization during the computation") do_final_plot = PISM.OptionBool("-inv_final_plot", "perform visualization at the end of the computation") Vmax = PISM.OptionReal("-inv_plot_vmax", "maximum velocity for plotting residuals", 30) design_var = PISM.OptionKeyword("-inv_ssa", "design variable for inversion", "tauc,hardav", "tauc").value() do_pause = PISM.OptionBool("-inv_pause", "pause each iteration") do_restart = PISM.OptionBool("-inv_restart", "Restart a stopped computation.") use_design_prior = config.get_boolean("inverse.use_design_prior") prep_module = PISM.OptionString("-inv_prep_module", "Python module used to do final setup of inverse solver") prep_module = prep_module.value() if prep_module.is_set() else None is_regional = PISM.OptionBool("-regional", "Compute SIA/SSA using regional model semantics") using_zeta_fixed_mask = config.get_boolean("inverse.use_zeta_fixed_mask") inv_method = config.get_string("inverse.ssa.method") if output_filename is None: output_filename = "pismi_" + os.path.basename(input_filename) saving_inv_data = (inv_data_filename != output_filename) forward_run = SSAForwardRun(input_filename, inv_data_filename, design_var) forward_run.setup() design_param = forward_run.designVariableParameterization() solver = PISM.invert.ssa.createInvSSASolver(forward_run) modeldata = forward_run.modeldata vecs = modeldata.vecs grid = modeldata.grid # Determine the prior guess for tauc/hardav. This can be one of # a) tauc/hardav from the input file (default) # b) tauc/hardav_prior from the inv_datafile if -inv_use_design_prior is set design_prior = createDesignVec(grid, design_var, '%s_prior' % design_var) long_name = design_prior.metadata().get_string("long_name") units = design_prior.metadata().get_string("units") design_prior.set_attrs("", "best prior estimate for %s (used for inversion)" % long_name, units, "") if PISM.util.fileHasVariable(inv_data_filename, "%s_prior" % design_var) and use_design_prior: PISM.logging.logMessage(" Reading '%s_prior' from inverse data file %s.\n" % (design_var, inv_data_filename)) design_prior.regrid(inv_data_filename, critical=True) vecs.add(design_prior, writing=saving_inv_data) else: if not PISM.util.fileHasVariable(input_filename, design_var): PISM.verbPrintf(1, com, "Initial guess for design variable is not available as '%s' in %s.\nYou can provide an initial guess in the inverse data file.\n" % ( design_var, input_filename)) exit(1) PISM.logging.logMessage("Reading '%s_prior' from '%s' in input file.\n" % (design_var, design_var)) design = createDesignVec(grid, design_var) design.regrid(input_filename, True) design_prior.copy_from(design) vecs.add(design_prior, writing=True) if using_zeta_fixed_mask: if PISM.util.fileHasVariable(inv_data_filename, "zeta_fixed_mask"): zeta_fixed_mask = PISM.model.createZetaFixedMaskVec(grid) zeta_fixed_mask.regrid(inv_data_filename) vecs.add(zeta_fixed_mask) else: if design_var == 'tauc': logMessage( " Computing 'zeta_fixed_mask' (i.e. locations where design variable '%s' has a fixed value).\n" % design_var) zeta_fixed_mask = PISM.model.createZetaFixedMaskVec(grid) zeta_fixed_mask.set(1) mask = vecs.mask with PISM.vec.Access(comm=zeta_fixed_mask, nocomm=mask): for (i, j) in grid.points(): if mask.grounded_ice(i, j): zeta_fixed_mask[i, j] = 0 vecs.add(zeta_fixed_mask) adjustTauc(vecs.mask, design_prior) elif design_var == 'hardav': PISM.logging.logPrattle( "Skipping 'zeta_fixed_mask' for design variable 'hardav'; no natural locations to fix its value.") pass else: raise NotImplementedError("Unable to build 'zeta_fixed_mask' for design variable %s.", design_var) # Convert design_prior -> zeta_prior zeta_prior = PISM.IceModelVec2S() zeta_prior.create(grid, "zeta_prior", PISM.WITH_GHOSTS, WIDE_STENCIL) design_param.convertFromDesignVariable(design_prior, zeta_prior) vecs.add(zeta_prior, writing=True) # Determine the initial guess for zeta. If we are restarting, load it from # the output file. Otherwise, if 'zeta_inv' is in the inverse data file, use it. # If none of the above, copy from 'zeta_prior'. zeta = PISM.IceModelVec2S() zeta.create(grid, "zeta_inv", PISM.WITH_GHOSTS, WIDE_STENCIL) zeta.set_attrs("diagnostic", "zeta_inv", "1", "zeta_inv") if do_restart: # Just to be sure, verify that we have a 'zeta_inv' in the output file. if not PISM.util.fileHasVariable(output_filename, 'zeta_inv'): PISM.verbPrintf( 1, com, "Unable to restart computation: file %s is missing variable 'zeta_inv'", output_filename) exit(1) PISM.logging.logMessage(" Inversion starting from 'zeta_inv' found in %s\n" % output_filename) zeta.regrid(output_filename, True) elif PISM.util.fileHasVariable(inv_data_filename, 'zeta_inv'): PISM.logging.logMessage(" Inversion starting from 'zeta_inv' found in %s\n" % inv_data_filename) zeta.regrid(inv_data_filename, True) else: zeta.copy_from(zeta_prior) vel_ssa_observed = None vel_ssa_observed = PISM.model.create2dVelocityVec(grid, '_ssa_observed', stencil_width=2) if PISM.util.fileHasVariable(inv_data_filename, "u_ssa_observed"): vel_ssa_observed.regrid(inv_data_filename, True) vecs.add(vel_ssa_observed, writing=saving_inv_data) else: if not PISM.util.fileHasVariable(inv_data_filename, "u_surface_observed"): PISM.verbPrintf( 1, context.com, "Neither u/v_ssa_observed nor u/v_surface_observed is available in %s.\nAt least one must be specified.\n" % inv_data_filename) exit(1) vel_surface_observed = PISM.model.create2dVelocityVec(grid, '_surface_observed', stencil_width=2) vel_surface_observed.regrid(inv_data_filename, True) vecs.add(vel_surface_observed, writing=saving_inv_data) sia_solver = PISM.SIAFD if is_regional: sia_solver = PISM.SIAFD_Regional vel_sia_observed = PISM.sia.computeSIASurfaceVelocities(modeldata, sia_solver) vel_sia_observed.metadata(0).set_name('u_sia_observed') vel_sia_observed.metadata(0).set_string('long_name', "x-component of the 'observed' SIA velocities") vel_sia_observed.metadata(1).set_name('v_sia_observed') vel_sia_observed.metadata(1).set_string('long_name', "y-component of the 'observed' SIA velocities") vel_ssa_observed.copy_from(vel_surface_observed) vel_ssa_observed.add(-1, vel_sia_observed) vecs.add(vel_ssa_observed, writing=True) # If the inverse data file has a variable tauc/hardav_true, this is probably # a synthetic inversion. We'll load it now so that it will get written # out, if needed, at the end of the computation in the output file. if PISM.util.fileHasVariable(inv_data_filename, "%s_true" % design_var): design_true = createDesignVec(grid, design_var, '%s_true' % design_var) design_true.regrid(inv_data_filename, True) design_true.read_attributes(inv_data_filename) vecs.add(design_true, writing=saving_inv_data) # Establish a logger which will save logging messages to the output file. message_logger = PISM.logging.CaptureLogger(output_filename, 'pismi_log') PISM.logging.add_logger(message_logger) if append_mode or do_restart: message_logger.readOldLog() # Prep the output file from the grid so that we can save zeta to it during the runs. if not append_mode: pio = PISM.util.prepare_output(output_filename) pio.close() zeta.write(output_filename) # Log the command line to the output file now so that we have a record of # what was attempted PISM.util.writeProvenance(output_filename) # Attach various iteration listeners to the solver as needed for: # Iteration report. solver.addIterationListener(PISM.invert.ssa.printIteration) # Misfit reporting/logging. misfit_logger = PISM.invert.ssa.MisfitLogger() solver.addIterationListener(misfit_logger) if inv_method.startswith('tikhonov'): solver.addIterationListener(PISM.invert.ssa.printTikhonovProgress) # Saving the current iteration solver.addDesignUpdateListener(PISM.invert.ssa.ZetaSaver(output_filename)) # Plotting if do_plotting: solver.addIterationListener(InvSSAPlotListener(grid, Vmax)) if solver.method == 'ign': solver.addLinearIterationListener(InvSSALinPlotListener(grid, Vmax)) # Solver is set up. Give the user's prep module a chance to do any final # setup. if prep_module is not None: if prep_module.endswith(".py"): prep_module = prep_module[0:-2] exec("import %s as user_prep_module" % prep_module) user_prep_module.prep_solver(solver) # Pausing (add this after the user's listeners) if do_pause: solver.addIterationListener(PISM.invert.listener.pauseListener) # Run the inverse solver! if do_restart: PISM.logging.logMessage('************** Restarting inversion. ****************\n') else: PISM.logging.logMessage('============== Starting inversion. ==================\n') # Try solving reason = solver.solveInverse(zeta_prior, vel_ssa_observed, zeta) if reason.failed(): PISM.logging.logError("Inverse solve FAILURE:\n%s\n" % reason.nested_description(1)) quit() PISM.logging.logMessage("Inverse solve success (%s)!\n" % reason.description()) (zeta, u) = solver.inverseSolution() # It may be that a 'tauc'/'hardav' was read in earlier. We replace it with # our newly generated one. if vecs.has(design_var): design = vecs.get(design_var) design_param.convertToDesignVariable(zeta, design) else: # Convert back from zeta to tauc or hardav design = createDesignVec(grid, design_var) design_param.convertToDesignVariable(zeta, design) vecs.add(design, writing=True) vecs.add(zeta, writing=True) u.metadata(0).set_name("u_ssa_inv") u.metadata(0).set_string("long_name", "x-component of SSA velocity computed by inversion") u.metadata(1).set_name("v_ssa_inv") u.metadata(1).set_string("long_name", "y-component of SSA velocity computed by inversion") vecs.add(u, writing=True) residual = PISM.model.create2dVelocityVec(grid, name='_inv_ssa_residual') residual.copy_from(u) residual.add(-1, vel_ssa_observed) r_mag = PISM.IceModelVec2S() r_mag.create(grid, "inv_ssa_residual", PISM.WITHOUT_GHOSTS, 0) r_mag.set_attrs("diagnostic", "magnitude of mismatch between observed surface velocities and their reconstrution by inversion", "m s-1", "inv_ssa_residual", 0) r_mag.metadata().set_double("_FillValue", convert(-0.01, 'm/year', 'm/s')) r_mag.metadata().set_double("valid_min", 0.0) r_mag.metadata().set_string("glaciological_units", "m year-1") r_mag.set_to_magnitude(residual) r_mag.mask_by(vecs.land_ice_thickness) vecs.add(residual, writing=True) vecs.add(r_mag, writing=True) # Write solution out to netcdf file forward_run.write(output_filename, append=append_mode) # If we're not in append mode, the previous command just nuked # the output file. So we rewrite the siple log. if not append_mode: message_logger.write(output_filename) # Save the misfit history misfit_logger.write(output_filename)
import numpy as np from PISM.util import convert config = PISM.Context().config log = PISM.Context().log # constants standard_gravity = config.get_double("constants.standard_gravity") ice_density = config.get_double("constants.ice.density") mantle_density = config.get_double("bed_deformation.mantle_density") mantle_viscosity = config.get_double("bed_deformation.mantle_viscosity") lithosphere_flexural_rigidity = config.get_double( "bed_deformation.lithosphere_flexural_rigidity") # disc load parameters disc_radius = convert(1000, "km", "m") disc_thickness = 1000.0 # meters # domain size Lx = 2 * disc_radius # time to use for the comparison T = convert(1e6, "years", "second") t_final = convert(20000, "years", "second") dt = convert(500, "years", "second") def deflection(time, radius, disc_thickness, disc_radius): """Compute the viscous plate deflection. See formula (17) in 'Fast computation of a viscoelastic deformable Earth model for ice-sheet simulations' by Bueler, Lingle, and Brown, 2007. """ return PISM.viscDisc(time, disc_thickness, disc_radius, radius,
def errors_ND(plot_results=True, T_final_years=1000.0, dt_years=100, Mz=101): """Test the enthalpy solver with Neumann B.C. at the base and Dirichlet B.C. at the top surface. """ T_final = convert(T_final_years, "years", "seconds") dt = convert(dt_years, "years", "seconds") column = EnthalpyColumn(Mz, dt) Lz = column.Lz z = np.array(column.sys.z()) E_base = EC.enthalpy(240.0, 0.0, EC.pressure(Lz)) E_surface = EC.enthalpy(260.0, 0.0, 0.0) dE_base = (E_surface - E_base) / Lz E_steady = E_surface + dE_base * (z - Lz) Q_base = -K * dE_base E_exact = exact_ND(Lz, dE_base, E_surface) with PISM.vec.Access(nocomm=[ column.enthalpy, column.u, column.v, column.w, column.strain_heating ]): column.sys.fine_to_coarse(E_exact(z, 0), 1, 1, column.enthalpy) column.reset_flow() column.reset_strain_heating() t = 0.0 while t < T_final: column.init_column() column.sys.set_basal_heat_flux(Q_base) column.sys.set_surface_dirichlet_bc(E_surface) x = column.sys.solve() column.sys.fine_to_coarse(x, 1, 1, column.enthalpy) t += dt E_exact_final = E_exact(z, t) if plot_results: t_years = convert(t, "seconds", "years") plt.figure() plt.xlabel("z, meters") plt.ylabel("E, J/kg") plt.step(z, E_exact(z, 0), color="blue", label="initial condition") plt.step(z, E_exact_final, color="green", label="exact solution") plt.step(z, cts(pressure(Lz - z)), "--", color="black", label="CTS") plt.step(z, E_steady, "--", color="green", label="steady state profile") plt.grid(True) plt.step(z, x, label="T={} years".format(t_years), color="red") plt.legend(loc="best") errors = E_exact(z, t) - x max_error = np.max(np.fabs(errors)) avg_error = np.average(np.fabs(errors)) return max_error, avg_error
inputs = PISM.EnergyModelInputs() inputs.cell_type = cell_type inputs.basal_frictional_heating = zero inputs.basal_heat_flux = basal_heat_flux inputs.ice_thickness = ice_thickness inputs.surface_liquid_fraction = zero inputs.shelf_base_temp = shelf_base_temp inputs.surface_temp = surface_temp inputs.till_water_thickness = zero inputs.volumetric_heating_rate = strain_heating3 inputs.u3 = u inputs.v3 = v inputs.w3 = w dt = convert(1, "years", "seconds") def use_model(model): print("* Performing a time step...") model.update(0, dt, inputs) try: model.update(0, dt) raise Exception("this should fail") except TypeError: pass print(model.stdout_flags()) stats = model.stats() enthalpy = model.enthalpy() bmr = model.basal_melt_rate()
Testing program for PISM's implementations of the SSA. Does a time-independent calculation. Does not run IceModel or a derived class thereof. Uses the van der Veen flow-line shelf geometry. Also may be used in a PISM software (regression) test. """ usage = \ """ usage of SSA_TEST_CFBC: run ssa_test_cfbc -Mx <number> -My <number> """ context = PISM.Context() H0 = 600. # meters V0 = convert(300, "m/year", "m/second") C = 2.45e-18 # "typical constant ice parameter" T = 400 # time used to compute the calving front location Q0 = V0 * H0 Hc1 = 4. * C / Q0 Hc2 = 1. / (H0 ** 4) def H_exact(x): return (Hc1 * x + Hc2) ** (-1 / 4.) def u_exact(x): return Q0 / H_exact(x)
def run(scenario, plot, pause, save): # set grid defaults config.set_number("grid.Mx", 193) config.set_number("grid.My", 129) config.set_number("grid.Lx", 3000e3) config.set_number("grid.Ly", 2000e3) config.set_number("grid.Mz", 2) config.set_number("grid.Lz", 1000) scenarios = { "1": (False, False, 1000.0), "2": (True, False, 1000.0), "3": (False, True, 0.0), "4": (True, True, 1000.0) } elastic, use_uplift, H0 = scenarios[scenario] print("Using scenario %s: elastic model = %s, use uplift = %s, H0 = %f m" % (scenario, elastic, use_uplift, H0)) config.set_flag("bed_deformation.lc.elastic_model", elastic) grid = create_grid() thickness, bed, uplift, sea_level = allocate(grid) # set initial geometry and uplift bed.set(0.0) thickness.set(0.0) sea_level.set(0.0) if use_uplift: initialize_uplift(uplift) time = ctx.ctx.time() time.init(ctx.ctx.log()) model = PISM.LingleClark(grid) model.bootstrap(bed, uplift, thickness, sea_level) # now add the disc load initialize_thickness(thickness, H0) dt = convert(100, "365 day", "seconds") # the time-stepping loop while time.current() < time.end(): # don't go past the end of the run dt_current = min(dt, time.end() - time.current()) model.update(thickness, sea_level, time.current(), dt_current) if plot: model.bed_elevation().view(400) model.uplift().view(400) print("t = %s years, dt = %s years" % (time.date(), time.convert_time_interval(dt_current, "years"))) time.step(dt_current) print("Reached t = %s years" % time.date()) if pause: print("Pausing for 5 seconds...") PISM.PETSc.Sys.sleep(5) if save: model.bed_elevation().dump("bed_elevation.nc") model.uplift().dump("bed_uplift.nc")
def run(): context = PISM.Context() config = context.config com = context.com PISM.set_abort_on_sigint(True) WIDE_STENCIL = int(config.get_number("grid.max_stencil_width")) usage = \ """ pismi.py [-i IN.nc [-o OUT.nc]]/[-a INOUT.nc] [-inv_data inv_data.nc] [-inv_forward model] [-inv_design design_var] [-inv_method meth] where: -i IN.nc is input file in NetCDF format: contains PISM-written model state -o OUT.nc is output file in NetCDF format to be overwritten -a INOUT.nc is input/output file in NetCDF format to be appended to -inv_data inv_data.nc is data file containing extra inversion data (e.g. observed surface velocities) -inv_forward model forward model: only 'ssa' supported -inv_design design_var design variable name; one of 'tauc'/'hardav' for SSA inversions -inv_method meth algorithm for inversion [sd,nlcg,ign,tikhonov_lmvm] notes: * only one of -i/-a is allowed; both specify the input file * only one of -o/-a is allowed; both specify the output file * if -o is used, only the variables involved in inversion are written to the output file. * if -a is used, the varaibles involved in inversion are appended to the given file. No original variables in the file are changed. """ append_mode = False input_filename = config.get_string("input.file") if len(input_filename) == 0: input_filename = None append = PISM.OptionString("-a", "append file") append_filename = append.value() if append.is_set() else None output_filename = config.get_string("output.file_name") if len(output_filename) == 0: output_filename = None if (input_filename is None) and (append_filename is None): PISM.verbPrintf( 1, com, "\nError: No input file specified. Use one of -i [file.nc] or -a [file.nc].\n" ) sys.exit(0) if (input_filename is not None) and (append_filename is not None): PISM.verbPrintf(1, com, "\nError: Only one of -i/-a is allowed.\n") sys.exit(0) if (output_filename is not None) and (append_filename is not None): PISM.verbPrintf(1, com, "\nError: Only one of -a/-o is allowed.\n") sys.edit(0) if append_filename is not None: input_filename = append_filename output_filename = append_filename append_mode = True inv_data_filename = PISM.OptionString("-inv_data", "inverse data file", input_filename).value() do_plotting = PISM.OptionBool( "-inv_plot", "perform visualization during the computation") do_final_plot = PISM.OptionBool( "-inv_final_plot", "perform visualization at the end of the computation") Vmax = PISM.OptionReal(context.unit_system, "-inv_plot_vmax", "maximum velocity for plotting residuals", "m / year", 30) design_var = PISM.OptionKeyword("-inv_ssa", "design variable for inversion", "tauc,hardav", "tauc").value() do_pause = PISM.OptionBool("-inv_pause", "pause each iteration") do_restart = PISM.OptionBool("-inv_restart", "Restart a stopped computation.") use_design_prior = config.get_flag("inverse.use_design_prior") prep_module = PISM.OptionString( "-inv_prep_module", "Python module used to do final setup of inverse solver") prep_module = prep_module.value() if prep_module.is_set() else None is_regional = PISM.OptionBool( "-regional", "Compute SIA/SSA using regional model semantics") using_zeta_fixed_mask = config.get_flag("inverse.use_zeta_fixed_mask") inv_method = config.get_string("inverse.ssa.method") if output_filename is None: output_filename = "pismi_" + os.path.basename(input_filename) saving_inv_data = (inv_data_filename != output_filename) forward_run = SSAForwardRun(input_filename, inv_data_filename, design_var) forward_run.setup() design_param = forward_run.designVariableParameterization() solver = PISM.invert.ssa.createInvSSASolver(forward_run) modeldata = forward_run.modeldata vecs = modeldata.vecs grid = modeldata.grid # Determine the prior guess for tauc/hardav. This can be one of # a) tauc/hardav from the input file (default) # b) tauc/hardav_prior from the inv_datafile if -inv_use_design_prior is set design_prior = createDesignVec(grid, design_var, '%s_prior' % design_var) long_name = design_prior.metadata().get_string("long_name") units = design_prior.metadata().get_string("units") design_prior.set_attrs( "", "best prior estimate for %s (used for inversion)" % long_name, units, units, "", 0) if PISM.util.fileHasVariable(inv_data_filename, "%s_prior" % design_var) and use_design_prior: PISM.logging.logMessage( " Reading '%s_prior' from inverse data file %s.\n" % (design_var, inv_data_filename)) design_prior.regrid(inv_data_filename, critical=True) vecs.add(design_prior, writing=saving_inv_data) else: if not PISM.util.fileHasVariable(input_filename, design_var): PISM.verbPrintf( 1, com, "Initial guess for design variable is not available as '%s' in %s.\nYou can provide an initial guess in the inverse data file.\n" % (design_var, input_filename)) exit(1) PISM.logging.logMessage( "Reading '%s_prior' from '%s' in input file.\n" % (design_var, design_var)) design = createDesignVec(grid, design_var) design.regrid(input_filename, True) design_prior.copy_from(design) vecs.add(design_prior, writing=True) if using_zeta_fixed_mask: if PISM.util.fileHasVariable(inv_data_filename, "zeta_fixed_mask"): zeta_fixed_mask = PISM.model.createZetaFixedMaskVec(grid) zeta_fixed_mask.regrid(inv_data_filename) vecs.add(zeta_fixed_mask) else: if design_var == 'tauc': logMessage( " Computing 'zeta_fixed_mask' (i.e. locations where design variable '%s' has a fixed value).\n" % design_var) zeta_fixed_mask = PISM.model.createZetaFixedMaskVec(grid) zeta_fixed_mask.set(1) mask = vecs.mask with PISM.vec.Access(comm=zeta_fixed_mask, nocomm=mask): for (i, j) in grid.points(): if mask.grounded_ice(i, j): zeta_fixed_mask[i, j] = 0 vecs.add(zeta_fixed_mask) adjustTauc(vecs.mask, design_prior) elif design_var == 'hardav': PISM.logging.logPrattle( "Skipping 'zeta_fixed_mask' for design variable 'hardav'; no natural locations to fix its value." ) pass else: raise NotImplementedError( "Unable to build 'zeta_fixed_mask' for design variable %s.", design_var) # Convert design_prior -> zeta_prior zeta_prior = PISM.IceModelVec2S(grid, "zeta_prior", PISM.WITH_GHOSTS, WIDE_STENCIL) design_param.convertFromDesignVariable(design_prior, zeta_prior) vecs.add(zeta_prior, writing=True) # Determine the initial guess for zeta. If we are restarting, load it from # the output file. Otherwise, if 'zeta_inv' is in the inverse data file, use it. # If none of the above, copy from 'zeta_prior'. zeta = PISM.IceModelVec2S(grid, "zeta_inv", PISM.WITH_GHOSTS, WIDE_STENCIL) zeta.set_attrs("diagnostic", "zeta_inv", "1", "1", "zeta_inv", 0) if do_restart: # Just to be sure, verify that we have a 'zeta_inv' in the output file. if not PISM.util.fileHasVariable(output_filename, 'zeta_inv'): PISM.verbPrintf( 1, com, "Unable to restart computation: file %s is missing variable 'zeta_inv'", output_filename) exit(1) PISM.logging.logMessage( " Inversion starting from 'zeta_inv' found in %s\n" % output_filename) zeta.regrid(output_filename, True) elif PISM.util.fileHasVariable(inv_data_filename, 'zeta_inv'): PISM.logging.logMessage( " Inversion starting from 'zeta_inv' found in %s\n" % inv_data_filename) zeta.regrid(inv_data_filename, True) else: zeta.copy_from(zeta_prior) vel_ssa_observed = None vel_ssa_observed = PISM.model.create2dVelocityVec(grid, '_ssa_observed', stencil_width=2) if PISM.util.fileHasVariable(inv_data_filename, "u_ssa_observed"): vel_ssa_observed.regrid(inv_data_filename, True) vecs.add(vel_ssa_observed, writing=saving_inv_data) else: if not PISM.util.fileHasVariable(inv_data_filename, "u_surface_observed"): PISM.verbPrintf( 1, context.com, "Neither u/v_ssa_observed nor u/v_surface_observed is available in %s.\nAt least one must be specified.\n" % inv_data_filename) exit(1) vel_surface_observed = PISM.model.create2dVelocityVec( grid, '_surface_observed', stencil_width=2) vel_surface_observed.regrid(inv_data_filename, True) vecs.add(vel_surface_observed, writing=saving_inv_data) sia_solver = PISM.SIAFD if is_regional: sia_solver = PISM.SIAFD_Regional vel_sia_observed = PISM.sia.computeSIASurfaceVelocities( modeldata, sia_solver) vel_sia_observed.metadata(0).set_name('u_sia_observed') vel_sia_observed.metadata(0).set_string( 'long_name', "x-component of the 'observed' SIA velocities") vel_sia_observed.metadata(1).set_name('v_sia_observed') vel_sia_observed.metadata(1).set_string( 'long_name', "y-component of the 'observed' SIA velocities") vel_ssa_observed.copy_from(vel_surface_observed) vel_ssa_observed.add(-1, vel_sia_observed) vecs.add(vel_ssa_observed, writing=True) # If the inverse data file has a variable tauc/hardav_true, this is probably # a synthetic inversion. We'll load it now so that it will get written # out, if needed, at the end of the computation in the output file. if PISM.util.fileHasVariable(inv_data_filename, "%s_true" % design_var): design_true = createDesignVec(grid, design_var, '%s_true' % design_var) design_true.regrid(inv_data_filename, True) try: f = PISM.File(com, inv_data_filename, PISM.PISM_NETCDF3, PISM.PISM_READONLY) PISM.read_attributes(f, design_true.get_name(), design_true.metadata()) finally: f.close() vecs.add(design_true, writing=saving_inv_data) # Establish a logger which will save logging messages to the output file. message_logger = PISM.logging.CaptureLogger(output_filename, 'pismi_log') PISM.logging.add_logger(message_logger) if append_mode or do_restart: message_logger.readOldLog() # Prep the output file from the grid so that we can save zeta to it during the runs. if not append_mode: pio = PISM.util.prepare_output(output_filename) pio.close() zeta.write(output_filename) # Log the command line to the output file now so that we have a record of # what was attempted PISM.util.writeProvenance(output_filename) # Attach various iteration listeners to the solver as needed for: # Iteration report. solver.addIterationListener(PISM.invert.ssa.printIteration) # Misfit reporting/logging. misfit_logger = PISM.invert.ssa.MisfitLogger() solver.addIterationListener(misfit_logger) if inv_method.startswith('tikhonov'): solver.addIterationListener(PISM.invert.ssa.printTikhonovProgress) # Saving the current iteration solver.addDesignUpdateListener(PISM.invert.ssa.ZetaSaver(output_filename)) # Plotting if do_plotting: solver.addIterationListener(InvSSAPlotListener(grid, Vmax)) if solver.method == 'ign': solver.addLinearIterationListener(InvSSALinPlotListener( grid, Vmax)) # Solver is set up. Give the user's prep module a chance to do any final # setup. if prep_module is not None: if prep_module.endswith(".py"): prep_module = prep_module[0:-2] exec("import %s as user_prep_module" % prep_module) user_prep_module.prep_solver(solver) # Pausing (add this after the user's listeners) if do_pause: solver.addIterationListener(PISM.invert.listener.pauseListener) # Run the inverse solver! if do_restart: PISM.logging.logMessage( '************** Restarting inversion. ****************\n') else: PISM.logging.logMessage( '============== Starting inversion. ==================\n') # Try solving reason = solver.solveInverse(zeta_prior, vel_ssa_observed, zeta) if reason.failed(): PISM.logging.logError("Inverse solve FAILURE:\n%s\n" % reason.nested_description(1)) quit() PISM.logging.logMessage("Inverse solve success (%s)!\n" % reason.description()) (zeta, u) = solver.inverseSolution() # It may be that a 'tauc'/'hardav' was read in earlier. We replace it with # our newly generated one. if vecs.has(design_var): design = vecs.get(design_var) design_param.convertToDesignVariable(zeta, design) else: # Convert back from zeta to tauc or hardav design = createDesignVec(grid, design_var) design_param.convertToDesignVariable(zeta, design) vecs.add(design, writing=True) vecs.add(zeta, writing=True) u.metadata(0).set_name("u_ssa_inv") u.metadata(0).set_string( "long_name", "x-component of SSA velocity computed by inversion") u.metadata(1).set_name("v_ssa_inv") u.metadata(1).set_string( "long_name", "y-component of SSA velocity computed by inversion") vecs.add(u, writing=True) residual = PISM.model.create2dVelocityVec(grid, name='_inv_ssa_residual') residual.copy_from(u) residual.add(-1, vel_ssa_observed) r_mag = PISM.IceModelVec2S(grid, "inv_ssa_residual", PISM.WITHOUT_GHOSTS, 0) r_mag.set_attrs( "diagnostic", "magnitude of mismatch between observed surface velocities and their reconstrution by inversion", "m s-1", "m year-1", "inv_ssa_residual", 0) r_mag.metadata().set_number("_FillValue", convert(-0.01, 'm/year', 'm/s')) r_mag.metadata().set_number("valid_min", 0.0) PISM.compute_magnitude(residual, r_mag) PISM.apply_mask(vecs.land_ice_thickness, 0.0, r_mag) vecs.add(residual, writing=True) vecs.add(r_mag, writing=True) # Write solution out to netcdf file (always append because the file was created already) forward_run.write(output_filename, append=True) # If we're not in append mode, the previous command just nuked # the output file. So we rewrite the siple log. if not append_mode: message_logger.write(output_filename) # Save the misfit history misfit_logger.write(output_filename)
def errors_ND(plot_results=True, T_final_years=1000.0, dt_years=100, Mz=101): """Test the enthalpy solver with Neumann B.C. at the base and Dirichlet B.C. at the top surface. """ T_final = convert(T_final_years, "years", "seconds") dt = convert(dt_years, "years", "seconds") column = EnthalpyColumn(Mz, dt) Lz = column.Lz z = np.array(column.sys.z()) E_base = EC.enthalpy(240.0, 0.0, EC.pressure(Lz)) E_surface = EC.enthalpy(260.0, 0.0, 0.0) dE_base = (E_surface - E_base) / Lz E_steady = E_surface + dE_base * (z - Lz) Q_base = - K * dE_base E_exact = exact_ND(Lz, dE_base, E_surface) with PISM.vec.Access(nocomm=[column.enthalpy, column.u, column.v, column.w, column.strain_heating]): column.sys.fine_to_coarse(E_exact(z, 0), 1, 1, column.enthalpy) column.reset_flow() column.reset_strain_heating() t = 0.0 while t < T_final: column.init_column() column.sys.set_basal_heat_flux(Q_base) column.sys.set_surface_dirichlet_bc(E_surface) x = column.sys.solve() column.sys.fine_to_coarse(x, 1, 1, column.enthalpy) t += dt E_exact_final = E_exact(z, t) if plot_results: t_years = convert(t, "seconds", "years") plt.figure() plt.xlabel("z, meters") plt.ylabel("E, J/kg") plt.step(z, E_exact(z, 0), color="blue", label="initial condition") plt.step(z, E_exact_final, color="green", label="exact solution") plt.step(z, cts(pressure(Lz - z)), "--", color="black", label="CTS") plt.step(z, E_steady, "--", color="green", label="steady state profile") plt.grid(True) plt.step(z, x, label="T={} years".format(t_years), color="red") plt.legend(loc="best") errors = E_exact(z, t) - x max_error = np.max(np.fabs(errors)) avg_error = np.average(np.fabs(errors)) return max_error, avg_error