def initialize_solvers(self): # Kinematics # Right Cauchy-Green tensor if self.nonlin: d = self.X.geometric_dimension() I = fd.Identity(d) # Identity tensor F = I + fd.grad(self.X) # Deformation gradient C = F.T * F E = (C - I) / 2. # Green-Lagrangian strain # E = 1./2.*( fd.grad(self.X).T + fd.grad(self.X) + fd.grad(self.X).T * fd.grad(self.X) ) # alternative equivalent definition else: E = 1. / 2. * (fd.grad(self.X).T + fd.grad(self.X) ) # linear strain self.W = (self.lam / 2.) * (fd.tr(E))**2 + self.mu * fd.tr(E * E) # f = fd.Constant((0, 0, -self.g)) # body force / rho # T = self.surface_force() # Total potential energy Pi = self.W * fd.dx # Compute first variation of Pi (directional derivative about X in the direction of v) F_expr = fd.derivative(Pi, self.X, self.v) self.DBC = fd.DirichletBC(self.V, fd.as_vector([0., 0., 0.]), self.bottom_id) # delX = fd.nabla_grad(self.X) # delv_B = fd.nabla_grad(self.v) # T_x_dv = self.lam * fd.div(self.X) * fd.div(self.v) \ # + self.mu * ( fd.inner( delX, delv_B + fd.transpose(delv_B) ) ) self.a_U = fd.dot(self.trial, self.v) * fd.dx # self.L_U = ( fd.dot( self.U, self.v ) - self.dt/2./self.rho * T_x_dv ) * fd.dx self.L_U = fd.dot( self.U, self.v) * fd.dx - self.dt / 2. / self.rho * F_expr #\ # + self.dt/2./self.rho*fd.dot(T,self.v)*fd.ds(1) # surface force at x==0 plane # + self.dt/2.*fd.dot(f,self.v)*fd.dx # body force self.a_X = fd.dot(self.trial, self.v) * fd.dx # self.L_interface = fd.dot(self.phi_vect, self.v) * fd.ds(self.interface_id) self.L_X = fd.dot((self.X + self.dt * self.U), self.v) * fd.dx #\ # - self.dt/self.rho * self.L_interface self.LVP_U = fd.LinearVariationalProblem(self.a_U, self.L_U, self.U, bcs=[self.DBC]) self.LVS_U = fd.LinearVariationalSolver(self.LVP_U) self.LVP_X = fd.LinearVariationalProblem(self.a_X, self.L_X, self.X, bcs=[self.DBC]) self.LVS_X = fd.LinearVariationalSolver(self.LVP_X)
def __init__(self, mesh, conditions, timestepping, params, output, solver_params): super().__init__(mesh, conditions, timestepping, params, output, solver_params) self.u0 = Function(self.V) self.u1 = Function(self.V) self.sigma0 = Function(self.S) self.sigma1 = Function(self.S) theta = conditions.theta uh = (1-theta) * self.u0 + theta * self.u1 a = Function(self.U) h = Function(self.U) p = TestFunction(self.V) q = TestFunction(self.S) self.initial_condition((self.u0, conditions.ic['u']), (a, conditions.ic['a']), (h, conditions.ic['h'])) ep_dot = self.strain(grad(uh)) zeta = self.zeta(h, a, self.delta(uh)) eta = zeta * params.e ** (-2) rheology = 2 * eta * ep_dot + (zeta - eta) * tr(ep_dot) * Identity(2) - 0.5 * self.Ice_Strength(h, a) * Identity(2) self.initial_condition((self.sigma0, rheology),(self.sigma1, self.sigma0)) def sigma_next(timestep, zeta, ep_dot, sigma, P): A = 1 + 0.25 * (timestep * params.e ** 2) / params.T B = timestep * 0.125 * (1 - params.e ** 2) / params.T rhs = (1 - (timestep * params.e ** 2) / (4 * params.T)) * sigma - timestep / params.T * ( 0.125 * (1 - params.e ** 2) * tr(sigma) * Identity(2) - 0.25 * P * Identity(2) + zeta * ep_dot) C = (rhs[0, 0] - rhs[1, 1]) / A D = (rhs[0, 0] + rhs[1, 1]) / (A + 2 * B) sigma00 = 0.5 * (C + D) sigma11 = 0.5 * (D - C) sigma01 = rhs[0, 1] sigma = as_matrix([[sigma00, sigma01], [sigma01, sigma11]]) return sigma s = sigma_next(self.timestep, zeta, ep_dot, self.sigma0, self.Ice_Strength(h, a)) sh = (1-theta) * s + theta * self.sigma0 eqn = self.momentum_equation(h, self.u1, self.u0, p, sh, params.rho, uh, conditions.ocean_curr, params.rho_a, params.C_a, params.rho_w, params.C_w, conditions.geo_wind, params.cor, self.timestep, ind=self.ind) tensor_eqn = inner(self.sigma1-s, q) * dx if conditions.stabilised['state']: alpha = conditions.stabilised['alpha'] eqn += stabilisation_term(alpha=alpha, zeta=avg(zeta), mesh=mesh, v=uh, test=p) bcs = DirichletBC(self.V, conditions.bc['u'], "on_boundary") uprob = NonlinearVariationalProblem(eqn, self.u1, bcs) self.usolver = NonlinearVariationalSolver(uprob, solver_parameters=solver_params.bt_params) sprob = NonlinearVariationalProblem(tensor_eqn, self.sigma1) self.ssolver = NonlinearVariationalSolver(sprob, solver_parameters=solver_params.bt_params)
def __init__(self, mesh, conditions, timestepping, params, output, solver_params): super().__init__(mesh, conditions, timestepping, params, output, solver_params) self.u0 = Function(self.V) self.u1 = Function(self.V) self.h = Function(self.U) self.a = Function(self.U) self.p = TestFunction(self.V) theta = conditions.theta self.uh = (1-theta) * self.u0 + theta * self.u1 ep_dot = self.strain(grad(self.uh)) self.initial_condition((self.u0, conditions.ic['u']),(self.u1, self.u0), (self.a, conditions.ic['a']),(self.h, conditions.ic['h'])) zeta = self.zeta(self.h, self.a, self.delta(self.uh)) eta = zeta * params.e ** -2 sigma = 2 * eta * ep_dot + (zeta - eta) * tr(ep_dot) * Identity(2) - 0.5 * self.Ice_Strength(self.h,self.a) * Identity(2) self.eqn = self.momentum_equation(self.h, self.u1, self.u0, self.p, sigma, params.rho, self.uh, conditions.ocean_curr, params.rho_a, params.C_a, params.rho_w, params.C_w, conditions.geo_wind, params.cor, self.timestep) if conditions.stabilised['state']: alpha = conditions.stabilised['alpha'] self.eqn += self.stabilisation_term(alpha=alpha, zeta=avg(zeta), mesh=mesh, v=self.uh, test=self.p) self.bcs = DirichletBC(self.V, conditions.bc['u'], "on_boundary")
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 derivative(self, out): super().derivative(out) if args.discretisation != "pkp0": return w = fd.TestFunction(self.V_m) u = solver.z.split()[0] v = solver.z_adj.split()[0] from firedrake import div, cell_avg, dx, tr, grad gamma = solver.gamma deriv = gamma * div(w) * cell_avg(div(u)) * div(v) * dx \ + gamma * (cell_avg(div(u) * div(w) - tr(grad(u)*grad(w))) - cell_avg(div(u)) * cell_avg(div(w))) * div(v) * dx \ - gamma * cell_avg(div(u)) * tr(grad(v)*grad(w)) * dx fd.assemble(deriv, tensor=self.deriv_m, form_compiler_parameters=self.params) outcopy = out.clone() outcopy.from_first_derivative(self.deriv_r) fd.warning(fd.RED % ("norm of extra term %e" % outcopy.norm())) out.plus(outcopy)
def hyperelasticity(mesh, degree): V = VectorFunctionSpace(mesh, 'Q', degree) v = TestFunction(V) du = TrialFunction(V) # Incremental displacement u = Function(V) # Displacement from previous iteration B = Function(V) # Body force per unit mass # Kinematics I = Identity(mesh.topological_dimension()) F = I + grad(u) # Deformation gradient C = F.T * F # Right Cauchy-Green tensor E = (C - I) / 2 # Euler-Lagrange strain tensor E = variable(E) # Material constants mu = Constant(1.0) # Lame's constants lmbda = Constant(0.001) # Strain energy function (material model) psi = lmbda / 2 * (tr(E)**2) + mu * tr(E * E) S = diff(psi, E) # Second Piola-Kirchhoff stress tensor PK = F * S # First Piola-Kirchoff stress tensor # Variational problem return derivative((inner(PK, grad(v)) - inner(B, v)) * dx, u, du)
def sigma_next(timestep, zeta, ep_dot, sigma, P): A = 1 + 0.25 * (timestep * params.e ** 2) / params.T B = timestep * 0.125 * (1 - params.e ** 2) / params.T rhs = (1 - (timestep * params.e ** 2) / (4 * params.T)) * sigma - timestep / params.T * ( 0.125 * (1 - params.e ** 2) * tr(sigma) * Identity(2) - 0.25 * P * Identity(2) + zeta * ep_dot) C = (rhs[0, 0] - rhs[1, 1]) / A D = (rhs[0, 0] + rhs[1, 1]) / (A + 2 * B) sigma00 = 0.5 * (C + D) sigma11 = 0.5 * (D - C) sigma01 = rhs[0, 1] sigma = as_matrix([[sigma00, sigma01], [sigma01, sigma11]]) return sigma
def __init__(self, mesh, conditions, timestepping, params, output, solver_params): super().__init__(mesh, conditions, timestepping, params, output, solver_params) self.w0 = Function(self.W3) self.w1 = Function(self.W3) u0, s0, h0, a0 = self.w0.split() p, q, r, m = TestFunctions(self.W3) self.initial_condition((u0, conditions.ic['u']), (s0, conditions.ic['s']), (a0, conditions.ic['a']), (h0, conditions.ic['h'])) self.w1.assign(self.w0) u1, s1, h1, a1 = split(self.w1) u0, s0, h0, a0 = split(self.w0) theta = conditions.theta uh = (1-theta) * u0 + theta * u1 sh = (1-theta) * s0 + theta * s1 hh = (1-theta) * h0 + theta * h1 ah = (1-theta) * a0 + theta * a1 ep_dot = self.strain(grad(uh)) zeta = self.zeta(hh, ah, self.delta(uh)) rheology = params.e ** 2 * sh + Identity(2) * 0.5 * ((1 - params.e ** 2) * tr(sh) + self.Ice_Strength(hh, ah)) eqn = self.momentum_equation(hh, u1, u0, p, sh, params.rho, uh, conditions.ocean_curr, params.rho_a, params.C_a, params.rho_w, params.C_w, conditions.geo_wind, params.cor, self.timestep, ind=self.ind) eqn += self.transport_equation(uh, hh, ah, h1, h0, a1, a0, r, m, self.n, self.timestep) eqn += inner(self.ind * (s1 - s0) + 0.5 * self.timestep * rheology / params.T, q) * dx eqn -= inner(q * zeta * self.timestep / params.T, ep_dot) * dx if conditions.stabilised['state']: alpha = conditions.stabilised['alpha'] eqn += self.stabilisation_term(alpha=alpha, zeta=avg(zeta), mesh=mesh, v=uh, test=p) bcs = DirichletBC(self.W3.sub(0), conditions.bc['u'], "on_boundary") uprob = NonlinearVariationalProblem(eqn, self.w1, bcs) self.usolver = NonlinearVariationalSolver(uprob, solver_parameters=solver_params.bt_params) self.u1, self.s0, self.h1, self.a1 = self.w1.split()
def __init__(self, mesh, conditions, timestepping, params, output, solver_params): super().__init__(mesh, conditions, timestepping, params, output, solver_params) self.w0 = Function(self.W2) self.w1 = Function(self.W2) u0, h0, a0 = self.w0.split() p, q, r = TestFunctions(self.W2) self.initial_condition((u0, conditions.ic['u']), (h0, conditions.ic['h']), (a0, conditions.ic['a'])) self.w1.assign(self.w0) u1, h1, a1 = split(self.w1) u0, h0, a0 = split(self.w0) theta = conditions.theta uh = (1-theta) * u0 + theta * u1 ah = (1-theta) * a0 + theta * a1 hh = (1-theta) * h0 + theta * h1 ep_dot = self.strain(grad(uh)) zeta = self.zeta(hh, ah, self.delta(uh)) eta = zeta * params.e ** (-2) sigma = 2 * eta * ep_dot + (zeta - eta) * tr(ep_dot) * Identity(2) - self.Ice_Strength(hh, ah) * 0.5 * Identity( 2) eqn = self.momentum_equation(hh, u1, u0, p, sigma, params.rho, uh, conditions.ocean_curr, params.rho_a, params.C_a, params.rho_w, params.C_w, conditions.geo_wind, params.cor, self.timestep) eqn += self.transport_equation(uh, hh, ah, h1, h0, a1, a0, q, r, self.n, self.timestep) if conditions.stabilised['state']: alpha = conditions.stabilised['alpha'] eqn += self.stabilisation_term(alpha=alpha, zeta=avg(zeta), mesh=mesh, v=uh, test=p) bcs = DirichletBC(self.W2.sub(0), conditions.bc['u'], "on_boundary") uprob = NonlinearVariationalProblem(eqn, self.w1, bcs) self.usolver = NonlinearVariationalSolver(uprob, solver_parameters=solver_params.bt_params) self.u1, self.h1, self.a1 = self.w1.split()
def sigma(v): return 2.0 * mu * epsilon(v) + lmbda * tr(epsilon(v)) * Identity(2)
def delta(self, u): return sqrt(self.params.Delta_min ** 2 + 2 * self.params.e ** (-2) * inner(dev(self.strain(grad(u))), dev(self.strain(grad(u)))) + tr( self.strain(grad(u))) ** 2)
def __init__(self, mesh, conditions, timestepping, params, output, solver_params): super().__init__(mesh, conditions, timestepping, params, output, solver_params) self.w0 = Function(self.W1) self.w1 = Function(self.W1) self.a = Function(self.U) self.h = Function(self.U) self.u0, self.s0 = self.w0.split() self.p, self.q = TestFunctions(self.W1) self.initial_condition((self.u0, conditions.ic['u']), (self.s0, conditions.ic['s']), (self.a, conditions.ic['a']), (self.h, conditions.ic['h'])) self.w1.assign(self.w0) u1, s1 = split(self.w1) u0, s0 = split(self.w0) theta = conditions.theta uh = (1-theta) * u0 + theta * u1 sh = (1-theta) * s0 + theta * s1 self.ep_dot = self.strain(grad(uh)) zeta = self.zeta(self.h, self.a, self.delta(uh)) self.rheology = params.e ** 2 * sh + Identity(2) * 0.5 * ((1 - params.e ** 2) * tr(sh) + self.Ice_Strength(self.h, self.a)) self.eqn = self.momentum_equation(self.h, u1, u0, self.p, sh, params.rho, uh, conditions.ocean_curr, params.rho_a, params.C_a, params.rho_w, params.C_w, conditions.geo_wind, params.cor, self.timestep, ind=self.ind) self.eqn += inner(self.ind * (s1 - s0) + 0.5 * self.timestep * self.rheology / params.T, self.q) * dx self.eqn -= inner(self.q * zeta * self.timestep / params.T, self.ep_dot) * dx if conditions.stabilised['state']: alpha = conditions.stabilised['alpha'] self.eqn += self.stabilisation_term(alpha=alpha, zeta=avg(zeta), mesh=mesh, v=uh, test=self.p) self.bcs = DirichletBC(self.W1.sub(0), conditions.bc['u'], "on_boundary")
def trace(A): r"""Compute the trace of a rank-2 tensor""" axes = get_mesh_axes(A.ufl_domain()) if axes in ["x", "xz"]: return A return firedrake.tr(A)