#! /usr/bin/env python # # Copyright (C) 2011, 2012, 2014 David Maxwell # # This file is part of PISM. # # PISM is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License as published by the Free Software # Foundation; either version 3 of the License, or (at your option) any later # version. # # PISM is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more # details. # # 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 import util import numpy as np import math import siple siple.reporting.clear_loggers() siple.reporting.add_logger(PISM.invert.sipletools.pism_logger) siple.reporting.set_pause_callback(PISM.invert.sipletools.pism_pause) import matplotlib.pyplot as pp class PlotListener(PISM.invert.listener.PlotListener): def __call__(self,inv_solver,it,data): grid = self.grid zeta = self.toproczero(data.zeta) u = self.toproczero(data.u) if inv_solver.method.startswith('tikhonov'): eta = data.tikhonov_penalty sWeight=1 dWeight=1/eta grad_zeta = self.toproczero(data.grad_JDesign) grad_u = self.toproczero(data.grad_JState) grad= self.toproczero(data.grad_JTikhonov) else: r = self.toproczero(data.residual) if zeta is not None: pp.figure(self.figure()) pp.clf() pp.subplot(1,3,1) pp.plot(grid.y,zeta[:,grid.Mx/2]) mag = np.max(np.abs(u)) pp.subplot(1,3,2) pp.plot(grid.y,u[0,:,grid.Mx/2]/mag) pp.subplot(1,3,3) if inv_solver.method.startswith('tikhonov'): pp.plot(grid.y,-grad_zeta[:,grid.Mx/2]*dWeight,grid.y,grad_u[:,grid.Mx/2]*sWeight,grid.y,grad[:,grid.Mx/2]) else: pp.plot(grid.y,r[0,:,grid.Mx/2]) pp.ion() pp.show() class LinPlotListener(PISM.invert.listener.PlotListener): def __call__(self,inv_solver,it,data): grid = self.grid x = self.toproczero(data.x) if x is not None: pp.figure(self.figure()) pp.clf() mag = np.max(np.abs(x)); if mag==0 : mag = 1 pp.plot(grid.y,x[:,grid.Mx/2]/mag) pp.ion() pp.show() Mx = 11 My = 61 kFEMStencilWidth = 1 m_schoof = 2; # (pure number) L_schoof = 40e3; # meters aspect_schoof = 0.05; # (pure) H0_schoof = aspect_schoof * L_schoof; # = 2000 m THICKNESS B_schoof = 3.7e8; # Pa s^{1/3}; hardness # given on p. 239 of Schoof; why so big? p_schoof = 4.0/3.0; # = 1 + 1/n slope = 0.001 right_side_weight = 1. tauc_guess_scale = 0.3 tauc_guess_const = None def testi_tauc(grid, tauc): standard_gravity = grid.config.get("standard_gravity"); ice_density = grid.config.get("ice_density"); f = ice_density * standard_gravity * H0_schoof * slope with PISM.vec.Access(comm=tauc): for (i,j) in grid.points(): y=grid.y[j] tauc[i,j] = f* (abs(y/L_schoof)**m_schoof) class testi_run(PISM.invert.ssa.SSATaucForwardRun): def __init__(self,Mx,My): self.grid = PISM.Context().newgrid() self.Mx = Mx self.My = My 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)) ) PISM.model.initShallowGrid(self.grid,Lx,Ly,Mx,My,PISM.X_PERIODIC); def _initPhysics(self): config = self.config config.set_flag("do_pseudo_plastic_till", False) # irrelevant enthalpyconverter = PISM.EnthalpyConverter(config); config.set_string("ssa_flow_law", "isothermal_glen") config.set_double("ice_softness", pow(3.7e8, -config.get("Glen_exponent"))) self.modeldata.setPhysics(enthalpyconverter) def _initSSACoefficients(self): vecs = self.modeldata.vecs; grid = self.grid vecs.add( model.createIceThicknessVec( grid ), 'thickness') vecs.add( model.createBedrockElevationVec(grid), 'bed') vecs.add( model.createYieldStressVec( grid ), 'tauc') vecs.add( model.createEnthalpyVec( grid ), 'enthalpy' ) vecs.add( model.createIceMaskVec( grid ), 'ice_mask' ) vecs.add( model.createDrivingStressXVec( grid ) ) vecs.add( model.createDrivingStressYVec( grid ) ) vecs.add( model.createVelocityMisfitWeightVec(grid) ) self._allocateBCs() vecs.thickness.set(H0_schoof) vecs.ice_mask.set(PISM.MASK_GROUNDED) vecs.bed.set(0.) testi_tauc(self.modeldata.grid, vecs.tauc) grid = self.grid standard_gravity = grid.config.get("standard_gravity"); ice_density = grid.config.get("ice_density"); f = ice_density * standard_gravity * H0_schoof * slope vecs.ssa_driving_stress_y.set(0) vecs.ssa_driving_stress_x.set(f) with PISM.vec.Access(comm=[vecs.bc_mask,vecs.vel_bc]): for (i,j) in grid.points(): if (j == 0) or (j==grid.My-1): vecs.bc_mask[i,j]=1 vecs.vel_bc[i,j].u=0 vecs.vel_bc[i,j].v=0 misfit_weight=vecs.vel_misfit_weight with PISM.vec.Access(comm=misfit_weight): for (i,j) in grid.points(): if grid.y[j] <= 0: misfit_weight[i,j] = 1.; else: misfit_weight[i,j] = right_side_weight; ## Main code starts here if __name__ == "__main__": context = PISM.Context() config = context.config PISM.set_abort_on_sigint(True) for o in PISM.OptionsGroup(context.com,"","Invert test I"): Mx = PISM.optionsInt("-Mx","Number of grid points in x-direction",default=Mx) My = PISM.optionsInt("-My","Number of grid points in y-direction",default=My) output_file = PISM.optionsString("-o","output file",default="invert_testi.nc") verbosity = PISM.optionsInt("-verbose","verbosity level",default=2) right_side_weight = PISM.optionsReal("-right_side_weight","L2 weight for y>0",default=right_side_weight) tauc_guess_scale = PISM.optionsReal("-tauc_guess_scale","initial guess for tauc to be this factor of the true value",default=tauc_guess_scale) tauc_guess_const = PISM.optionsReal("-tauc_guess_const","initial guess for tauc to be this constant",default=tauc_guess_const) do_plotting = PISM.optionsFlag("-inv_plot","perform visualization during the computation",default=False) do_final_plot = PISM.optionsFlag("-inv_final_plot","perform visualization at the end of the computation",default=True) do_pause = PISM.optionsFlag("-inv_pause","pause each iteration",default=False) test_adjoint = PISM.optionsFlag("-inv_test_adjoint","Test that the adjoint is working",default=False) inv_method = config.get_string("inv_ssa_method") length_scale = L_schoof slope = 0.001 standard_gravity = config.get("standard_gravity"); ice_density = config.get("ice_density"); f0 = ice_density * standard_gravity * H0_schoof * slope stress_scale = f0 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)) ) area_scale = Lx*Ly depth_scale = H0_schoof B = B_schoof velocity_scale = (f0/B)**(3.)*(length_scale/depth_scale)**(3.)*length_scale time_scale = length_scale / velocity_scale strainrate_scale = 1./ time_scale viscosity_scale = B*(strainrate_scale**(-2./3.)) nuH_scale = viscosity_scale * depth_scale PISM.setVerbosityLevel(verbosity) testi = testi_run(Mx,My) testi.setup() solver = PISM.invert.ssa.createInvSSASolver(testi) tauc_param = solver.ssarun.designVariableParameterization() grid = testi.grid # Build the true yeild stress for test I tauc_true = PISM.model.createYieldStressVec(grid,name="tauc_true") testi_tauc(grid, tauc_true) # Convert tauc_true to zeta_true zeta_true = PISM.IceModelVec2S(); zeta_true.create(grid,"zeta_true",PISM.WITH_GHOSTS,kFEMStencilWidth) tauc_param = PISM.invert.ssa.createDesignVariableParam(config,'tauc') tauc_param.convertFromDesignVariable(tauc_true,zeta_true) # Build the initial guess for tauc for the inversion. tauc = PISM.model.createYieldStressVec(grid) if not tauc_guess_const is None: tauc.set(tauc_guess_const) else: testi_tauc(grid, tauc) tauc.scale(tauc_guess_scale) # Convert tauc guess to zeta guess zeta0 = PISM.IceModelVec2S(); zeta0.create(grid, "zeta", PISM.WITH_GHOSTS, kFEMStencilWidth) tauc_param.convertFromDesignVariable(tauc,zeta0) if test_adjoint: if solver.method.startswith('tikhonov'): siple.reporting.msg("option -inv_test_adjoint cannot be used with inverse method %s",solver.method) exit(1) from PISM.invert.sipletools import PISMLocalVector as PLV stencil_width=1 forward_problem = solver.forward_problem d = PLV(PISM.vec.randVectorS(grid,1e5,stencil_width)) r = PLV(PISM.vec.randVectorV(grid, grid.convert(1.0, "m/year", "m/second"), stencil_width)) (domainIP,rangeIP)=forward_problem.testTStar(PLV(zeta0),d,r,3) siple.reporting.msg("domainip %g rangeip %g",domainIP,rangeIP) exit(0) # Setup the output file. pio = PISM.PIO(grid.com,"netcdf3") pio.open(output_file,PISM.NC_WRITE,False) pio.def_time(grid.config.get_string("time_dimension_name"), grid.config.get_string("calendar"), grid.time.units_string()) pio.append_time(grid.config.get_string("time_dimension_name"),grid.time.current()) pio.close() zeta0.write(output_file) # Send the true yeild stress through the forward problem to # get at true velocity field. u_obs = PISM.model.create2dVelocityVec( grid, name='_ssa_true', desc='SSA velocity boundary condition',intent='intent' ) solver.solveForward(zeta_true,out=u_obs) # Attach various iteration listeners to the solver as needed for: # progress reporting, if inv_method.startswith('tikhonov'): solver.addIterationListener(PISM.invert.ssa.PrintTikhonovProgress) # Plotting if do_plotting: solver.addIterationListener(PlotListener(grid)) if inv_method=='ign': solver.addLinearIterationListener(LinPlotListener(grid)) # Pausing if do_pause: solver.addIterationListener(PISM.invert.listener.pauseListener) # Iteration saving solver.addDesignUpdateListener(PISM.invert.ssa.ZetaSaver(output_file)) # Try solving reason = solver.solveInverse(zeta0,u_obs,zeta0) if reason.failed(): PISM.verbPrintf(1,grid.com,"Inverse solve FAILURE (%s)!\n" % reason.description()); quit() PISM.verbPrintf(1,grid.com,"Inverse solve success (%s)!\n" % reason.description()); (zeta_i,u_i) = solver.inverseSolution() tauc_param.convertToDesignVariable(zeta_i,tauc) # Write solution out to netcdf file testi.write(output_file) tauc.write(output_file) tauc_true.write(output_file) u_i.set_name("_computed",0) u_i.write(output_file) u_obs.write(output_file) # Draw a pretty picture tz = PISM.vec.ToProcZero(grid) tauc_a = tz.communicate(tauc) tauc_true = tz.communicate(tauc_true) tz2 = PISM.vec.ToProcZero(grid,dof=2,dim=2) u_i_a = tz2.communicate(u_i) u_obs_a = tz2.communicate(u_obs) secpera = grid.convert(1.0, "year", "seconds") if do_final_plot and (not tauc_a is None): from matplotlib import pyplot pyplot.clf() pyplot.subplot(1,2,1) pyplot.plot(grid.y,tauc_a[:,Mx/2]) pyplot.plot(grid.y,tauc_true[:,Mx/2]) pyplot.subplot(1,2,2) pyplot.plot(grid.y,u_i_a[0,:,Mx/2]*secpera) pyplot.plot(grid.y,u_obs_a[0,:,Mx/2]*secpera) pyplot.ion() pyplot.show() siple.reporting.endpause()