def vert_integrate(self, u): """ Integrate <u> from the surface to the bed. """ s = '::: vertically integrating function :::' print_text(s, self.D1Model_color) ff = self.ff Q = self.Q phi = TestFunction(Q) v = TrialFunction(Q) # surface Dirichlet boundary : def surface(x, on_boundary): return on_boundary and x[0] == self.S_bc # integral is zero on surface bcs = DirichletBC(Q, 0.0, surface) a = v.dx(0) * phi * dx L = u * phi * dx v = Function(Q) solve(a == L, v, bcs, annotate=False) print_min_max(v, 'vertically integrated function') #print_min_max(v, 'vertically integrated %s' % u.name()) return v
def solve(self, annotate=False): """ Perform the Newton solve of the full-Stokes equations """ model = self.model params = self.solve_params # solve nonlinear system : rtol = params['solver']['newton_solver']['relative_tolerance'] maxit = params['solver']['newton_solver']['maximum_iterations'] alpha = params['solver']['newton_solver']['relaxation_parameter'] s = "::: solving BP horizontal velocity with %i max iterations" + \ " and step size = %.1f :::" print_text(s % (maxit, alpha), self.color()) # zero out self.velocity for good convergence for any subsequent solves, # e.g. model.L_curve() : model.assign_variable(self.get_U(), DOLFIN_EPS, cls=self) # compute solution : solve(self.mom_F == 0, self.G, J = self.mom_Jac, bcs = self.mom_bcs, annotate = annotate, solver_parameters = params['solver']) U, p = self.G.split() u, v, w = split(U) self.assx.assign(model.u, project(u, model.Q, annotate=False), annotate=False) self.assy.assign(model.v, project(v, model.Q, annotate=False), annotate=False) self.assz.assign(model.w, project(w, model.Q, annotate=False), annotate=False) self.assp.assign(model.p, p, annotate=False) print_min_max(model.U3, 'U', cls=self) print_min_max(model.p, 'p', cls=self)
def init_rho(self, rho): """ """ s = "::: initializing density :::" print_text(s, self.D1Model_color) self.assign_variable(self.rho, rho) print_min_max(self.rho, 'rho')
def vert_integrate(self, u, d='up', Q='self'): """ Integrate <u> from the bed to the surface. """ s = "::: vertically integrating function :::" print_text(s, cls=self) if type(Q) != FunctionSpace: Q = self.Q ff = self.ff phi = TestFunction(Q) v = TrialFunction(Q) bcs = [] # integral is zero on bed (ff = 3,5) if d == 'up': bcs.append(DirichletBC(Q, 0.0, ff, self.GAMMA_B_GND)) # grounded bcs.append(DirichletBC(Q, 0.0, ff, self.GAMMA_B_FLT)) # shelves a = v.dx(2) * phi * dx # integral is zero on surface (ff = 2,6) elif d == 'down': bcs.append(DirichletBC(Q, 0.0, ff, self.GAMMA_S_GND)) # grounded bcs.append(DirichletBC(Q, 0.0, ff, self.GAMMA_S_FLT)) # shelves bcs.append(DirichletBC(Q, 0.0, ff, self.GAMMA_U_GND)) # grounded bcs.append(DirichletBC(Q, 0.0, ff, self.GAMMA_U_FLT)) # shelves a = -v.dx(2) * phi * dx L = u * phi * dx name = 'value integrated %s' % d v = Function(Q, name=name) solve(a == L, v, bcs, annotate=False) print_min_max(u, 'vertically integrated function', cls=self) return v
def init_r(self, r): """ """ s = "::: initializing grain-size :::" print_text(s, self.D1Model_color) self.assign_variable(self.r, r) print_min_max(self.r, 'r^2')
def init_B_bc(self, B_bc): """ Set the scalar-value for bed. """ s = "::: initializng bed boundary condition :::" print_text(s, self.D1Model_color) self.B_bc = B_bc print_min_max(self.B_bc, 'B_bc')
def init_S_bc(self, S_bc): """ Set the scalar-value for the surface. """ s = "::: initializng surface boundary condition :::" print_text(s, self.D1Model_color) self.S_bc = S_bc print_min_max(self.S_bc, 'S_bc')
def init_adot(self, adot): """ """ s = "::: initializing accumulation :::" print_text(s, self.D1Model_color) self.assign_variable(self.adot, adot) self.assign_variable(self.bdot, self.rhoi(0) * adot / self.spy(0)) print_min_max(self.adot, 'adot') print_min_max(self.bdot, 'bdot')
def calc_thickness(self): """ Calculate the continuous thickness field which increases from 0 at the surface to the actual thickness at the bed. """ s = "::: calculating z-varying thickness :::" print_text(s, cls=self) #H = project(self.S - self.x[2], self.Q, annotate=False) H = self.vert_integrate(Constant(1.0), d='down') Hv = H.vector() Hv[Hv < 0] = 0.0 print_min_max(H, 'H', cls=self) return H
def solve(self, annotate=False): """ Perform the Newton solve of the full-Stokes equations """ model = self.model params = self.solve_params # solve nonlinear system : rtol = params['solver']['newton_solver']['relative_tolerance'] maxit = params['solver']['newton_solver']['maximum_iterations'] alpha = params['solver']['newton_solver']['relaxation_parameter'] s = "::: solving Dukowicz-Brinkerhoff-full-Stokes equations" + \ " with %i max iterations and step size = %.1f :::" print_text(s % (maxit, alpha), self.color()) # zero out self.velocity for good convergence for any subsequent solves, # e.g. model.L_curve() : model.assign_variable(self.get_U(), DOLFIN_EPS, cls=self) # compute solution : solve(self.mom_F == 0, self.U, J = self.mom_Jac, bcs = self.mom_bcs, annotate = annotate, solver_parameters = params['solver']) u, v, w, p = self.U.split() self.assx.assign(model.u, u, annotate=False) self.assy.assign(model.v, v, annotate=False) self.assz.assign(model.w, w, annotate=False) self.assp.assign(model.p, p, annotate=False) U3 = model.U3.split(True) print_min_max(U3[0], 'u', cls=self) print_min_max(U3[1], 'v', cls=self) print_min_max(U3[2], 'w', cls=self) print_min_max(model.p, 'p', cls=self)
def solve_compaction_velocity(self, annotate=True): """ """ s = "::: solving firn compaction velocity :::" print_text(s, self.color()) w_delta = self.w_delta model = self.model # linear solve : solve(lhs(w_delta) == rhs(w_delta), model.w, self.wBc, annotate=annotate) print_min_max(model.w, 'w')
def solve(self): """ """ model = self.model s = "::: solving 'SSA_Balance' for flow direction :::" print_text(s, self.color()) solve(lhs(self.delta) == rhs(self.delta), self.U_s) u_s, u_t = self.U_s.split(True) model.assign_variable(model.u_s, u_s) model.assign_variable(model.u_t, u_t) print_min_max(model.u_s, 'u_s') print_min_max(model.u_t, 'u_t') # solve for the individual stresses now that the corrected velocities # are found. self.solve_component_stress()
def calc_vert_average(self, u): """ Calculates the vertical average of a given function space and function. :param u: Function representing the model's function space :rtype: Dolfin projection and Function of the vertical average """ H = self.S - self.B uhat = self.vert_integrate(u, d='up') s = "::: calculating vertical average :::" print_text(s, cls=self) ubar = project(uhat / H, self.Q, annotate=False) print_min_max(ubar, 'ubar', cls=self) name = "vertical average of %s" % u.name() ubar.rename(name, '') ubar = self.vert_extrude(ubar, d='down') return ubar
def rhs_func_explicit(self, t, S, *f_args): """ This function calculates the change in height of the surface of the ice sheet. :param t : Time :param S : Current height of the ice sheet :rtype : Array containing rate of change of the ice surface values """ model = self.model config = self.config thklim = config['free_surface']['thklim'] B = model.B.compute_vertex_values() S[(S - B) < thklim] = thklim + B[(S - B) < thklim] # the surface is never on a periodic FunctionSpace : if config['periodic_boundary_conditions']: d2v = dof_to_vertex_map(model.Q_non_periodic) else: d2v = dof_to_vertex_map(model.Q) model.assign_variable(model.S, S[d2v]) if config['velocity']['on']: model.U.vector()[:] = 0.0 self.velocity_instance.solve() if config['velocity']['log']: U = project(as_vector([model.u, model.v, model.w])) s = '::: saving velocity U.pvd file :::' print_text(s, self.color()) self.file_U << U print_min_max(U, 'U') if config['surface_climate']['on']: self.surface_climate_instance.solve() if config['free_surface']['on']: self.surface_instance.solve() if self.config['log']: s = '::: saving surface S.pvd file :::' print_text(s, self.color()) self.file_S << model.S print_min_max(model.S, 'S') return model.dSdt.compute_vertex_values()
def solve_adjoint_momentum(self, H): """ Solves for the adjoint variables self.Lam from the Hamiltonian <H>. """ U = self.get_U() Phi = self.get_Phi() Lam = self.get_Lam() # we desire the derivative of the Hamiltonian w.r.t. the model state U # in the direction of the test function Phi to vanish : dI = derivative(H, U, Phi) s = "::: solving adjoint momentum :::" print_text(s, self.color()) aw = assemble(lhs(dI)) Lw = assemble(rhs(dI)) a_solver = KrylovSolver('cg', 'hypre_amg') a_solver.solve(aw, Lam.vector(), Lw, annotate=False) #lam_nx, lam_ny = model.Lam.split(True) #lam_ix, lam_iy = model.Lam.split() #if self.config['adjoint']['surface_integral'] == 'shelves': # lam_nx.vector()[model.gnd_dofs] = 0.0 # lam_ny.vector()[model.gnd_dofs] = 0.0 #elif self.config['adjoint']['surface_integral'] == 'grounded': # lam_nx.vector()[model.shf_dofs] = 0.0 # lam_ny.vector()[model.shf_dofs] = 0.0 ## function assigner translates between mixed space and P1 space : #U_sp = model.U.function_space() #assx = FunctionAssigner(U_sp.sub(0), lam_nx.function_space()) #assy = FunctionAssigner(U_sp.sub(1), lam_ny.function_space()) #assx.assign(lam_ix, lam_nx) #assy.assign(lam_iy, lam_ny) #solve(self.aw == self.Lw, model.Lam, # solver_parameters = {"linear_solver" : "cg", # "preconditioner" : "hypre_amg"}, # annotate=False) #print_min_max(norm(model.Lam), '||Lam||') print_min_max(Lam, 'Lam')
def deriv_cb(I, dI, c): global counter, Rs, Js, J1s, J2s if method == 'ipopt': s0 = '>>> ' s1 = 'iteration %i (max %i) complete' s2 = ' <<<' text0 = get_text(s0, 'red', 1) text1 = get_text(s1 % (counter, max_iter), 'red') text2 = get_text(s2, 'red', 1) if MPI.rank(mpi_comm_world()) == 0: print text0 + text1 + text2 counter += 1 s = '::: adjoint obj. gradient post callback function :::' print_text(s, cls=self) print_min_max(dI, 'dI/dcontrol', cls=self) # update the DA current velocity to the model for evaluation # purposes only; the model.assign_variable function is # annotated for purposes of linking physics models to the adjoint # process : u_opt = DolfinAdjointVariable(model.U3).tape_value() model.init_U(u_opt, cls=self) # print functional values : control.assign(c, annotate=False) ftnls = self.calc_functionals() D = self.calc_misfit() # functional lists to be populated : Rs.append(ftnls[0]) Js.append(ftnls[1]) Ds.append(D) if self.obj_ftn_type == 'log_L2_hybrid': J1s.append(ftnls[2]) J2s.append(ftnls[3]) if self.reg_ftn_type == 'TV_Tik_hybrid': R1s.append(ftnls[4]) R2s.append(ftnls[5]) # call that callback, if you want : if adj_callback is not None: adj_callback(I, dI, c)
def solve(self): """ """ config = self.config self.assign_variable(self.Shat, self.S) self.assign_variable(self.ahat, self.adot) self.assign_variable(self.uhat, self.u) self.assign_variable(self.vhat, self.v) self.assign_variable(self.what, self.w) m = assemble(self.mass_matrix, keep_diagonal=True) r = assemble(self.stiffness_matrix, keep_diagonal=True) s = "::: solving free-surface :::" print_text(s, self.D3Model_color) if config['free_surface']['lump_mass_matrix']: m_l = assemble(self.lumped_mass) m_l = m_l.get_local() m_l[m_l == 0.0] = 1.0 m_l_inv = 1. / m_l if config['free_surface']['static_boundary_conditions']: self.static_boundary.apply(m, r) if config['free_surface']['use_shock_capturing']: k = assemble(self.diffusion_matrix) r -= k print_min_max(r, 'D') if config['free_surface']['lump_mass_matrix']: self.assign_variable(self.dSdt, m_l_inv * r.get_local()) else: m.ident_zeros() solve(m, self.dSdt.vector(), r, annotate=False) A = assemble(lhs(self.A_pro)) p = assemble(rhs(self.A_pro)) q = Vector() solve(A, q, p, annotate=False) self.assign_variable(self.dSdt, q)
def unify_eta(self): """ Unifies viscosity defined over grounded and shelves to model.eta. """ s = "::: unifying viscosity on shelf and grounded areas to model.eta :::" print_text(s, self.color()) model = self.model num_shf = MPI.sum(mpi_comm_world(), len(model.shf_dofs)) num_gnd = MPI.sum(mpi_comm_world(), len(model.gnd_dofs)) print_min_max(num_shf, 'number of floating vertices') print_min_max(num_gnd, 'number of grounded vertices') if num_gnd == 0 and num_shf == 0: s = " - floating and grounded regions have not been marked -" print_text(s, self.color()) elif num_gnd == 0: s = " - all floating ice, assigning eta_shf to eta -" print_text(s, self.color()) model.init_eta(project(self.eta_shf, model.Q)) elif num_shf == 0: s = " - all grounded ice, assigning eta_gnd to eta -" print_text(s, self.color()) model.init_eta(project(self.eta_gnd, model.Q)) else: s = " - grounded and floating ice present, unifying eta -" print_text(s, self.color()) eta_shf = project(self.eta_shf, model.Q) eta_gnd = project(self.eta_gnd, model.Q) # remove areas where viscosities overlap : eta_shf.vector()[model.gnd_dofs] = 0.0 eta_gnd.vector()[model.shf_dofs] = 0.0 # unify eta to self.eta : model.init_eta(eta_shf.vector() + eta_gnd.vector())
def solve(self, annotate=False): """ Perform the Newton solve of the first order equations """ model = self.model params = self.solve_params # solve nonlinear system : rtol = params['solver']['newton_solver']['relative_tolerance'] maxit = params['solver']['newton_solver']['maximum_iterations'] alpha = params['solver']['newton_solver']['relaxation_parameter'] s = "::: solving Dukowicz BP horizontal velocity with %i max" + \ " iterations and step size = %.1f :::" print_text(s % (maxit, alpha), self.color()) # zero out self.velocity for good convergence for any subsequent solves, # e.g. model.L_curve() : model.assign_variable(self.get_U(), DOLFIN_EPS, cls=self) # compute solution : solve(self.mom_F == 0, self.U, J=self.mom_Jac, bcs=self.mom_bcs, annotate=annotate, solver_parameters=params['solver']) u, v = self.U.split() self.assx.assign(model.u, u, annotate=annotate) self.assy.assign(model.v, v, annotate=annotate) u, v, w = model.U3.split(True) print_min_max(u, 'u', cls=self) print_min_max(v, 'v', cls=self) if params['solve_vert_velocity']: self.solve_vert_velocity(annotate) if params['solve_pressure']: self.solve_pressure(annotate=False)
def solve_vert_velocity(self, annotate=annotate): """ Solve for vertical velocity w. """ s = "::: solving Dukowicz reduced vertical velocity :::" print_text(s, self.color()) model = self.model aw = assemble(lhs(self.w_F)) Lw = assemble(rhs(self.w_F)) #if self.bc_w != None: # self.bc_w.apply(aw, Lw) w_solver = LUSolver(self.solve_params['vert_solve_method']) w_solver.solve(aw, self.w.vector(), Lw, annotate=annotate) #solve(lhs(self.R2) == rhs(self.R2), self.w, bcs = self.bc_w, # solver_parameters = {"linear_solver" : sm})#, # "symmetric" : True}, # annotate=False) self.assz.assign(model.w, self.w, annotate=annotate) #w = project(self.w, model.Q, annotate=annotate) print_min_max(self.w, 'w', cls=self)
def vert_extrude(self, u, d='up', Q='self'): r""" This extrudes a function *u* vertically in the direction *d* = 'up' or 'down'. It does this by solving a variational problem: .. math:: \frac{\partial v}{\partial z} = 0 \hspace{10mm} v|_b = u """ s = "::: extruding function %swards :::" % d print_text(s, cls=self) if type(Q) != FunctionSpace: Q = self.Q ff = self.ff phi = TestFunction(Q) v = TrialFunction(Q) a = v.dx(2) * phi * dx L = DOLFIN_EPS * phi * dx bcs = [] # extrude bed (ff = 3,5) if d == 'up': bcs.append(DirichletBC(Q, u, ff, self.GAMMA_B_GND)) # grounded bcs.append(DirichletBC(Q, u, ff, self.GAMMA_B_FLT)) # shelves # extrude surface (ff = 2,6) elif d == 'down': bcs.append(DirichletBC(Q, u, ff, self.GAMMA_S_GND)) # grounded bcs.append(DirichletBC(Q, u, ff, self.GAMMA_S_FLT)) # shelves bcs.append(DirichletBC(Q, u, ff, self.GAMMA_U_GND)) # grounded bcs.append(DirichletBC(Q, u, ff, self.GAMMA_U_FLT)) # shelves try: name = '%s extruded %s' % (u.name(), d) except AttributeError: name = 'extruded' v = Function(Q, name=name) solve(a == L, v, bcs, annotate=False) print_min_max(v, 'extruded function', cls=self) return v
def solve_vert_velocity(self, annotate=False): """ Perform the Newton solve of the first order equations """ model = self.model # solve for vertical velocity : s = "::: solving BP vertical velocity :::" print_text(s, self.color()) aw = assemble(lhs(self.w_F)) Lw = assemble(rhs(self.w_F)) if self.bc_w != None: self.bc_w.apply(aw, Lw) w_solver = LUSolver(self.solve_params['vert_solve_method']) w_solver.solve(aw, self.wf.vector(), Lw, annotate=annotate) #solve(lhs(self.R2) == rhs(self.R2), self.w, bcs = self.bc_w, # solver_parameters = {"linear_solver" : sm})#, # "symmetric" : True}, # annotate=False) self.assz.assign(model.w, self.wf, annotate=annotate) print_min_max(self.wf, 'w', cls=self)
def solve(self, annotate=True): """ """ s = "::: solving firn density, overburden stress, and grain radius :::" print_text(s, self.color()) model = self.model # newton's iterative method : solve(self.delta == 0, self.U, bcs=self.bcs, J=self.J, solver_parameters=self.solve_params['solver'], annotate=annotate) rho, sigma, r = self.U.split() self.assrho.assign(model.rho, rho) self.asssig.assign(model.sigma, sigma) self.assrss.assign(model.r, r) rhop = model.rho.vector().array() # update kc term in drhodt : # if rho > 550, kc = kcHigh # if rho <= 550, kc = kcLow # with parameterizations given by ligtenberg et all 2011 A = model.rhoi(0) / model.rhow(0) * 1e3 * model.adot(0) rhoCoefNew = np.ones(model.dof) rhoHigh = np.where(rhop > 550)[0] rhoLow = np.where(rhop <= 550)[0] rhoCoefNew[rhoHigh] = model.kcHh(0) * (2.366 - 0.293 * ln(A)) rhoCoefNew[rhoLow] = model.kcLw(0) * (1.435 - 0.151 * ln(A)) model.assign_variable(model.rhoCoef, rhoCoefNew) print_min_max(model.rho, 'rho') print_min_max(model.sigma, 'sigma') print_min_max(model.r, 'r') s = "::: solving firn densification rate :::" print_text(s, self.color()) model.assign_variable(model.drhodt, project(self.drhodt)) print_min_max(model.drhodt, 'drho/dt') self.solve_compaction_velocity(annotate=annotate)
def solve(self, annotate=True): """ Solves for hybrid conservation of mass. """ model = self.model params = self.solve_params # find corrective velocities : s = "::: solving for corrective velocities :::" print_text(s, self.color()) solve(self.M == self.ubar_proj, model.ubar_c, solver_parameters={'linear_solver': 'mumps'}, form_compiler_parameters=params['ffc_params'], annotate=annotate) solve(self.M == self.vbar_proj, model.vbar_c, solver_parameters={'linear_solver': 'mumps'}, form_compiler_parameters=params['ffc_params'], annotate=annotate) print_min_max(model.ubar_c, 'ubar_c', cls=self) print_min_max(model.vbar_c, 'vbar_c', cls=self) # SOLVE MASS CONSERVATION bounded by (H_max, H_min) : meth = params['solver']['snes_solver']['method'] maxit = params['solver']['snes_solver']['maximum_iterations'] s = "::: solving 'MassTransportHybrid' using method '%s' with %i " + \ "max iterations :::" print_text(s % (meth, maxit), self.color()) # define variational solver for the mass problem : #p = NonlinearVariationalProblem(self.R_thick, model.H, J=self.J_thick, # bcs=self.bc, form_compiler_parameters=params['ffc_params']) #p.set_bounds(model.H_min, model.H_max) #s = NonlinearVariationalSolver(p) #s.parameters.update(params['solver']) out = self.solver.solve(annotate=annotate) print_min_max(model.H, 'H', cls=self) # update previous time step's H : model.assign_variable(model.H0, model.H, cls=self) # update the surface : s = "::: updating surface :::" print_text(s, self.color()) B_v = model.B.vector().array() H_v = model.H.vector().array() S_v = B_v + H_v model.assign_variable(model.S, S_v, cls=self) return out
def solve(self, annotate=False): """ Perform the Newton solve of the reduced full-Stokes equations """ model = self.model params = self.solve_params # solve nonlinear system : rtol = params['solver']['newton_solver']['relative_tolerance'] maxit = params['solver']['newton_solver']['maximum_iterations'] alpha = params['solver']['newton_solver']['relaxation_parameter'] lin_slv = params['solver']['newton_solver']['linear_solver'] precon = params['solver']['newton_solver']['preconditioner'] err_conv = params['solver']['newton_solver']['error_on_nonconvergence'] s = "::: solving Dukowicz full-Stokes reduced equations with %i max" + \ " iterations and step size = %.1f :::" print_text(s % (maxit, alpha), self.color()) # zero out self.velocity for good convergence for any subsequent solves, # e.g. model.L_curve() : model.assign_variable(self.get_U(), DOLFIN_EPS, cls=self) def cb_ftn(): self.solve_vert_velocity(annotate) # compute solution : #solve(self.mom_F == 0, self.U, J = self.mom_Jac, bcs = self.mom_bcs, # annotate = annotate, solver_parameters = params['solver']) model.home_rolled_newton_method(self.mom_F, self.U, self.mom_Jac, self.mom_bcs, atol=1e-6, rtol=rtol, relaxation_param=alpha, max_iter=maxit, method=lin_slv, preconditioner=precon, cb_ftn=cb_ftn) u, v = self.U.split() self.assx.assign(model.u, u, annotate=False) self.assy.assign(model.v, v, annotate=False) # solve for the vertical velocity : if params['solve_vert_velocity']: self.solve_vert_velocity(annotate) if params['solve_pressure']: self.solve_pressure(annotate) U3 = model.U3.split(True) print_min_max(U3[0], 'u', cls=self) print_min_max(U3[1], 'v', cls=self) print_min_max(U3[2], 'w', cls=self)
def solve(self, annotate=False): """ Solve the energy equations, saving enthalpy to model.theta, temperature to model.T, and water content to model.W. """ model = self.model mesh = model.mesh Q = model.Q T_melt = model.T_melt T = model.T T_w = model.T_w W = model.W W0 = model.W0 L = model.L c = self.c params = self.solve_params # solve nonlinear system : rtol = params['solver']['newton_solver']['relative_tolerance'] maxit = params['solver']['newton_solver']['maximum_iterations'] alpha = params['solver']['newton_solver']['relaxation_parameter'] s = "::: solving monolithic with %i max iterations" + \ " and step size = %.1f :::" print_text(s % (maxit, alpha), self.color()) # compute solution : solve(self.F == 0, self.G, J = self.Jac, bcs = self.bcs, annotate = annotate, solver_parameters = params['solver']) U, theta = self.G.split() u, v = split(U) self.assx.assign(model.u, u, annotate=False) self.assy.assign(model.v, v, annotate=False) self.asst.assign(model.theta, theta, annotate=False) # solve for the vertical velocity : if params['solve_vert_velocity']: self.solve_vert_velocity(annotate) U3 = model.U3.split(True) print_min_max(U3[0], 'u', cls=self) print_min_max(U3[1], 'v', cls=self) print_min_max(U3[2], 'w', cls=self) # temperature solved with quadradic formula, using expression for c : s = "::: calculating temperature :::" print_text(s, cls=self) theta_v = theta.vector().array() T_n_v = (-146.3 + np.sqrt(146.3**2 + 2*7.253*theta_v)) / 7.253 T_v = T_n_v.copy() Tp_v = T_n_v.copy() # create pressure-adjusted temperature for rate-factor : Tp_v[Tp_v > T_w(0)] = T_w(0) model.init_Tp(Tp_v, cls=self) # update temperature for wet/dry areas : T_melt_v = T_melt.vector().array() theta_melt_v = model.theta_melt.vector().array() warm = theta_v >= theta_melt_v cold = theta_v < theta_melt_v T_v[warm] = T_melt_v[warm] model.assign_variable(T, T_v, cls=self) # water content solved diagnostically : s = "::: calculating water content :::" print_text(s, cls=self) W_v = (theta_v - theta_melt_v) / L(0) # update water content : #W_v[cold] = 0.0 # no water where frozen W_v[W_v < 0.0] = 0.0 # no water where frozen, please. #W_v[W_v > 1.0] = 1.0 # capped at 100% water, i.e., no hot water. model.assign_variable(W0, W, cls=self) model.assign_variable(W, W_v, cls=self)
def solve_component_stress(self): """ """ model = self.model s = "::: solving 'SSA_Balance' for stresses :::" print_text(s, self.color()) Q = model.Q beta = model.beta S = model.S B = model.B H = S - B rhoi = model.rhoi g = model.g etabar = model.etabar Q = model.Q U_s = self.U_s U_n = self.U_n U_t = self.U_t phi = TestFunction(Q) dtau = TrialFunction(Q) s = dot(U_s, U_n) t = dot(U_s, U_t) grads = as_vector([s.dx(0), s.dx(1)]) gradt = as_vector([t.dx(0), t.dx(1)]) dsdi = dot(grads, U_n) dsdj = dot(grads, U_t) dtdi = dot(gradt, U_n) dtdj = dot(gradt, U_t) gradphi = as_vector([phi.dx(0), phi.dx(1)]) gradS = as_vector([S.dx(0), S.dx(1)]) dphidi = dot(gradphi, U_n) dphidj = dot(gradphi, U_t) dSdi = dot(gradS, U_n) dSdj = dot(gradS, U_t) gradphi = as_vector([dphidi, dphidj]) gradS = as_vector([dSdi, dSdj]) epi_1 = as_vector([2 * dsdi + dtdj, 0.5 * (dsdj + dtdi)]) epi_2 = as_vector([0.5 * (dsdj + dtdi), 2 * dtdj + dsdi]) tau_id_s = phi * rhoi * g * H * gradS[0] * dx tau_jd_s = phi * rhoi * g * H * gradS[1] * dx tau_ib_s = -beta * s * phi * dx tau_jb_s = -beta * t * phi * dx tau_ii_s = -2 * etabar * H * epi_1[0] * gradphi[0] * dx tau_ij_s = -2 * etabar * H * epi_1[1] * gradphi[1] * dx tau_ji_s = -2 * etabar * H * epi_2[0] * gradphi[0] * dx tau_jj_s = -2 * etabar * H * epi_2[1] * gradphi[1] * dx # mass matrix : M = assemble(phi * dtau * dx) # solve the linear system : solve(M, model.tau_id.vector(), assemble(tau_id_s)) print_min_max(model.tau_id, 'tau_id') solve(M, model.tau_jd.vector(), assemble(tau_jd_s)) print_min_max(model.tau_jd, 'tau_jd') solve(M, model.tau_ib.vector(), assemble(tau_ib_s)) print_min_max(model.tau_ib, 'tau_ib') solve(M, model.tau_jb.vector(), assemble(tau_jb_s)) print_min_max(model.tau_jb, 'tau_jb') solve(M, model.tau_ii.vector(), assemble(tau_ii_s)) print_min_max(model.tau_ii, 'tau_ii') solve(M, model.tau_ij.vector(), assemble(tau_ij_s)) print_min_max(model.tau_ij, 'tau_ij') solve(M, model.tau_ji.vector(), assemble(tau_ji_s)) print_min_max(model.tau_ji, 'tau_ji') solve(M, model.tau_jj.vector(), assemble(tau_jj_s)) print_min_max(model.tau_jj, 'tau_jj')
def solve(self): """ """ s = "::: solving 'FS_Balance' :::" print_text(s, self.color()) model = self.model # solve the linear system : solve(self.M, model.tau_ii.vector(), assemble(self.tau_ii)) print_min_max(model.tau_ii, 'tau_ii') solve(self.M, model.tau_ij.vector(), assemble(self.tau_ij)) print_min_max(model.tau_ij, 'tau_ij') solve(self.M, model.tau_ik.vector(), assemble(self.tau_ik)) print_min_max(model.tau_ik, 'tau_ik') solve(self.M, model.tau_ji.vector(), assemble(self.tau_ji)) print_min_max(model.tau_ji, 'tau_ji') solve(self.M, model.tau_jj.vector(), assemble(self.tau_jj)) print_min_max(model.tau_jj, 'tau_jj') solve(self.M, model.tau_jk.vector(), assemble(self.tau_jk)) print_min_max(model.tau_jk, 'tau_jk') solve(self.M, model.tau_ki.vector(), assemble(self.tau_ki)) print_min_max(model.tau_ki, 'tau_ki') solve(self.M, model.tau_kj.vector(), assemble(self.tau_kj)) print_min_max(model.tau_kj, 'tau_kj') solve(self.M, model.tau_kk.vector(), assemble(self.tau_kk)) print_min_max(model.tau_kk, 'tau_kk')
def solve(self, annotate=True): """ Solve the balance velocity magnitude :math:`\Vert \\bar{\mathbf{u}} \Vert`. This will be completed in four steps, 1. Calculate the surface gradient :math:`\\frac{\partial S}{\partial x}` and :math:`\\frac{\partial S}{\partial y}` saved to ``model.dSdx`` and ``model.dSdy``. 2. Solve for the smoothed component of driving stress .. math:: \\tau_x = \\rho g H \\frac{\partial S}{\partial x}, \hspace{10mm} \\tau_y = \\rho g H \\frac{\partial S}{\partial y} saved respectively to ``model.Nx`` and ``model.Ny``. 3. Calculate the normalized flux directions .. math:: d_x = -\\frac{\\tau_x}{\Vert \\tau_x \Vert}, \hspace{10mm} d_y = -\\frac{\\tau_y}{\Vert \\tau_y \Vert}, saved respectively to ``model.d_x`` and ``model.d_y``. 4. Calculate the balance velocity magnitude :math:`\Vert \\bar{\mathbf{u}} \Vert` from .. math:: \\nabla \cdot \\left( \\bar{\mathbf{u}} H \\right) = \dot{a} - F_b saved to ``model.Ubar``. """ model = self.model s = "::: solving BalanceVelocity :::" print_text(s, cls=self) s = "::: calculating surface gradient :::" print_text(s, cls=self) dSdx = project(model.S.dx(0), model.Q, annotate=annotate) dSdy = project(model.S.dx(1), model.Q, annotate=annotate) model.assign_variable(model.dSdx, dSdx, cls=self) model.assign_variable(model.dSdy, dSdy, cls=self) # update velocity direction from driving stress : s = "::: solving for smoothed x-component of driving stress " + \ "with kappa = %g :::" % self.kappa print_text(s, cls=self) solve(self.a_dSdx == self.L_dSdx, model.Nx, annotate=annotate) print_min_max(model.Nx, 'Nx', cls=self) s = "::: solving for smoothed y-component of driving stress :::" print_text(s, cls=self) solve(self.a_dSdy == self.L_dSdy, model.Ny, annotate=annotate) print_min_max(model.Ny, 'Ny', cls=self) # normalize the direction vector : s = "::: calculating normalized flux direction" \ + " from driving stress :::" print_text(s, cls=self) d_x_v = model.Nx.vector().array() d_y_v = model.Ny.vector().array() d_n_v = np.sqrt(d_x_v**2 + d_y_v**2 + 1e-16) model.assign_variable(model.d_x, -d_x_v / d_n_v, cls=self) model.assign_variable(model.d_y, -d_y_v / d_n_v, cls=self) # calculate balance-velocity : s = "::: solving velocity balance magnitude :::" print_text(s, cls=self) solve(self.B == self.a, model.Ubar, annotate=annotate) print_min_max(model.Ubar, 'Ubar', cls=self) # enforce positivity of balance-velocity : s = "::: removing negative values of balance velocity :::" print_text(s, cls=self) Ubar_v = model.Ubar.vector().array() Ubar_v[Ubar_v < 0] = 0 model.assign_variable(model.Ubar, Ubar_v, cls=self)
def solve_component_stress(self): """ """ model = self.model s = "solving 'BP_Balance' for internal forces :::" print_text(s, self.color()) Q = model.Q N = model.N beta = model.beta S = model.S B = model.B H = S - B rhoi = model.rhoi g = model.g eta = self.eta f_w = self.f_w dx = model.dx dx_f = model.dx_f dx_g = model.dx_g ds = model.ds dBed_g = model.dBed_g dBed_f = model.dBed_f dLat_t = model.dLat_t dBed = model.dBed # solve with corrected velociites : U_s = self.U_s U_n = self.U_n U_t = self.U_t ## or not : #u,v,w = model.U3.split(True) #U = as_vector([u, v]) #U_mag = sqrt(dot(U,U) + DOLFIN_EPS) #U_n = U / U_mag #U_t = as_vector([v, -u]) / U_mag #s = dot(U, U_n) #t = dot(U, U_t) #U_s = as_vector([s, t]) # functionspaces : phi = TestFunction(Q) dtau = TrialFunction(Q) s = dot(U_s, U_n) t = dot(U_s, U_t) U_s = as_vector([s, t]) grads = as_vector([s.dx(0), s.dx(1)]) gradt = as_vector([t.dx(0), t.dx(1)]) dsdi = dot(grads, U_n) dsdj = dot(grads, U_t) dsdz = s.dx(2) dtdi = dot(gradt, U_n) dtdj = dot(gradt, U_t) dtdz = t.dx(2) dwdz = -(dsdi + dtdj) gradphi = as_vector([phi.dx(0), phi.dx(1)]) gradS = as_vector([S.dx(0), S.dx(1)]) dphidi = dot(gradphi, U_n) dphidj = dot(gradphi, U_t) dSdi = dot(gradS, U_n) dSdj = dot(gradS, U_t) gradphi = as_vector([dphidi, dphidj, phi.dx(2)]) gradS = as_vector([dSdi, dSdj, S.dx(2)]) epi_1 = as_vector([dsdi + dwdz, 0.5 * (dsdj + dtdi), 0.5 * dsdz]) epi_2 = as_vector([0.5 * (dtdi + dsdj), dtdj + dwdz, 0.5 * dtdz]) F_id_s = +phi * rhoi * g * gradS[0] * dx #\ # - 2 * eta * dwdz * dphidi * dx #\ # + 2 * eta * dwdz * phi * N[0] * U_n[0] * ds F_jd_s = +phi * rhoi * g * gradS[1] * dx #\ # - 2 * eta * dwdz * dphidj * dx #\ # + 2 * eta * dwdz * phi * N[1] * U_n[1] * ds F_ib_s = -beta * s * phi * dBed F_jb_s = -beta * t * phi * dBed F_ip_s = f_w * N[0] * phi * dLat_t F_jp_s = f_w * N[1] * phi * dLat_t F_pn_s = f_w * N[0] * phi * dLat_t F_pt_s = f_w * N[1] * phi * dLat_t F_ii_s = - 2 * eta * epi_1[0] * gradphi[0] * dx \ # + 2 * eta * epi_1[0] * phi * N[0] * U_n[0] * ds # + f_w * N[0] * phi * U_n[0] * dLat_t F_ij_s = -2 * eta * epi_1[1] * gradphi[1] * dx # \ # + 2 * eta * epi_1[1] * phi * N[1] * U_n[1] * ds # + f_w * N[1] * phi * U_n[1] * dLat_t F_iz_s = -2 * eta * epi_1[2] * gradphi[2] * dx + F_ib_s #\ # + 2 * eta * epi_1[2] * phi * N[2] * ds F_ji_s = -2 * eta * epi_2[0] * gradphi[0] * dx # \ # + 2 * eta * epi_2[0] * phi * N[0] * U_t[0] * ds # + f_w * N[0] * phi * U_t[0] * dLat_t F_jj_s = -2 * eta * epi_2[1] * gradphi[1] * dx # \ # + 2 * eta * epi_2[0] * phi * N[1] * U_t[1] * ds # + f_w * N[1] * phi * U_t[1] * dLat_t F_jz_s = -2 * eta * epi_2[2] * gradphi[2] * dx + F_jb_s #\ # + 2 * eta * epi_2[2] * phi * N[2] * ds # mass matrix : M = assemble(phi * dtau * dx) # solve the linear system : solve(M, model.F_id.vector(), assemble(F_id_s)) print_min_max(model.F_id, 'F_id') solve(M, model.F_jd.vector(), assemble(F_jd_s)) print_min_max(model.F_jd, 'F_jd') solve(M, model.F_ib.vector(), assemble(F_ib_s)) print_min_max(model.F_ib, 'F_ib') solve(M, model.F_jb.vector(), assemble(F_jb_s)) print_min_max(model.F_jb, 'F_jb') solve(M, model.F_ip.vector(), assemble(F_ip_s)) print_min_max(model.F_ip, 'F_ip') solve(M, model.F_jp.vector(), assemble(F_jp_s)) print_min_max(model.F_jp, 'F_jp') solve(M, model.F_ii.vector(), assemble(F_ii_s)) print_min_max(model.F_ii, 'F_ii') solve(M, model.F_ij.vector(), assemble(F_ij_s)) print_min_max(model.F_ij, 'F_ij') solve(M, model.F_iz.vector(), assemble(F_iz_s)) print_min_max(model.F_iz, 'F_iz') solve(M, model.F_ji.vector(), assemble(F_ji_s)) print_min_max(model.F_ji, 'F_ji') solve(M, model.F_jj.vector(), assemble(F_jj_s)) print_min_max(model.F_jj, 'F_jj') solve(M, model.F_jz.vector(), assemble(F_jz_s)) print_min_max(model.F_jz, 'F_jz') if self.vert_integrate: s = "::: vertically integrating 'BP_Balance' internal forces :::" print_text(s, self.color()) tau_ii = model.vert_integrate(model.F_ii, d='down') tau_ij = model.vert_integrate(model.F_ij, d='down') tau_iz = model.vert_integrate(model.F_iz, d='down') tau_ji = model.vert_integrate(model.F_ji, d='down') tau_jj = model.vert_integrate(model.F_jj, d='down') tau_jz = model.vert_integrate(model.F_jz, d='down') tau_id = model.vert_integrate(model.F_id, d='down') tau_jd = model.vert_integrate(model.F_jd, d='down') tau_ip = model.vert_integrate(model.F_ip, d='down') tau_jp = model.vert_integrate(model.F_jp, d='down') tau_ib = model.vert_extrude(model.F_ib, d='up') tau_jb = model.vert_extrude(model.F_jb, d='up') model.assign_variable(model.tau_id, tau_id, cls=self) model.assign_variable(model.tau_jd, tau_jd, cls=self) model.assign_variable(model.tau_ib, tau_ib, cls=self) model.assign_variable(model.tau_jb, tau_jb, cls=self) model.assign_variable(model.tau_ip, tau_ip, cls=self) model.assign_variable(model.tau_jp, tau_jp, cls=self) model.assign_variable(model.tau_ii, tau_ii, cls=self) model.assign_variable(model.tau_ij, tau_ij, cls=self) model.assign_variable(model.tau_iz, tau_iz, cls=self) model.assign_variable(model.tau_ji, tau_ji, cls=self) model.assign_variable(model.tau_jj, tau_jj, cls=self) model.assign_variable(model.tau_jz, tau_jz, cls=self)