def update_map(self): d_clipped = fe.conditional(fe.gt(self.d_new, 0.5), self.d_new, 0.) d_int_full = fe.assemble(self.d_new * fe.det(self.grad_gamma) * fe.dx) d_int = fe.assemble(d_clipped * fe.det(self.grad_gamma) * fe.dx) print("d_int_clipped {}".format(float(d_int))) print("d_int_full {}".format(float(d_int_full))) update_flag = False if d_int - self.d_integrals[-1] > self.d_integral_interval: update_flag = True if update_flag and not self.finish_flag: print('\n') print( '=================================================================================' ) print('>> Updating map...') print( '=================================================================================' ) new_tip_point = self.identify_crack_tip() if self.inside_domain(new_tip_point): if len(self.control_points) > 1: v1 = self.control_points[-1] - self.control_points[-2] v2 = new_tip_point - self.control_points[-1] v1 = v1 / np.linalg.norm(v1) v2 = v2 / np.linalg.norm(v2) print("new_tip_point is {}".format(new_tip_point)) print("v1 is {}".format(v1)) print("v2 is {}".format(v2)) print("control points are \n{}".format( self.control_points)) print("impact_radii are {}".format(self.impact_radii)) assert np.dot( v1, v2 ) > np.sqrt(2) / 2, "Crack propogration angle not good" self.compute_impact_radii(new_tip_point) self.interpolate_H() self.d_integrals.append(d_int) print( '=================================================================================' ) else: self.finish_flag = True self.update_weak_form = True else: print("Do not modify map") print("d_integrals {}".format(self.d_integrals))
def psi_minus_linear_elasticity_model_C(epsilon, lamda, mu): sqrt_delta = fe.conditional( fe.gt(fe.tr(epsilon)**2 - 4 * fe.det(epsilon), 0), fe.sqrt(fe.tr(epsilon)**2 - 4 * fe.det(epsilon)), 0) eigen_value_1 = (fe.tr(epsilon) + sqrt_delta) / 2 eigen_value_2 = (fe.tr(epsilon) - sqrt_delta) / 2 tr_epsilon_minus = fe.conditional(fe.lt(fe.tr(epsilon), 0.), fe.tr(epsilon), 0.) eigen_value_1_minus = fe.conditional(fe.lt(eigen_value_1, 0.), eigen_value_1, 0.) eigen_value_2_minus = fe.conditional(fe.lt(eigen_value_2, 0.), eigen_value_2, 0.) return lamda / 2 * tr_epsilon_minus**2 + mu * (eigen_value_1_minus**2 + eigen_value_2_minus**2)
def psi_aux_Borden(F, mu, kappa): J = fe.det(F) C = F.T * F Jinv = J**(-2 / 3) U = 0.5 * kappa * (0.5 * (J**2 - 1) - fe.ln(J)) Wbar = 0.5 * mu * (Jinv * (fe.tr(C) + 1) - 3) return U, Wbar
def _construct_eigenproblem(self, u: ufl.Argument, v: ufl.Argument) \ -> Tuple[ufl.algebra.Operator, ufl.algebra.Operator]: """Construct left- and right-hand sides of eigenvalue problem. Parameters ---------- u : ufl.Argument A function belonging to the function space under consideration. v : ufl.Argument A function belonging to the function space under consideration. Returns ------- a : ufl.algebra.Operator Left hand side form. b : ufl.algebra.Operator Right hand side form. """ g = self.metric_tensor sqrt_g = fenics.sqrt(fenics.det(g)) inv_g = fenics.inv(g) # $a(u, v) = \int_M \nabla u \cdot g^{-1} \nabla v \, \sqrt{\det(g)} \, d x$. a = fenics.dot(fenics.grad(u), inv_g * fenics.grad(v)) * sqrt_g # $b(u, v) = \int_M u \, v \, \sqrt{\det(g)} \, d x$. b = fenics.dot(u, v) * sqrt_g return a, b
def energy_norm(self, u): psi_plus = self.psi_plus(strain(self.mfem_grad(u))) psi_minus = self.psi_minus(strain(self.mfem_grad(u))) return np.sqrt( float( fe.assemble((g_d(self.d_exact) * psi_plus + psi_minus) * fe.det(self.grad_gamma) * fe.dx)))
def __setup_a_priori(self): """Sets up the attributes and petsc solver for the a priori quality check. Returns ------- None """ options = [[['ksp_type', 'preonly'], ['pc_type', 'jacobi'], ['pc_jacobi_type', 'diagonal'], ['ksp_rtol', 1e-16], ['ksp_atol', 1e-20], ['ksp_max_it', 1000]]] self.ksp_prior = PETSc.KSP().create() _setup_petsc_options([self.ksp_prior], options) self.transformation_container = fenics.Function( self.form_handler.deformation_space) dim = self.mesh.geometric_dimension() if not self.volume_change > 1: raise ConfigError('MeshQuality', 'volume_change', 'This parameter has to be larger than 1.') self.a_prior = self.trial_dg0 * self.test_dg0 * self.dx self.L_prior = fenics.det( fenics.Identity(dim) + fenics.grad(self.transformation_container) ) * self.test_dg0 * self.dx
def invariants(F): C = F.T * F # Invariants I_1 = tr(C) + (3 - dim) I_2 = 0.5 * ((tr(C) + (3 - dim))**2 - (tr(C * C) + (3 - dim))) J = det(F) # this is a third invariant 'I_3' return I_1, I_2, J
def Kinematics(u): # Kinematics d = u.geometric_dimension() I = fe.Identity(d) # Identity tensor F = I + fe.grad(u) # Deformation gradient F = fe.variable(F) # To differentiate Psi(F) J = fe.det(F) # Jacobian of F C = F.T*F # Right Cauchy-Green deformation tensor Ic = fe.tr(C) # Trace of C return [F, J, C, Ic]
def build_weak_form_staggered(self): self.x_hat = fe.variable(fe.SpatialCoordinate(self.mesh)) self.x = fe.variable( map_function_ufl(self.x_hat, self.control_points, self.impact_radii, self.map_type, self.boundary_info)) self.grad_gamma = fe.diff(self.x, self.x_hat) def mfem_grad_wrapper(grad): def mfem_grad(u): return fe.dot(grad(u), fe.inv(self.grad_gamma)) return mfem_grad self.mfem_grad = mfem_grad_wrapper(fe.grad) self.psi_plus = partial(self.psi_plus_linear_elasticity, lamda=self.lamda, mu=self.mu) self.psi_minus = partial(self.psi_minus_linear_elasticity, lamda=self.lamda, mu=self.mu) self.psi = partial(psi_linear_elasticity, lamda=self.lamda, mu=self.mu) sigma_plus = cauchy_stress_plus(strain(self.mfem_grad(self.x_new)), self.psi_plus) sigma_minus = cauchy_stress_minus(strain(self.mfem_grad(self.x_new)), self.psi_minus) self.u_exact, self.d_exact = self.compute_analytical_solutions_fully_broken( self.x) self.G_u = (g_d(self.d_exact) * fe.inner(sigma_plus, strain(self.mfem_grad(self.eta))) \ + fe.inner(sigma_minus, strain(self.mfem_grad(self.eta)))) * fe.det(self.grad_gamma) * fe.dx self.G_d = (self.d_new - self.d_exact) * self.zeta * fe.det( self.grad_gamma) * fe.dx self.u_initial = self.nonzero_initial_guess(self.x) self.x_new.assign(fe.project(self.u_initial, self.U))
def build_weak_form_staggered(self): self.x_hat = fe.variable(fe.SpatialCoordinate(self.mesh)) self.x = map_function_ufl(self.x_hat, self.control_points, self.impact_radii, self.map_type, self.boundary_info) self.grad_gamma = fe.diff(self.x, self.x_hat) def mfem_grad_wrapper(grad): def mfem_grad(u): return fe.dot(grad(u), fe.inv(self.grad_gamma)) return mfem_grad self.mfem_grad = mfem_grad_wrapper(fe.grad) # A special note (Tianju): We hope to use Model C, but Newton solver fails without the initial guess by Model A if self.i < 2: self.psi_plus = partial(psi_plus_linear_elasticity_model_A, lamda=self.lamda, mu=self.mu) self.psi_minus = partial(psi_minus_linear_elasticity_model_A, lamda=self.lamda, mu=self.mu) else: self.psi_plus = partial(psi_plus_linear_elasticity_model_C, lamda=self.lamda, mu=self.mu) self.psi_minus = partial(psi_minus_linear_elasticity_model_C, lamda=self.lamda, mu=self.mu) print("use model C") self.psi = partial(psi_linear_elasticity, lamda=self.lamda, mu=self.mu) self.sigma_plus = cauchy_stress_plus( strain(self.mfem_grad(self.x_new)), self.psi_plus) self.sigma_minus = cauchy_stress_minus( strain(self.mfem_grad(self.x_new)), self.psi_minus) # self.sigma = cauchy_stress_plus(strain(self.mfem_grad(self.x_new)), self.psi) # self.sigma_degraded = g_d(self.d_new) * self.sigma_plus + self.sigma_minus self.G_u = (g_d(self.d_new) * fe.inner(self.sigma_plus, strain(self.mfem_grad(self.eta))) \ + fe.inner(self.sigma_minus, strain(self.mfem_grad(self.eta)))) * fe.det(self.grad_gamma) * fe.dx if self.solution_scheme == 'explicit': self.G_d = (self.H_old * self.zeta * g_d_prime(self.d_new, g_d) \ + self.G_c / self.l0 * (self.zeta * self.d_new + self.l0**2 * fe.inner(self.mfem_grad(self.zeta), self.mfem_grad(self.d_new)))) * fe.det(self.grad_gamma) * fe.dx else: self.G_d = (history(self.H_old, self.psi_plus(strain(self.mfem_grad(self.x_new))), self.psi_cr) * self.zeta * g_d_prime(self.d_new, g_d) \ + self.G_c / self.l0 * (self.zeta * self.d_new + self.l0**2 * fe.inner(self.mfem_grad(self.zeta), self.mfem_grad(self.d_new)))) * fe.det(self.grad_gamma) * fe.dx
def _solve(self, z, x=None): # problem variables du = TrialFunction(self.V) # incremental displacement v = TestFunction(self.V) # test function u = Function(self.V) # displacement from previous iteration # kinematics ii = Identity(3) # identity tensor dimension 3 f = ii + grad(u) # deformation gradient c = f.T * f # right Cauchy-Green tensor # invariants of deformation tensors ic = tr(c) j = det(f) # elasticity parameters if type(z) in [list, np.ndarray]: param = self.param_remapper(z[0]) if self.param_remapper is not None else z[0] else: param = self.param_remapper(z) if self.param_remapper is not None else z e_var = variable(Constant(param)) # Young's modulus nu = Constant(.3) # Shear modulus (Lamè's second parameter) mu, lmbda = e_var / (2 * (1 + nu)), e_var * nu / ((1 + nu) * (1 - 2 * nu)) # strain energy density, total potential energy psi = (mu / 2) * (ic - 3) - mu * ln(j) + (lmbda / 2) * (ln(j)) ** 2 pi = psi * dx - self.time * dot(self.f, u) * self.ds(3) ff = derivative(pi, u, v) # compute first variation of pi jj = derivative(ff, u, du) # compute jacobian of f # solving if x is not None: numeric_evals = np.zeros(shape=(x.shape[1], len(self.times))) evals = np.zeros(shape=(x.shape[1], len(self.eval_times))) else: numeric_evals = None evals = None for it, t in enumerate(self.times): self.time.t = t self.solver(ff == 0, u, self.bcs, J=jj, bcs=self.bcs, solver_parameters=self.solver_parameters) if x is not None: numeric_evals[:, it] = np.log(np.array([-u(x_)[2] for x_ in x.T]).T) # time-interpolation if x is not None: for i in range(evals.shape[0]): evals[i, :] = np.interp(self.eval_times, self.times, numeric_evals[i, :]) return (evals, u) if x is not None else u
def _energy_density(self, u): young_mod = 100 poisson_ratio = 0.3 shear_mod = young_mod / (2 * (1 + poisson_ratio)) bulk_mod = young_mod / (3 * (1 - 2 * poisson_ratio)) d = u.geometric_dimension() F = self.DeformationGradient(u) F = fa.variable(F) J = fa.det(F) I1 = fa.tr(self.RightCauchyGreen(F)) # Plane strain assumption Jinv = J**(-2 / 3) energy = ((shear_mod / 2) * (Jinv * (I1 + 1) - 3) + (bulk_mod / 2) * (J - 1)**2) return energy
def obj(x): p = fe.Constant(x) x_coo = fe.SpatialCoordinate(self.mesh) control_points = list(self.control_points) control_points.append(p) pseudo_radii = np.zeros(len(control_points)) distance_field, _ = distance_function_segments_ufl( x_coo, control_points, pseudo_radii) d_artificial = fe.exp(-distance_field / self.l0) d_clipped = fe.conditional(fe.gt(self.d_new, 0.5), self.d_new, 0.) L_tape = fe.assemble((d_clipped - d_artificial)**2 * fe.det(self.grad_gamma) * fe.dx) # L_tape = fe.assemble((self.d_new - d_artificial)**2 * fe.det(self.grad_gamma) * fe.dx) L = float(L_tape) return L
def __init__(self, mesh: fe.Mesh, constitutive_model: ConstitutiveModelBase, u_order=1, p_order=0): # TODO a lot here... element_v = fe.VectorElement("P", mesh.ufl_cell(), u_order) element_s = fe.FiniteElement("DG", mesh.ufl_cell(), p_order) # mixed_element = fe.MixedElement([element_v, element_v, element_s]) mixed_element = fe.MixedElement([element_v, element_s]) self.W = fe.FunctionSpace(mesh, mixed_element) self.V, self.Q = self.W.split() self.w = fe.Function(self.W) self.u, self.p = fe.split(self.w) w0 = fe.Function(self.W) self.u0, self.p0 = fe.split(w0) self.ut, self.pt = fe.TestFunctions(self.W) self.F = kin.def_grad(self.u) self.F0 = kin.def_grad(self.u0) S_iso = constitutive_model.iso_stress(self.u) mod_p = constitutive_model.p(self.u) J = fe.det(self.F) F_inv = fe.inv(self.F) if mod_p is None: mod_p = J**2 - 1. else: mod_p -= self.p S = S_iso + J * self.p * F_inv * F_inv.T self.d_LHS = fe.inner(fe.grad(self.ut), self.F * S) * fe.dx \ + fe.inner(mod_p, self.pt) * fe.dx # + fe.inner(mod_p, fe.tr(fe.nabla_grad(self.ut)*fe.inv(self.F))) * fe.dx self.d_RHS = (fe.inner(fe.Constant((0., 0., 0.)), self.ut) * fe.dx)
def evaluate_errors(self): print("Evaluate L2 errors...") print("Model {}, map {}, refinement {}".format(self.model_flag), self.map_type, self.local_refinement_iteration) u_error_l2 = np.sqrt( float( fe.assemble( fe.inner(self.x_new - self.u_exact, self.x_new - self.u_exact) * fe.det(self.grad_gamma) * fe.dx))) u_error_semi_h1 = np.sqrt(float(fe.assemble(fe.inner(self.mfem_grad(self.x_new - self.u_exact), \ self.mfem_grad(self.x_new - self.u_exact)) * fe.det(self.grad_gamma) * fe.dx))) # d_error_l2 = np.sqrt(float(fe.assemble((self.d_new - self.d_exact)**2 * fe.det(self.grad_gamma) * fe.dx))) print("Displacement error l2 is {}".format(u_error_l2)) print("Displacement error semi h1 is {}".format(u_error_semi_h1)) # print("Damage error is {}".format(d_error_l2)) self.u_energy_error = self.energy_norm(self.x_new - self.u_exact) print("Displacement error energy_norm is {}".format( self.u_energy_error))
element=element_3) # Body force per unit volume t_bar = fe.Constant((0.0, 0.0, 0.0)) # Traction force on the boundary # Define test and trial functions w = fe.Function(V) # most recently computed solution (u, p) = fe.split(w) (v, q) = fe.TestFunctions(V) dw = fe.TrialFunction(V) # Kinematics d = u.geometric_dimension() I = fe.Identity(d) # Identity tensor F = fe.variable(I + grad(u)) # Deformation gradient C = fe.variable(F.T * F) # Right Cauchy-Green tensor J = fe.det(F) DE = lambda v: 0.5 * (F.T * grad(v) + grad(v).T * F) a_0 = fe.as_vector([[1.0], [0.], [0.]]) A_00 = dot(a_0, a_0.T) # Invariants I_1 = tr(C) I_2 = 0.5 * (tr(C)**2 - tr(C * C)) I_4 = dot(a_0.T, C * a_0) # parameters taken from O. Roehrle and Heidlauf # Mooney-Rivlin parameters (in Pa)
def psi_minus_Borden(F, mu, kappa): J = fe.det(F) U, Wbar = psi_aux_Borden(F, mu, kappa) return fe.conditional(fe.lt(J, 1), U, 0)
def psi_Borden(F, mu, kappa): J = fe.det(F) U, Wbar = psi_aux_Borden(F, mu, kappa) return U + Wbar
def I3(C): return fe.det(C)
def psi_Miehe(F, mu, beta): J = fe.det(F) C = F.T * F W = mu / 2 * (fe.tr(C) + 1 - 3) + mu / beta * (J**(-beta) - 1) return W
w0 = Solution() w0.up = w w0.t = 0 dt = 2.e-5 sol, W = half_exp_dyn(w0, dt=dt, t_end=500 * dt, show_plots=False) # dif = explicit_relax_dyn(w0, kappa=1e4, dt=dt, t_end=1000*dt, show_plots=False) (u0, p0, v0) = fe.split(w0) T = 0.5 * rho * inner(v0, v0) plot_form(sol, w0, W * dx) plot_form(sol, w0, T * dx) plot_form(sol, w0, (T + W) * dx) plot_form(sol, w0, (det(deformation_grad(u0))) * dx) save_to_vtk(sol) """ # def solve_dynamics(): u0 = w.split(deepcopy=True)[0] # p = w.sub(1, deepcopy=True) v0 = fe.Function(V_v) (p1, v1) = fe.TrialFunctions(V_pv) (q, xi) = fe.TestFunctions(V_pv) bcs_u, bcs_p, bcs_v = load_2d_muscle_bc(V_u, V_pv.sub(0), V_pv.sub(1), boundaries)
def compute_static_deformation(self): assert self.mesh is not None # now we define subdomains on the mesh bottom = fe.CompiledSubDomain('near(x[2], 0) && on_boundary') top = fe.CompiledSubDomain('near(x[2], 1) && on_boundary') # middle = fe.CompiledSubDomain('x[2] > 0.3 && x[2] < 0.7') # Initialize mesh function for interior domains self.domains = fe.MeshFunction('size_t', self.mesh, 3) self.domains.set_all(0) # middle.mark(self.domains, 1) # Initialize mesh function for boundary domains self.boundaries = fe.MeshFunction('size_t', self.mesh, 2) self.boundaries.set_all(0) bottom.mark(self.boundaries, 1) top.mark(self.boundaries, 2) # Define new measures associated with the interior domains and # exterior boundaries self.dx = fe.Measure('dx', domain=self.mesh, subdomain_data=self.domains) self.ds = fe.Measure('ds', domain=self.mesh, subdomain_data=self.boundaries) # define function spaces V = fe.VectorFunctionSpace(self.mesh, "Lagrange", 1) # now we define subdomains on the mesh bottom = fe.CompiledSubDomain('near(x[2], 0) && on_boundary') top = fe.CompiledSubDomain('near(x[2], 1) && on_boundary') # middle = fe.CompiledSubDomain('x[2] > 0.3 && x[2] < 0.7') d = self.mesh.geometry().dim() # Initialize mesh function for interior domains self.domains = fe.MeshFunction('size_t', self.mesh, d) self.domains.set_all(0) # middle.mark(self.domains, 1) # Initialize mesh function for boundary domains self.boundaries = fe.MeshFunction('size_t', self.mesh, d - 1) self.boundaries.set_all(0) bottom.mark(self.boundaries, 1) top.mark(self.boundaries, 2) # Define new measures associated with the interior domains and # exterior boundaries self.dx = fe.Measure('dx', domain=self.mesh, subdomain_data=self.domains) self.ds = fe.Measure('ds', domain=self.mesh, subdomain_data=self.boundaries) c_zero = fe.Constant((0, 0, 0)) # define boundary conditions bc_bottom = fe.DirichletBC(V, c_zero, bottom) bc_top = fe.DirichletBC(V, c_zero, top) bcs = [bc_bottom] # , bc_top] # define functions du = TrialFunction(V) v = TestFunction(V) u = Function(V) B = fe.Constant((0., 2.0, 0.)) T = fe.Constant((0.0, 0.0, 0.0)) d = u.geometric_dimension() I = fe.Identity(d) F = I + grad(u) C = F.T * F I_1 = tr(C) J = det(F) E, mu = 10., 0.3 mu, lmbda = fe.Constant(E / (2 * (1 + mu))), fe.Constant( E * mu / ((1 + mu) * (1 - 2 * mu))) # stored energy (comp. neo-hookean model) psi = (mu / 2.) * (I_1 - 3) - mu * fe.ln(J) + (lmbda / 2.) * (fe.ln(J))**2 dx = self.dx ds = self.ds Pi = psi * fe.dx - dot(B, u) * fe.dx - dot(T, u) * fe.ds F = fe.derivative(Pi, u, v) J = fe.derivative(F, u, du) fe.solve(F == 0, u, bcs, J=J) # save results self.u = u # write to disk output = fe.File("/tmp/static.pvd") output << u
def J_(U): return det(F_(U))
b = fe.Constant((0.0, 0.0, 0.0)) # Body force per unit volume t_bar = fe.Constant((0.0, 0.0, 0.0)) # Traction force on the boundary # Define test and trial functions w = fe.Function(V) # most recently computed solution (u, p) = fe.split(w) (v, q) = fe.TestFunctions(V) dw = fe.TrialFunction(V) # Kinematics d = u.geometric_dimension() I = fe.Identity(d) # Identity tensor F = fe.variable(I + grad(u)) # Deformation gradient C = fe.variable(F.T * F) # Right Cauchy-Green tensor J = fe.det(C) DE = lambda v: 0.5 * (F.T * grad(v) + grad(v).T * F) a_0 = fe.as_vector([[1.0], [0.], [0.]]) # Invariants I_1 = tr(C) I_2 = 0.5 * (tr(C)**2 - tr(C * C)) I_4 = dot(a_0.T, C * a_0) # Continuation parameter lmbda = 0.01 # parameters taken from O. Roehrle and Heidlauf
def iso_def_grad(u): F = def_grad(u) F /= fe.det(F)**(1. / 3.) return F