def updateCoefficients(self): # Init coefficient matrix P, Inv = SpatialCoordinate(self.mesh) self.a = as_matrix([[+.5 * (P * self.sigma)**2, 0], [0, 0]]) # def K(t): return self.K0 + beta_SA * sin(4*pi*(t - t_SA)) def K(t): return self.K0 self.b = as_vector([ +self.alpha * (K(self.t) - P), -(self.gamma[0] + self.cost(self.gamma[0])) ]) self.c = Constant(-self.r) # Init right-hand side self.f = -(self.gamma[0] - self.cost(self.gamma[0])) * P self.u_T = -2 * P * ufl.Max(1000 - Inv, 0) # self.u_T = Constant(0.0) # Set boundary conditions # self.g_t = lambda t : [(Constant(0.0), "near(x[0],0)")] self.g = self.u_T
def bdrag_to_alpha(self, B2): """Convert basal drag to alpha""" sl = self.params.ice_dynamics.sliding_law if sl == 'linear': alpha = sqrt(B2) elif sl == 'budd': bed = self.bed H = self.H g = self.params.constants.g rhoi = self.params.constants.rhoi rhow = self.params.constants.rhow u_obs = self.u_obs_M v_obs = self.v_obs_M vel_rp = self.params.constants.vel_rp # Flotation Criterion H_flt = -rhow / rhoi * bed fl_ex = conditional(H <= H_flt, 1.0, 0.0) N = (1 - fl_ex) * (H * rhoi * g + ufl.Min(bed, 0.0) * rhow * g) U_mag = sqrt(u_obs**2 + v_obs**2 + vel_rp**2) alpha = (1 - fl_ex) * sqrt( B2 * ufl.Max(N, 0.01)**(-1.0 / 3.0) * U_mag**(2.0 / 3.0)) return alpha
def gen_alpha(self, a_bgd=500.0, a_lb=1e2, a_ub=1e4): """Generate initial guess for alpha (slip coeff)""" bed = self.bed H = self.H g = self.params.constants.g rhoi = self.params.constants.rhoi rhow = self.params.constants.rhow u_obs = self.u_obs_M v_obs = self.v_obs_M vel_rp = self.params.constants.vel_rp U = ufl.Max((u_obs**2 + v_obs**2)**(1 / 2.0), 50.0) # Flotation Criterion H_s = -rhow / rhoi * bed fl_ex = conditional(H <= H_s, 1.0, 0.0) # Thickness Criterion m_d = conditional(H > 0, 1.0, 0.0) # Calculate surface gradient R_f = ((1.0 - fl_ex) * bed + (fl_ex) * (-rhoi / rhow) * H) s_ = ufl.Max(H + R_f, 0) s = project(s_, self.Q) grads = (s.dx(0)**2.0 + s.dx(1)**2.0)**(1.0 / 2.0) # Calculate alpha, apply background, apply bound B2_ = ((1.0 - fl_ex) * rhoi * g * H * grads / U + (fl_ex) * a_bgd) * m_d + (1.0 - m_d) * a_bgd B2_tmp1 = ufl.Max(B2_, a_lb) B2_tmp2 = ufl.Min(B2_tmp1, a_ub) sl = self.params.ice_dynamics.sliding_law if sl == 'linear': alpha = sqrt(B2_tmp2) elif sl == 'weertman': N = (1 - fl_ex) * (H * rhoi * g + ufl.Min(bed, 0.0) * rhow * g) U_mag = sqrt(u_obs**2 + v_obs**2 + vel_rp**2) alpha = (1 - fl_ex) * sqrt( B2_tmp2 * ufl.Max(N, 0.01)**(-1.0 / 3.0) * U_mag**(2.0 / 3.0)) self.alpha = project(alpha, self.Qp) self.alpha.rename('alpha', 'a Function')
def f1(phi): """Factor representing humidity effects, i.e. carbonation reaction stops for very low humidities. Note ---- Saetta 1993, page 764, formula (5) """ mid = 2.5 * (phi - 0.5) return ufl.Max(ufl.Min(mid, 1.0), 0.0)
def initControl(self): # Initialize control spaces self.controlSpace = [] self.controlSpace.append(FunctionSpace(self.mesh, "DG", 0)) self.controlSpace.append(FunctionSpace(self.mesh, "DG", 0)) # self.controlSpace.append(FunctionSpace(self.mesh, "CG", 1)) # self.controlSpace.append(FunctionSpace(self.mesh, "CG", 1)) self.gamma = [] # Initialize controls Dxu = Dx(self.u, 0) spx = Dxu + self.beta smx = Dxu - self.beta Dyu = Dx(self.u, 1) spy = Dyu + self.beta smy = Dyu - self.beta if self.alpha < 1e-15: self.gamma.append( conditional(spx < 0, self.cmax, conditional(smx > 0, self.cmin, 0))) self.gamma.append( conditional(spy < 0, self.cmax, conditional(smy > 0, self.cmin, 0))) else: self.gamma.append( conditional( spx < 0, ufl.Min(-1.0 * spx / self.alpha, self.cmax), conditional(smx > 0, ufl.Max(-1.0 * smx / self.alpha, self.cmin), 0))) self.gamma.append( conditional( spy < 0, ufl.Min(-1.0 * spy / self.alpha, self.cmax), conditional(smy > 0, ufl.Max(-1.0 * smy / self.alpha, self.cmin), 0)))
def increase_conductivity(self, cond, e): # Set up the three way choice function intermediate = e * self.k + self.h not_less_than = ufl.conditional(ufl.gt(e, self.threshold_irreversible), self.sigma_end, intermediate) cond_expression = ufl.conditional(ufl.lt(e, self.threshold_reversible), self.sigma_start, not_less_than) # Project this onto the function space cond_function = d.project(ufl.Max(cond_expression, cond), cond.function_space()) cond.assign(cond_function)
def initControl(self): self.controlSpace = [ FunctionSpace(self.mesh, "DG", 1), FunctionSpace(self.mesh, "DG", 1) ] self.gamma = [] # Dxu = project(Dx(self.u,0),FunctionSpace(self.mesh, "DG", 0)) Dxu = Dx(self.u, 0) spx = Dxu + self.beta smx = Dxu - self.beta # Dyu = project(Dx(self.u,1),FunctionSpace(self.mesh, "DG", 0)) Dyu = Dx(self.u, 1) spy = Dyu + self.beta smy = Dyu - self.beta if self.alpha < 1e-15: self.gamma.append( conditional(spx < 0, self.cmax, conditional(smx > 0, self.cmin, 0))) self.gamma.append( conditional(spy < 0, self.cmax, conditional(smy > 0, self.cmin, 0))) else: self.gamma.append( conditional( spx < 0, ufl.Min(-1.0 * spx / self.alpha, self.cmax), conditional(smx > 0, ufl.Max(-1.0 * smx / self.alpha, self.cmin), 0))) self.gamma.append( conditional( spy < 0, ufl.Min(-1.0 * spy / self.alpha, self.cmax), conditional(smy > 0, ufl.Max(-1.0 * smy / self.alpha, self.cmin), 0)))
def initControl(self): # Initialize control spaces self.controlSpace = [FunctionSpace(self.mesh, "DG", 1)] # Initialize controls P, Inv = SpatialCoordinate(self.mesh) cmax = self.k1 * sqrt(Inv) cmin = -self.k2 * sqrt(1 / (Inv + self.k3) - 1 / self.k4) ui = Dx(self.u, 1) u1 = self.Gamma(cmin, P, ui) u2 = self.Gamma(-Constant(self.k5), P, ui) u3 = self.Gamma(Constant(0.0), P, ui) u4 = self.Gamma(cmax, P, ui) umax = ufl.Max(u1, ufl.Max(u2, ufl.Max(u3, u4))) # self.gamma[0] = cmin g1 = conditional( u1 >= umax, cmin, conditional(u2 >= umax, -self.k5, conditional(u3 >= umax, 0.0, cmax))) self.gamma = [g1]
def eigenstate_legacy(A): """Eigenvalues and eigenprojectors of the 3x3 (real-valued) tensor A. Provides the spectral decomposition A = sum_{a=0}^{2} λ_a * E_a with eigenvalues λ_a and their associated eigenprojectors E_a = n_a^R x n_a^L ordered by magnitude. The eigenprojectors of eigenvalues with multiplicity n are returned as 1/n-fold projector. Note: Tensor A must not have complex eigenvalues! """ if ufl.shape(A) != (3, 3): raise RuntimeError( f"Tensor A of shape {ufl.shape(A)} != (3, 3) is not supported!") # eps = 1.0e-10 # A = ufl.variable(A) # # --- determine eigenvalues λ0, λ1, λ2 # # additively decompose: A = tr(A) / 3 * I + dev(A) = q * I + B q = ufl.tr(A) / 3 B = A - q * ufl.Identity(3) # observe: det(λI - A) = 0 with shift λ = q + ω --> det(ωI - B) = 0 = ω**3 - j * ω - b j = ufl.tr( B * B ) / 2 # == -I2(B) for trace-free B, j < 0 indicates A has complex eigenvalues b = ufl.tr(B * B * B) / 3 # == I3(B) for trace-free B # solve: 0 = ω**3 - j * ω - b by substitution ω = p * cos(phi) # 0 = p**3 * cos**3(phi) - j * p * cos(phi) - b | * 4 / p**3 # 0 = 4 * cos**3(phi) - 3 * cos(phi) - 4 * b / p**3 | --> p := sqrt(j * 4 / 3) # 0 = cos(3 * phi) - 4 * b / p**3 # 0 = cos(3 * phi) - r with -1 <= r <= +1 # phi_k = [acos(r) + (k + 1) * 2 * pi] / 3 for k = 0, 1, 2 p = 2 / ufl.sqrt(3) * ufl.sqrt(j + eps**2) # eps: MMM r = 4 * b / p**3 r = ufl.Max(ufl.Min(r, +1 - eps), -1 + eps) # eps: LMM, MMH phi = ufl.acos(r) / 3 # sorted eigenvalues: λ0 <= λ1 <= λ2 λ0 = q + p * ufl.cos(phi + 2 / 3 * ufl.pi) # low λ1 = q + p * ufl.cos(phi + 4 / 3 * ufl.pi) # middle λ2 = q + p * ufl.cos(phi) # high # # --- determine eigenprojectors E0, E1, E2 # E0 = ufl.diff(λ0, A).T E1 = ufl.diff(λ1, A).T E2 = ufl.diff(λ2, A).T # return [λ0, λ1, λ2], [E0, E1, E2]
def updateCoefficients(self): x, y = SpatialCoordinate(self.mesh) sigma1 = 0.3 sigma2 = 0.3 rho = 0.5 r = 0.05 K = 40 self.u_T = ufl.Max(K - ufl.Min(x, y), 0) self.u_ = ExplicitSolution_WorstOfTwoAssetsPut( self.t, K, r, self.T[1], sigma1, sigma2, rho, cell=self.mesh.ufl_cell(), domain=self.mesh) # Init coefficient matrix self.a = 0.5 * \ as_matrix([[sigma1**2 * x**2, rho*sigma1*sigma2*x*y], [rho*sigma1*sigma2*x*y, sigma2**2 * y**2]]) self.b = as_vector([r * x, r * y]) self.c = Constant(-r) # Init right-hand side self.f = Constant(0.0) # Set boundary conditions to exact solution if self.exact_bc: self.g = ExplicitSolution_WorstOfTwoAssetsPut( self.t, K, r, self.T[1], sigma1, sigma2, rho, cell=self.mesh.ufl_cell(), domain=self.mesh) else: self.g = [(Constant(0.0), 'near(max(x[0],x[1]),200)'), (Constant(K * exp(-r * (self.T[1] - self.t))), 'near(min(x[0],x[1]),0)')]
def get_scaled_jacobians2d(mesh, python=False): """ Computes the scaled Jacobian of each cell in a 2D triangular mesh :arg mesh: the input mesh to do computations on :kwarg python: compute the measure using Python? :rtype: firedrake.function.Function scaled_jacobians with scaled jacobian data. """ P0 = firedrake.FunctionSpace(mesh, "DG", 0) if python: P0_ten = firedrake.TensorFunctionSpace(mesh, "DG", 0) J = firedrake.interpolate(ufl.Jacobian(mesh), P0_ten) edge1 = ufl.as_vector([J[0, 0], J[1, 0]]) edge2 = ufl.as_vector([J[0, 1], J[1, 1]]) edge3 = edge1 - edge2 a = ufl.sqrt(ufl.dot(edge1, edge1)) b = ufl.sqrt(ufl.dot(edge2, edge2)) c = ufl.sqrt(ufl.dot(edge3, edge3)) detJ = ufl.JacobianDeterminant(mesh) jacobian_sign = ufl.sign(detJ) max_product = ufl.Max( ufl.Max(ufl.Max(a * b, a * c), ufl.Max(b * c, b * a)), ufl.Max(c * a, c * b) ) scaled_jacobians = firedrake.interpolate(detJ / max_product * jacobian_sign, P0) else: coords = mesh.coordinates scaled_jacobians = firedrake.Function(P0) op2.par_loop( get_pyop2_kernel("get_scaled_jacobian", 2), mesh.cell_set, scaled_jacobians.dat(op2.WRITE, scaled_jacobians.cell_node_map()), coords.dat(op2.READ, coords.cell_node_map()), ) return scaled_jacobians
def eig(A): """Eigenvalues of 3x3 tensor""" eps = 1.0e-12 q = ufl.tr(A) / 3.0 p1 = 0.5 * (A[0, 1]**2 + A[1, 0]**2 + A[0, 2]**2 + A[2, 0]**2 + A[1, 2]**2 + A[2, 1]**2) p2 = (A[0, 0] - q)**2 + (A[1, 1] - q)**2 + (A[2, 2] - q)**2 + 2 * p1 p = ufl.sqrt(p2 / 6) B = (A - q * ufl.Identity(3)) r = ufl.det(B) / (2 * p**3) r = ufl.Max(ufl.Min(r, 1.0 - eps), -1.0 + eps) phi = ufl.acos(r) / 3.0 eig0 = ufl.conditional(p2 < eps, q, q + 2 * p * ufl.cos(phi)) eig2 = ufl.conditional(p2 < eps, q, q + 2 * p * ufl.cos(phi + (2 * numpy.pi / 3))) eig1 = ufl.conditional(p2 < eps, q, 3 * q - eig0 - eig2) # since trace(A) = eig1 + eig2 + eig3 return eig0, eig1, eig2
def comp_Q_vaf(self, verbose=False): """QOI: Volume above flotation""" cnst = self.params.constants H = self.H_np # B stands in for self.bed, which leads to a taping error B = Function(self.bed.function_space()) B.assign(self.bed, annotate=False) rhoi = Constant(cnst.rhoi) rhow = Constant(cnst.rhow) dIce = self.dIce # dt = self.dt b_ex = conditional(B < 0.0, 1.0, 0.0) HAF = ufl.Max(b_ex * (H + (rhow / rhoi) * B) + (1 - b_ex) * (H), 0.0) Q_vaf = HAF * dIce if verbose: info(f"Q_vaf: {assemble(Q_vaf)}") return Q_vaf
import dolfin as df import numpy as np import ufl # TODO: more ... linear = lambda x: x ReLu = lambda x: ufl.Max(x, df.Constant(0)) class DenseLayer(object): def __init__(self, input_dim, output_dim, mesh, use_bias=True, activation=linear): self.input_dim = input_dim # Remeber for consistency checks # Represent (odim, idim) matrix by rows W_space = df.VectorFunctionSpace(mesh, 'R', 0, input_dim) self.weights = [ self.init_weights(W_space) for row in range(output_dim) ] if use_bias: b_space = df.VectorFunctionSpace(mesh, 'R', 0, output_dim) self.bias = self.init_bias(b_space) else: self.bias = None self.rho = activation
def gen_alpha(self, a_bgd=500.0, a_lb=1e2, a_ub=1e4): """Generate initial guess for alpha (slip coeff)""" method = self.params.inversion.initial_guess_alpha_method.lower() if method == "wearing": # Martin Wearing's: alpha = 358.4 - 26.9*log(17.9*speed_obs); u_obs = self.u_obs_M v_obs = self.v_obs_M vel_rp = self.params.constants.vel_rp U_mag = sqrt(u_obs**2 + v_obs**2 + vel_rp**2) # U_mag = ufl.Max((u_obs**2 + v_obs**2)**(1/2.0), 50.0) B2 = 358.4 - 26.9 * ln(17.9 * U_mag) alpha = self.bdrag_to_alpha(B2) self.alpha.assign(project(alpha, self.Qp)) elif method == "sia": bed = self.bed H = self.H g = self.params.constants.g rhoi = self.params.constants.rhoi rhow = self.params.constants.rhow u_obs = self.u_obs_M v_obs = self.v_obs_M vel_rp = self.params.constants.vel_rp U = ufl.Max((u_obs**2 + v_obs**2)**(1 / 2.0), 50.0) # Flotation Criterion H_flt = -rhow / rhoi * bed fl_ex = conditional(H <= H_flt, 1.0, 0.0) # Thickness Criterion m_d = conditional(H > 0, 1.0, 0.0) # Calculate surface gradient R_f = ((1.0 - fl_ex) * bed + (fl_ex) * (-rhoi / rhow) * H) s_ = ufl.Max(H + R_f, 0) s = project(s_, self.Q) grads = (s.dx(0)**2.0 + s.dx(1)**2.0)**(1.0 / 2.0) # Calculate alpha, apply background, apply bound B2_ = ((1.0 - fl_ex) * rhoi * g * H * grads / U + (fl_ex) * a_bgd) * m_d + (1.0 - m_d) * a_bgd B2_tmp1 = ufl.Max(B2_, a_lb) B2_tmp2 = ufl.Min(B2_tmp1, a_ub) alpha = self.bdrag_to_alpha(B2_tmp2) self.alpha.assign(project(alpha, self.Qp)) elif method == "constant": init_guess = self.params.inversion.initial_guess_alpha self.alpha.vector()[:] = init_guess self.alpha.vector().apply('insert') else: raise NotImplementedError(f"Don't have code for method {method}") function_update_state(self.alpha) write_diag = self.params.io.write_diagnostics if write_diag: diag_dir = self.params.io.diagnostics_dir phase_suffix = self.params.inversion.phase_suffix phase_name = self.params.inversion.phase_name inout.write_variable(self.alpha, self.params, name="alpha_init_guess", outdir=diag_dir, phase_name=phase_name, phase_suffix=phase_suffix)
return rho * g * Hmid * S.dx(0) * phi(s) # Driving stress (floating) def tau_dx_f(s): return rho * g * (1 - rho / rho_w) * Hmid * Hmid.dx(0) * phi(s) # Normal vectors normalx = (B.dx(0)) / sqrt((B.dx(0))**2 + 1.0) normalz = sqrt(1 - normalx**2) # Overburden P_0 = rho * g * Hmid # Water pressure (ocean only, no basal hydro.) P_w = ufl.Max(-rho_w * g * B, 1e-16) # basal shear stress applied on grounded ice tau_b = beta2 * u(1) / (1.0 - normalx**2) * grounded # Momentum balance residual (Blatter-Pattyn/O(1)/LMLa) R = (-vi.intz(membrane_xx) - vi.intz(shear_xz) - phi(1) * tau_b - vi.intz(tau_dx) * grounded - vi.intz(tau_dx_f) * (1 - grounded)) * dx # shelf front boundary condition F_ocean_x = 1.0 / 2.0 * rho * g * (1 - (rho / rho_w)) * H**2 * Phi[0] * ds(1) R += F_ocean_x # # MASS BALANCE ###################################
def def_mom_eq(self): """Define the momentum equation to be solved in solve_mom_eq""" # Simplify accessing fields and parameters constants = self.params.constants bed = self.bed H = self.H alpha = self.alpha rhoi = constants.rhoi rhow = constants.rhow delta = 1.0 - rhoi / rhow g = constants.g n = constants.glen_n tol = constants.float_eps dIce = self.dIce ds = self.ds sl = self.params.ice_dynamics.sliding_law vel_rp = constants.vel_rp # Vector components of trial function u, v = split(self.U) # Vector components of test function Phi = self.Phi Phi_x, Phi_y = split(Phi) # Derivatives u_x, u_y = u.dx(0), u.dx(1) v_x, v_y = v.dx(0), v.dx(1) # Viscosity U_marker = Function(self.U.function_space(), name="%s_marker" % self.U.name()) nu = self.viscosity(U_marker) # Switch parameters H_s = -rhow / rhoi * bed fl_ex = self.float_conditional(H, H_s) B2 = self.sliding_law(alpha, U_marker) ############################################## # Construct weak form ############################################## # Driving stress quantities F = (1 - fl_ex) * 0.5*rhoi*g*H**2 + \ (fl_ex) * 0.5*rhoi*g*(delta*H**2 + (1-delta)*H_s**2 ) W = (1 - fl_ex) * rhoi*g*H + \ (fl_ex) * rhoi*g*H_s # Depth of the submarine portion of the calving front # ufl.Max to avoid edge case of land termininating calving front draft = ufl.Max(((fl_ex) * (rhoi / rhow) * H - (1 - fl_ex) * bed), Constant(0.0)) # Terminating margin boundary condition # The -F term is related to the integration by parts in the weak form sigma_n = 0.5 * rhoi * g * ((H**2) - (rhow / rhoi) * (draft**2)) self.mom_F = ( # Membrance Stresses -inner(grad(Phi_x), H * nu * as_vector([4 * u_x + 2 * v_y, u_y + v_x])) * self.dIce - inner(grad(Phi_y), H * nu * as_vector([u_y + v_x, 4 * v_y + 2 * u_x])) * self.dIce # Basal Drag - inner(Phi, (1.0 - fl_ex) * B2 * as_vector([u, v])) * self.dIce # Driving Stress + (div(Phi) * F - inner(grad(bed), W * Phi)) * self.dIce) # Natural BC term which falls out of weak form: # Doesn't apply when domain is periodic if not self.params.mesh.periodic_bc: self.mom_F -= inner(Phi * F, self.nm) * ds ########################################## # Boundary Conditions ########################################## # Dirichlet self.flow_bcs = [] for bc in self.params.bcs: if bc.flow_bc == "obs_vel": dirichlet_condition = self.latbc elif bc.flow_bc == "no_slip": dirichlet_condition = Constant((0.0, 0.0)) elif bc.flow_bc == "free_slip": raise NotImplementedError else: continue # Add the dirichlet condition to list self.flow_bcs.extend([ DirichletBC(self.V, dirichlet_condition, self.ff, lab) for lab in bc.labels ]) # Neumann # We construct a MeasureSum of different exterior facet sections # (for now this is only for the calving front) # Then we add to the neumann_bcs list: calving_weak_form_bc * ds(calving_fronts) self.neumann_bcs = [] for bc in self.params.bcs: if bc.flow_bc == "calving": condition = inner(Phi * sigma_n, self.nm) else: # don't need to do anything for 'natural' continue measure_list = [ds(i) for i in bc.labels] measure_sum = measure_list[0] for m in measure_list[1:]: measure_sum += m self.neumann_bcs.append(condition * measure_sum) # Add the Neumann BCs to the weak form for neumann in self.neumann_bcs: self.mom_F += neumann ########################################### # Expand derivatives & add marker functions ########################################### self.mom_Jac_p = ufl.algorithms.expand_derivatives( ufl.replace(derivative(self.mom_F, self.U), {U_marker: self.U})) self.mom_F = ufl.algorithms.expand_derivatives( ufl.replace(self.mom_F, {U_marker: self.U})) self.mom_Jac = ufl.algorithms.expand_derivatives( derivative(self.mom_F, self.U))
def eps_eqv(sigma, E): e1, e2, e3 = fecoda.misc.eig(sigma) eqv = ufl.Max(e1, ufl.Max(e2, e3)) / E return eqv
def compile_forms(iv0, iv1, w0, w1, f, g, heat_flux, water_flux, co2_flux, t, dt, reb_dx, con_dx, damage_off=False, randomize=0.0): """Return Jacobian and residual forms""" t0 = time() mesh = w0["displ"].function_space.mesh # Prepare zero initial guesses, test and trial fctions, global w_displ_trial = ufl.TrialFunction(w0["displ"].function_space) w_displ_test = ufl.TestFunction(w0["displ"].function_space) w_temp_trial = ufl.TrialFunction(w0["temp"].function_space) w_temp_test = ufl.TestFunction(w0["temp"].function_space) w_phi_trial = ufl.TrialFunction(w0["phi"].function_space) w_phi_test = ufl.TestFunction(w0["phi"].function_space) w_co2_trial = ufl.TrialFunction(w0["co2"].function_space) w_co2_test = ufl.TestFunction(w0["co2"].function_space) # # Creep, shrinkage strains # # Autogenous shrinkage increment deps_sh_au = (mps.eps_sh_au(t + dt) - mps.eps_sh_au(t)) # Thermal strain increment deps_th = (misc.beta_C * (w1["temp"] - w0["temp"]) * ufl.Identity(3)) # Drying shrinkage increment deps_sh_dr = (mps.k_sh * (w1["phi"] - w0["phi"]) * ufl.Identity(3)) eta_dash_mid = mps.eta_dash(iv0["eta_dash"], dt / 2.0, w0["temp"], w0["phi"]) # Prepare creep factors beta_cr = mps.beta_cr(dt) lambda_cr = mps.lambda_cr(dt, beta_cr) creep_v_mid = mps.creep_v(t + dt / 2.0) if randomize > 0.0: # Randomize Young's modulus # This helps convergence at the point where crack initiation begins # Randomized E fluctuates uniformly in [E-eps/2, E+eps/2] rnd = Function(iv0["eta_dash"].function_space) rnd.vector.array[:] = 1.0 - randomize / 2 + np.random.rand( *rnd.vector.array.shape) * randomize else: rnd = 1.0 E_kelv = rnd * mps.E_kelv(creep_v_mid, lambda_cr, dt, t, eta_dash_mid) gamma0 = [] for i in range(mps.M): gamma0.append(iv0[f"gamma_{i}"]) deps_cr_kel = mps.deps_cr_kel(beta_cr, gamma0, creep_v_mid) deps_cr_dash = mps.deps_cr_dash(iv0["sigma"], eta_dash_mid, dt) deps_el = mech.eps_el(w1["displ"] - w0["displ"], deps_th, deps_cr_kel, deps_cr_dash, deps_sh_dr, deps_sh_au) # Water vapour saturation pressure p_sat = water.p_sat(0.5 * (w1["temp"] + w0["temp"])) water_cont = water.water_cont(0.5 * (w1["phi"] + w0["phi"])) dw_dphi = water.dw_dphi(0.5 * (w1["phi"] + w0["phi"])) # Rate of CaCO_3 concentration change dot_caco3 = co2.dot_caco3(dt * 24 * 60 * 60, iv0["caco3"], w1["phi"], w1["co2"], w1["temp"]) # # Balances residuals # sigma_eff = iv0["sigma"] + mech.stress(E_kelv, deps_el) eps_eqv = ufl.Max( damage_rankine.eps_eqv(sigma_eff, mps.E_static(creep_v_mid)), iv0["eps_eqv"]) f_c = mech.f_c(t) f_t = mech.f_t(f_c) G_f = mech.G_f(f_c) dmg = damage_rankine.damage(eps_eqv, mesh, mps.E_static(creep_v_mid), f_t, G_f) # Prepare stress increments if damage_off: dmg = 0.0 * dmg eps_eqv = iv0["eps_eqv"] sigma_rebar = mech.stress_rebar(mech.E_rebar, w1["displ"]) sigma = (1.0 - dmg) * sigma_eff _con_dx = [] for dx in con_dx: _con_dx += [dx(metadata={"quadrature_degree": quad_degree_stress})] _con_dx = ufl.classes.MeasureSum(*_con_dx) _reb_dx = [] for dx in reb_dx: _reb_dx += [dx(metadata={"quadrature_degree": quad_degree_stress})] _reb_dx = ufl.classes.MeasureSum(*_reb_dx) # Momentum balance for concrete material mom_balance = -ufl.inner(sigma, ufl.grad(w_displ_test)) * _con_dx # Momentum balance for rebar material if len(reb_dx) > 0: mom_balance += -ufl.inner(sigma_rebar, ufl.grad(w_displ_test)) * _reb_dx # Add volume body forces for measure, force in g.items(): mom_balance -= ufl.inner(force, w_displ_test) * measure # Add surface forces to mom balance for measure, force in f.items(): mom_balance += ufl.inner(force, w_displ_test) * measure _thc_dx = [] for dx in con_dx + reb_dx: _thc_dx += [dx(metadata={"quadrature_degree": quad_degree_thc})] _thc_dx = ufl.classes.MeasureSum(*_thc_dx) # Energy balance = evolution of temperature energy_balance = ( mech.rho_c * misc.C_pc / (dt * 24 * 60 * 60) * ufl.inner( (w1["temp"] - w0["temp"]), w_temp_test) * _thc_dx + misc.lambda_c * ufl.inner(ufl.grad(w1["temp"]), ufl.grad(w_temp_test)) * _thc_dx + water.h_v * water.delta_p * ufl.inner(ufl.grad( w1["phi"] * p_sat), ufl.grad(w_temp_test)) * _thc_dx + co2.alpha3 * dot_caco3 * w_temp_test * _thc_dx) # Water balance = evolution of humidity water_balance = (ufl.inner( dw_dphi * 1.0 / (dt * 24 * 60 * 60) * (w1["phi"] - w0["phi"]), w_phi_test) * _thc_dx + ufl.inner( dw_dphi * water.D_ws(water_cont) * ufl.grad(w1["phi"]) + water.delta_p * ufl.grad(w1["phi"] * p_sat), ufl.grad(w_phi_test)) * _thc_dx + co2.alpha2 * dot_caco3 * w_phi_test * _thc_dx) for measure, flux in water_flux.items(): water_balance -= ufl.inner(flux, w_phi_test) * measure co2_balance = ( ufl.inner(1.0 / (dt * 24 * 60 * 60) * (w1["co2"] - w0["co2"]), w_co2_test) * _thc_dx + ufl.inner(co2.D_co2 * ufl.grad(w1["co2"]), ufl.grad(w_co2_test)) * _thc_dx + co2.alpha4 * dot_caco3 * w_co2_test * _thc_dx) for measure, flux in co2_flux.items(): co2_balance -= ufl.inner(flux, w_co2_test) * measure J_mom = ufl.derivative(mom_balance, w1["displ"], w_displ_trial) J_energy_temp = ufl.derivative(energy_balance, w1["temp"], w_temp_trial) J_energy_hum = ufl.derivative(energy_balance, w1["phi"], w_phi_trial) J_energy_co2 = ufl.derivative(energy_balance, w1["co2"], w_co2_trial) J_energy = J_energy_hum + J_energy_temp + J_energy_co2 J_water_temp = ufl.derivative(water_balance, w1["temp"], w_temp_trial) J_water_hum = ufl.derivative(water_balance, w1["phi"], w_phi_trial) J_water_co2 = ufl.derivative(water_balance, w1["co2"], w_co2_trial) J_water = J_water_temp + J_water_hum + J_water_co2 J_co2_temp = ufl.derivative(co2_balance, w1["temp"], w_temp_trial) J_co2_hum = ufl.derivative(co2_balance, w1["phi"], w_phi_trial) J_co2_co2 = ufl.derivative(co2_balance, w1["co2"], w_co2_trial) J_co2 = J_co2_temp + J_co2_hum + J_co2_co2 # Put all Jacobians together J_all = J_mom + J_energy + J_water + J_co2 # Lower algebra symbols and apply derivatives up to terminals # This is needed for the Replacer to work properly preserve_geometry_types = (ufl.CellVolume, ufl.FacetArea) J_all = ufl.algorithms.apply_algebra_lowering.apply_algebra_lowering(J_all) J_all = ufl.algorithms.apply_derivatives.apply_derivatives(J_all) J_all = ufl.algorithms.apply_geometry_lowering.apply_geometry_lowering( J_all, preserve_geometry_types) J_all = ufl.algorithms.apply_derivatives.apply_derivatives(J_all) J_all = ufl.algorithms.apply_geometry_lowering.apply_geometry_lowering( J_all, preserve_geometry_types) J_all = ufl.algorithms.apply_derivatives.apply_derivatives(J_all) J = extract_blocks(J_all, [w_displ_test, w_temp_test, w_phi_test, w_co2_test], [w_displ_trial, w_temp_trial, w_phi_trial, w_co2_trial]) J[0][0]._signature = "full" if not damage_off else "dmgoff" # Just make sure these are really empty Forms assert len(J[1][0].arguments()) == 0 assert len(J[2][0].arguments()) == 0 assert len(J[3][0].arguments()) == 0 F = [-mom_balance, -energy_balance, -water_balance, -co2_balance] rank = MPI.COMM_WORLD.rank if rank == 0: logger.info("Compiling tangents J...") J_compiled = [ Form(J[0][0]), [[Form(J[i][j]) for j in range(1, 4)] for i in range(1, 4)] ] if rank == 0: logger.info("Compiling residuals F...") F_compiled = [Form(F[0]), [Form(F[i]) for i in range(1, 4)]] expr = OrderedDict() eta_dash1 = mps.eta_dash(iv0["eta_dash"], dt, w1["temp"], w1["phi"]) expr["eta_dash"] = (eta_dash1, iv0["eta_dash"].function_space.ufl_element()) expr["caco3"] = (iv0["caco3"] + dt * 24 * 60 * 60 * dot_caco3, iv0["caco3"].function_space.ufl_element()) expr["eps_cr_kel"] = (iv0["eps_cr_kel"] + deps_cr_kel, iv0["eps_cr_kel"].function_space.ufl_element()) expr["eps_cr_dash"] = (iv0["eps_cr_dash"] + deps_cr_dash, iv0["eps_cr_dash"].function_space.ufl_element()) expr["eps_sh_dr"] = (iv0["eps_sh_dr"] + deps_sh_dr, iv0["eps_sh_dr"].function_space.ufl_element()) expr["eps_th"] = (iv0["eps_th"] + deps_th, iv0["eps_th"].function_space.ufl_element()) expr["sigma"] = (iv0["sigma"] + mech.stress(E_kelv, deps_el), iv0["sigma"].function_space.ufl_element()) expr["eps_eqv"] = (eps_eqv, iv0["eps_eqv"].function_space.ufl_element()) expr["dmg"] = (dmg, iv0["dmg"].function_space.ufl_element()) for i in range(mps.M): expr[f"gamma_{i}"] = (lambda_cr[i] * (iv1["sigma"] - iv0["sigma"]) + (beta_cr[i]) * gamma0[i], gamma0[i].function_space.ufl_element()) expr_compiled = OrderedDict() for name, item in expr.items(): if rank == 0: logger.info(f"Compiling expressions for {name}...") expr_compiled[name] = CompiledExpression(item[0], item[1]) if rank == 0: logger.info(f"[Timer] UFL forms setup and compilation: {time() - t0}") return J_compiled, F_compiled, expr_compiled
# Total differential of yield function df = + ufl.inner(ufl.diff(f, S), S - S0) \ + ufl.inner(ufl.diff(f, h), h - h0) \ + ufl.inner(ufl.diff(f, B), B - B0) # Derivative of plastic potential wrt stress dgdS = ufl.diff(g, S) # Unwrap expression from variable S, B, h = S.expression(), B.expression(), h.expression() # Variation of Green-Lagrange strain δE = dolfiny.expression.derivative(E, m, δm) # Plastic multiplier (J2 plasticity: closed-form solution for return-map) dλ = ufl.Max(f, 0) # ppos = MacAuley bracket # Weak form (as one-form) F = + ufl.inner(δE, S) * dx \ + ufl.inner(δP, (P - P0) - dλ * dgdS) * dx \ + ufl.inner(δh, (h - h0) - dλ * bh * (qh * 1.00 - h)) * dx \ + ufl.inner(δB, (B - B0) - dλ * bb * (qb * dgdS - B)) * dx # Overall form (as list of forms) F = dolfiny.function.extract_blocks(F, δm) # Create output xdmf file -- open in Paraview with Xdmf3ReaderT ofile = dolfiny.io.XDMFFile(comm, f"{name}.xdmf", "w") # Write mesh, meshtags ofile.write_mesh_meshtags(mesh, mts)
def psi_plus_linear_elasticity_model_B(epsilon, lamda, mu): dim = 2 bulk_mod = lamda + 2. * mu / dim tr_epsilon_plus = ufl.Max(fe.tr(epsilon), 0) return bulk_mod / 2. * tr_epsilon_plus**2 + mu * fe.inner( fe.dev(epsilon), fe.dev(epsilon))
def tau_dx(): return rho * g * H_ * S.dx(0) * phibar points, weights = full_quad(4) vi = VerticalIntegrator(points, weights) # Pressure and sliding law normalx = (B.dx(0) + h_s.dx(0)) / df.sqrt((B.dx(0) + h_s.dx(0))**2 + 1.0) normalz = df.sqrt(1 - normalx**2) P_0 = H P_w = ufl.Max(k * H, rho_w / rho_i * (l - Base)) N = ufl.Max(P_0 - P_w, df.Constant(0.000)) # tau_b = beta2 * u(1) * N tau_b = (beta2 * (abs(N) + 1.0e-4)**(1.0 / n_sliding) * (abs(u(1)) + 1.0e-4)**(1.0 / n_sliding - 1) * u(1)) # tau_b = ( # beta2 # * (abs(u(1)) + 1.0) ** (1.0 / n - 1) # * u(1) # * (abs(N) + 1.0) ** (1.0 / n) # # * (1 - normalx**2) # # * grounded # ) I_stress = (-vi.intz(membrane_xx) - vi.intz(shear_xz) - phi(1) * tau_b - tau_dx()) * df.dx
def main(config_file): print("===WARNING=== - this code has not been fully adapted to new config format") print("Consult TODOs in run_balancemeltrates.py") init_yr = 5 #TODO - where in the config? #Read run config file params = ConfigParser(config_file) log = inout.setup_logging(params) inout.log_preamble("balance meltrates", params) dd = params.io.input_dir outdir = params.io.output_dir run_length = params.time.run_length n_steps = params.time.total_steps assert init_yr < run_length # #Load Data # param = pickle.load( open( os.path.join(dd,'param.p'), "rb" ) ) # param['outdir'] = outdir # param['sliding_law'] = sl # param['picard_params'] = {"nonlinear_solver":"newton", # "newton_solver":{"linear_solver":"umfpack", # "maximum_iterations":25, # "absolute_tolerance":1.0e-3, # "relative_tolerance":5.0e-2, # "convergence_criterion":"incremental", # "error_on_nonconvergence":False, # "lu_solver":{"same_nonzero_pattern":False, "symmetric":False, "reuse_factorization":False}}} #Load Data mesh = Mesh(os.path.join(outdir, 'mesh.xml')) M = FunctionSpace(mesh, 'DG', 0) #TODO - what's the logic here?: Q = FunctionSpace(mesh, 'Lagrange', 1)# if os.path.isfile(os.path.join(dd,'param.p')) else M mask = Function(M,os.path.join(outdir,'mask.xml')) if os.path.isfile(os.path.join(outdir,'data_mesh.xml')): data_mesh = Mesh(os.path.join(outdir,'data_mesh.xml')) Mdata = FunctionSpace(data_mesh, 'DG', 0) data_mask = Function(Mdata, os.path.join(outdir,'data_mask.xml')) else: data_mesh = mesh data_mask = mask if not params.mesh.periodic_bc: Qp = Q V = VectorFunctionSpace(mesh,'Lagrange',1,dim=2) else: Qp = fice_mesh.get_periodic_space(params, mesh, dim=1) V = fice_mesh.get_periodic_space(params, mesh, dim=2) #Load fields U = Function(V,os.path.join(outdir,'U.xml')) alpha = Function(Qp,os.path.join(outdir,'alpha.xml')) beta = Function(Qp,os.path.join(outdir,'beta.xml')) bed = Function(Q,os.path.join(outdir,'bed.xml')) smb = Function(M,os.path.join(outdir, 'smb.xml')) thick = Function(M,os.path.join(outdir,'thick.xml')) mask_vel = Function(M,os.path.join(outdir,'mask_vel.xml')) u_obs = Function(M,os.path.join(outdir,'u_obs.xml')) v_obs = Function(M,os.path.join(outdir,'v_obs.xml')) u_std = Function(M,os.path.join(outdir,'u_std.xml')) v_std = Function(M,os.path.join(outdir,'v_std.xml')) uv_obs = Function(M,os.path.join(outdir,'uv_obs.xml')) mdl = model.model(mesh, data_mask, params, init_fields=False) # TODO initialization mdl.init_bed(bed) mdl.init_thick(thick) mdl.gen_surf() mdl.init_mask(mask) mdl.init_vel_obs(u_obs,v_obs,mask_vel,u_std,v_std) mdl.init_lat_dirichletbc() mdl.init_bmelt(Constant(0.0)) mdl.init_alpha(alpha) mdl.init_beta(beta, False) mdl.init_smb(smb) mdl.label_domain() #Solve slvr = solver.ssa_solver(mdl) slvr.save_ts_zero() slvr.timestep(save = 1, adjoint_flag=0) #Balance melt rates #Load time series of ice thicknesses hdf = HDF5File(slvr.mesh.mpi_comm(), os.path.join(outdir, 'H_ts.h5'), "r") attr = hdf.attributes("H") nsteps = attr['count'] #model time step dt = params.time.dt #Model iterations to difference between iter_s = np.ceil(init_yr/dt) #Iteration closest to 5yr iter_f = nsteps - 1 #Final iteration dT = dt*(iter_f - iter_s) #Time diff in years between iterations #Read iteration data HS = Function(slvr.M) HF = Function(slvr.M) hdf.read(HS, "H/vector_{0}".format(int(iter_s))) hdf.read(HF, "H/vector_{0}".format(int(iter_f))) #Mask out grounded region rhow = params.constants.rhow rhoi = params.constants.rhoi H_s = -rhow/rhoi * bed fl_ex = conditional(slvr.H_init <= H_s, Constant(1.0), Constant(0.0)) #Calculate bmelt bmelt = project(ufl.Max(fl_ex*(HF - HS)/dT, Constant(0.0)), slvr.M) #Output model variables in ParaView+Fenics friendly format pickle.dump( mdl.param, open( os.path.join(outdir,'bmeltrate_param.p'), "wb" ) ) # File(os.path.join(outdir,'mesh.xml')) << mdl.mesh vtkfile = File(os.path.join(outdir,'bmelt.pvd')) xmlfile = File(os.path.join(outdir,'bmelt.xml')) vtkfile << bmelt xmlfile << bmelt return mdl
def u_T(x, y): return ufl.Max(y - K, 0)