def inverse_map_function_ufl(x, control_points, impact_radii, map_type): if len(control_points) == 0: return x x = fe.variable(x) df, rho = distance_function_segments_ufl(x, control_points, impact_radii) grad_x = fe.diff(df, x) delta_x = fe.conditional( fe.gt(df, rho), fe.Constant((0., 0.)), grad_x * (rho * inverse_ratio_function_ufl(df / rho, map_type) - df)) return delta_x + x
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 solve_steady_state_heiser_weissinger(kappa): w = fe.Function(V_up) (u, p) = fe.split(w) p = fe.variable(p) (eta, q) = fe.TestFunctions(V_up) dw = fe.TrialFunction(V_up) kappa = fe.Constant(kappa) bcs_u, bcs_p, bcs_v = load_2d_muscle_bc(V_up.sub(0), V_up.sub(1), None, boundaries) F = deformation_grad(u) I_1, I_2, J = invariants(F) F_iso = isochronic_deformation_grad(F, J) I_1_iso, I_2_iso = invariants(F)[0:2] W = material_mooney_rivlin(I_1_iso, I_2_iso, c_10, c_01) #+ incompr_relaxation(p, kappa) g = incompr_constr(J) # Lagrange function (without constraint) L = -W # Modified Lagrange function (with constraints) L_mod = L - p * g P = first_piola_stress(L, F) G = incompr_stress(g, F) # = J*fe.inv(F.T) Lp = const_eq(L_mod, p) a_static = weak_div_term(P + p * G, eta) + inner(B, eta) * dx + inner(Lp, q) * dx J_static = fe.derivative(a_static, w, dw) ffc_options = {"optimize": True} problem = fe.NonlinearVariationalProblem( a_static, w, bcs_u + bcs_p, J=J_static, form_compiler_parameters=ffc_options) solver = fe.NonlinearVariationalSolver(problem) solver.solve() return w
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 map_function_ufl(x_hat, control_points, impact_radii, map_type, boundary_info=None): if len(control_points) == 0: return x_hat x_hat = fe.variable(x_hat) df, rho = distance_function_segments_ufl(x_hat, control_points, impact_radii) grad_x_hat = fe.diff(df, x_hat) delta_x_hat = fe.conditional( fe.gt(df, rho), fe.Constant((0., 0.)), grad_x_hat * (rho * ratio_function_ufl(df / rho, map_type) - df)) if boundary_info is None: return delta_x_hat + x_hat else: last_control_point = control_points[-1] points, directions, rho_default = boundary_info mid_point, mid_point1, mid_point2 = points direct_vec, rotated_vec = directions aux_control_point1 = last_control_point + rho_default * rotated_vec aux_control_point2 = last_control_point - rho_default * rotated_vec w1 = np.linalg.norm(mid_point1 - aux_control_point1) w2 = np.linalg.norm(mid_point2 - aux_control_point2) w0 = np.linalg.norm(mid_point - last_control_point) assert np.absolute(2 * w0 - w1 - w2) < 1e-5 AB = mid_point - last_control_point AP = x_hat - last_control_point x1 = AB[0] y1 = AB[1] x2 = AP[0] y2 = AP[1] mod = fe.sqrt(x1**2 + y1**2) df_to_direct = (x1 * y2 - y1 * x2) / mod # AB x AP df_to_rotated = (x1 * x2 + y1 * y2) / mod k1 = rho_default * (w1 + w2) / (rho_default * (w1 + w2) + df_to_direct * (w1 - w2)) new_df_to_direct = rho_default * ratio_function_ufl( df_to_direct / rho_default, map_type) k2 = rho_default * (w1 + w2) / (rho_default * (w1 + w2) + new_df_to_direct * (w1 - w2)) new_df_to_rotated = df_to_rotated * k1 / k2 x = fe.as_vector(last_control_point + direct_vec * new_df_to_rotated + rotated_vec * new_df_to_direct) return fe.conditional( fe.gt(df_to_rotated, 0), fe.conditional(fe.gt(np.absolute(df_to_direct), rho), x_hat, x), delta_x_hat + x_hat)
def first_PK_stress_minus(F, psi_minus): F = fe.variable(F) energy_minus = psi_minus(F) P_minus = fe.diff(energy_minus, F) return P_minus
def g_d_prime(d, degrad_func): d = fe.variable(d) degrad = degrad_func(d) degrad_prime = fe.diff(degrad, d) return degrad_prime
def stress(self, u): u_var = fe.variable(u) C = fe.variable(kin.right_cauchy_green(u_var)) return 2 * fe.diff(self.strain_energy(u_var), C)
def deformation_grad(u): I = fe.Identity(dim) return fe.variable(I + grad(u))
def first_PK_stress(F, psi): F = fe.variable(F) energy = psi(F) P = fe.diff(energy, F) return P
integrals_V.append(fe.dot(fLoad, u) * dxp(i)) ########################## VARIATIONAL FORMULATION ########################### # Large displacements kinematics def largeKinematics(u): d = u.geometric_dimension() I = fe.Identity(d) Fgrad = I + fe.grad(u) C = Fgrad.T * Fgrad E = 0.5 * (C - I) return E E = largeKinematics(u) E = fe.variable(E) # Stored strain energy density for a generic model def strainDensityFunction(E, Ey, nu): mu = Ey / (2. * (1 + nu)) lambda_ = Ey * nu / ((1 + nu) * (1 - 2 * nu)) return lambda_ / 2. * (fe.tr(E))**2. + mu * fe.tr(E * E) # Collect the strain density functions integrals_E = [] for i in materials: psi = strainDensityFunction(E, materials[i][0], materials[i][1]) integrals_E.append(psi * dxp(i))
def cauchy_stress(epsilon, psi): epsilon = fe.variable(epsilon) energy = psi(epsilon) sigma = fe.diff(energy, epsilon) return sigma
# Define acting force 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
def cauchy_stress_minus(epsilon, psi_minus): epsilon = fe.variable(epsilon) energy_minus = psi_minus(epsilon) sigma_minus = fe.diff(energy_minus, epsilon) return sigma_minus