def value_form(self): # volume integral self.detDT.interpolate(fd.det(fd.grad(self.Q.T))) if min(self.detDT.vector()) > 0.05: integrand = (self.sigma - self.f)**2 else: integrand = np.nan * (self.sigma - self.f)**2 return integrand * fd.dx(metadata={"quadrature_degree": 1})
def eigenvalues(a): r"""Return a pair of symbolic expressions for the largest and smallest eigenvalues of a 2D rank-2 tensor""" tr_a = tr(a) det_a = det(a) # TODO: Fret about numerical stability Δ = sqrt(tr_a**2 - 4 * det_a) return ((tr_a + Δ) / 2, (tr_a - Δ) / 2)
def sources(self, **kwargs): keys = ("damage", "velocity", "strain_rate", "membrane_stress") D, u, ε, M = itemgetter(*keys)(kwargs) # Increase/decrease damage depending on stress and strain rates ε_1 = eigenvalues(ε)[0] σ_e = sqrt(inner(M, M) - det(M)) ε_h = firedrake.Constant(self.healing_strain_rate) σ_d = firedrake.Constant(self.damage_stress) γ_h = firedrake.Constant(self.healing_rate) γ_d = firedrake.Constant(self.damage_rate) healing = γ_h * min_value(ε_1 - ε_h, 0) fracture = γ_d * conditional(σ_e - σ_d > 0, ε_1, 0.0) * (1 - D) return healing + fracture
def sources(self, **kwargs): keys = ('damage', 'velocity', 'strain_rate', 'membrane_stress') keys_alt = ('D', 'u', 'ε', 'M') D, u, ε, M = get_kwargs_alt(kwargs, keys, keys_alt) # Increase/decrease damage depending on stress and strain rates ε_1 = eigenvalues(ε)[0] σ_e = sqrt(inner(M, M) - det(M)) ε_h = firedrake.Constant(self.healing_strain_rate) σ_d = firedrake.Constant(self.damage_stress) γ_h = firedrake.Constant(self.healing_rate) γ_d = firedrake.Constant(self.damage_rate) healing = γ_h * min_value(ε_1 - ε_h, 0) fracture = γ_d * conditional(σ_e - σ_d > 0, ε_1, 0.) * (1 - D) return healing + fracture
def sources(self, **kwargs): keys = ('damage', 'velocity', 'fluidity') keys_alt = ('D', 'u', 'A') D, u, A = get_kwargs_alt(kwargs, keys, keys_alt) # Increase/decrease damage depending on stress and strain rates ε = sym(grad(u)) ε_1 = eigenvalues(ε)[0] σ = M(ε, A) σ_e = sqrt(inner(σ, σ) - det(σ)) ε_h = firedrake.Constant(self.healing_strain_rate) σ_d = firedrake.Constant(self.damage_stress) γ_h = firedrake.Constant(self.healing_rate) γ_d = firedrake.Constant(self.damage_rate) healing = γ_h * min_value(ε_1 - ε_h, 0) fracture = γ_d * conditional(σ_e - σ_d > 0, ε_1, 0.) * (1 - D) return healing + fracture
cfl_conditional = fd.conditional(fd.lt(np.abs(vnorm), tol), 1 / tol, h / vnorm) outfile = fd.File("plots/sb_t_supg.pvd") sol = fd.Function(W) c0.assign(0.) # initialize timestep while t < sim_time: # move next time step print("* iteration= {:4d}, dtime= {:8.6f}, time={:8.6f}".format(it, dt, t)) # SB idt.assign(1 / dt) fd.solve(a == L, sol, bcs=bcs) vel.assign(sol.sub(0)) Pe = vnorm * h / (2.0 * fd.det(Diff)) numCFL = dt / fd.interpolate(cfl_conditional, DG0).dat.data.min() print('Peclet = {}; CFL = {}; vel. = {}'.format( fd.interpolate(Pe, DG0).dat.data.mean(), numCFL, np.sqrt(np.sum(vel.dat.data * vel.dat.data, axis=1)).max())) # tracer transport.solve() # update sol. res = fd.norm(fd.interpolate(R, DG0)) print('Residual = {}'.format(res)) dt = CFL * fd.interpolate(cfl_conditional, DG0).dat.data.min() dt = np.min([sim_time - t, dt]) if (sim_time - t) > dt else dt0 Dt.assign(dt)
def solve(self, dt, D0, u, A, D_inflow=None, **kwargs): r"""Propogate the damage forward by one timestep This function uses a Runge-Kutta scheme to upwind damage (limiting damage diffusion) while sourcing and sinking damage assocaited with crevasse opening/crevasse healing Parameters ---------- dt : float Timestep D0 : firedrake.Function initial damage feild should be discontinuous u : firedrake.Function Ice velocity A : firedrake.Function fluidity parameter D_inflow : firedrake.Function Damage of the upstream ice that advects into the domain Returns ------- D : firedrake.Function Ice damage at `t + dt` """ D_inflow = D_inflow if D_inflow is not None else D0 Q = D0.function_space() dD, φ = firedrake.TrialFunction(Q), firedrake.TestFunction(Q) d = φ * dD * dx D = D0.copy(deepcopy=True) n = firedrake.FacetNormal(Q.mesh()) un = 0.5 * (inner(u, n) + abs(inner(u, n))) L1 = dt * (D * div(φ * u) * dx - φ * max_value(inner(u, n), 0) * D * ds - φ * min_value(inner(u, n), 0) * D_inflow * ds - (φ('+') - φ('-')) * (un('+') * D('+') - un('-') * D('-')) * dS) D1 = firedrake.Function(Q) D2 = firedrake.Function(Q) L2 = firedrake.replace(L1, {D: D1}) L3 = firedrake.replace(L1, {D: D2}) dq = firedrake.Function(Q) # Three-stage strong structure-preserving Runge Kutta (SSPRK3) method params = { 'ksp_type': 'preonly', 'pc_type': 'bjacobi', 'sub_pc_type': 'ilu' } prob1 = firedrake.LinearVariationalProblem(d, L1, dq) solv1 = firedrake.LinearVariationalSolver(prob1, solver_parameters=params) prob2 = firedrake.LinearVariationalProblem(d, L2, dq) solv2 = firedrake.LinearVariationalSolver(prob2, solver_parameters=params) prob3 = firedrake.LinearVariationalProblem(d, L3, dq) solv3 = firedrake.LinearVariationalSolver(prob3, solver_parameters=params) solv1.solve() D1.assign(D + dq) solv2.solve() D2.assign(0.75 * D + 0.25 * (D1 + dq)) solv3.solve() D.assign((1.0 / 3.0) * D + (2.0 / 3.0) * (D2 + dq)) # Increase/decrease damage depending on stress and strain rates ε = sym(grad(u)) ε_1 = eigenvalues(ε)[0] σ = M(ε, A) σ_e = sqrt(inner(σ, σ) - det(σ)) ε_h = firedrake.Constant(self.healing_strain_rate) σ_d = firedrake.Constant(self.damage_stress) γ_h = firedrake.Constant(self.healing_rate) γ_d = firedrake.Constant(self.damage_rate) healing = γ_h * min_value(ε_1 - ε_h, 0) fracture = γ_d * conditional(σ_e - σ_d > 0, ε_1, 0.) * (1 - D) # Clamp damage field to [0, 1] D.project(min_value(max_value(D + dt * (healing + fracture), 0), 1)) return D