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 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 Piola1(d_, w_, lambda_, mu_s, E_func=None): I = Identity(2) if callable(E_func): E = E_func(d_, w_) else: F = I + grad(d_["n"]) E = 0.5 * ((F.T * F) - I) return F * (lambda_ * tr(E) * I + 2 * mu_s * E)
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 _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 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 get_new_value(self, r: fenics.Function) -> fenics.Expression: return 2.0*self.lame_mu*fenics.sym(fenics.grad(r)) \ + self.lame_lambda*fenics.tr(fenics.sym(fenics.grad(r)))*fenics.Identity(len(r))
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
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)
v = fs.TestFunction(V) f = fs.Constant((0, 0, -rho * g)) T = fs.Constant((0, 0, 0)) a = fs.inner(sigma(u), epsilon(v)) * fs.dx L = fs.dot(f, v) * fs.dx + fs.dot(T, v) * fs.ds # Compute solution u = fs.Function(V) fs.solve(a == L, u, bc) # Plot solution plt.figure() fs.plot(u, title='Displacement', mode='displacement') # Plot stress s = sigma(u) - (1. / 3) * fs.tr(sigma(u)) * fs.Identity(d) # deviatoric stress von_Mises = fs.sqrt(3. / 2 * fs.inner(s, s)) V = fs.FunctionSpace(mesh, 'P', 1) von_Mises = fs.project(von_Mises, V) plt.figure() fs.plot(von_Mises, title='Stress intensity') # Compute magnitude of displacement u_magnitude = fs.sqrt(fs.dot(u, u)) u_magnitude = fs.project(u_magnitude, V) plt.figure() fs.plot(u_magnitude, title='Displacement magnitude') print('min/max u:', u_magnitude.vector().min(), u_magnitude.vector().max()) # Save solution to file in VTK format fs.File('results/displacement.pvd') << u
def tr(self, A): return FEN.tr(A)
def psi_minus_linear_elasticity_model_B(epsilon, lamda, mu): dim = 2 bulk_mod = lamda + 2. * mu / dim tr_epsilon_minus = ufl.Min(fe.tr(epsilon), 0) return bulk_mod / 2. * tr_epsilon_minus**2
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 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 sigma(u): return (lmbda * fn.tr(eps(u)) * fn.Identity(2) + 2 * mu * eps(u))
def half_exp_dyn(w0, dt=1.e-5, t_end=1.e-4, show_plots=False): u0 = w0.u p0 = w0.p v0 = w0.v bcs_u, bcs_p, bcs_v = load_2d_muscle_bc(V_u, V_pv.sub(0), V_pv.sub(1), boundaries) F = deformation_grad(u0) I_1, I_2, J = invariants(F) F_iso = isochronic_deformation_grad(F, J) #I_1_iso, I_2_iso = invariants(F_iso)[0:2] W = material_mooney_rivlin(I_1, I_2, c_10, c_01) g = incompr_constr(J) # Lagrange function (without constraint) L = -W P = first_piola_stress(L, F) G = incompr_stress(g, F) # a_dyn_u = inner(u1 - u0, eta) * dx - dt * inner(v1, eta) * dx u1 = fe.TrialFunction(V_u) eta = fe.TestFunction(V_u) #u11 = fe.Function(V_u) #F1 = deformation_grad(u11) #g1 = incompr_constr(fe.det(F1)) #G1 = incompr_stress(g1, F1) (p1, v1) = fe.TrialFunctions(V_pv) (q, xi) = fe.TestFunctions(V_pv) a_dyn_u = inner(u1 - u0, eta) * dx - dt * inner(v0, eta) * dx a_dyn_p = fe.tr(G * grad(v1)) * q * dx #a_dyn_v = rho*inner(v1-v0, xi)*dx + dt*(inner(P + p0*G, grad(xi))*dx - inner(B, xi)*dx) a_dyn_v = rho * inner(v1 - v0, xi) * dx + dt * (inner( P, grad(xi)) * dx + inner(p1 * G, grad(xi)) * dx - inner(B, xi) * dx) a_u = fe.lhs(a_dyn_u) l_u = fe.rhs(a_dyn_u) a_pv = fe.lhs(a_dyn_p + a_dyn_v) l_pv = fe.rhs(a_dyn_p + a_dyn_v) u1 = fe.Function(V_u) pv1 = fe.Function(V_pv) sol = [] vol = fe.assemble(1. * dx) A_u = fe.assemble(a_u) A_pv = fe.assemble(a_pv) for bc in bcs_u: bc.apply(A_u) t = 0 while t < t_end: print("progress: %f" % (100. * t / t_end)) # update displacement u L_u = fe.assemble(l_u) fe.solve(A_u, u1.vector(), L_u) u0.assign(u1) L_pv = fe.assemble(l_pv) for bc in bcs_p + bcs_v: bc.apply(A_pv, L_pv) fe.solve(A_pv, pv1.vector(), L_pv) if fe.norm(pv1.vector()) > 1e8: print('ERROR: norm explosion') break # update initial values for next step w0.u = u1 w0.pv = pv1 p0.assign(w0.p) v0.assign(w0.v) t += dt if show_plots: # plot result fe.plot(w0.sub(0), mode='displacement') plt.show() # save solutions sol.append(Solution(t=t)) sol[-1].upv.assign(w0) return sol, W
def I1(C): return fe.tr(C)
def stress(self, u): E = kin.green_lagrange_strain(u) I = kin.identity(u) return self._parameters['lambda'] * fe.tr( E) * I + 2 * self._parameters['mu'] * E
uViewer << u # Maximum and minimum displacement u_magnitude = fe.sqrt(fe.dot(u, u)) u_magnitude = fe.project(u_magnitude, W) print('Min/Max displacement:', u_magnitude.vector().array().min(), u_magnitude.vector().array().max()) # Computation of the large deformation strains #cprint("Computing the deformation tensor and saving to file...", 'green') epsilon_u = largeKinematics(u) epsilon_u_project = fe.project(epsilon_u, Z) epsilonViewer = fe.File('paraview/strain.pvd') epsilonViewer << epsilon_u_project # Computation of the stresses #cprint("Stress derivation and saving to file...", 'green') S = fe.diff(psi, E) S_project = fe.project(S, Z) sigmaViewer = fe.File('paraview/stress.pvd') sigmaViewer << S_project # Computation of an equivalent stress s = S - (1. / 3) * fe.tr(S) * fe.Identity(u.geometric_dimension()) von_Mises = fe.sqrt(3. / 2 * fe.inner(s, s)) von_Mises_project = fe.project(von_Mises, W) misesViewer = fe.File('paraview/mises.pvd') misesViewer << von_Mises_project print("Maximum equivalent stress:", von_Mises_project.vector().array().max())
def sigma(r): return 2.0 * mu * fnc.sym(fnc.grad(r)) + lmbda * fnc.tr( fnc.sym(fnc.grad(r))) * fnc.Identity(len(r))
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 # Mooney-Rivlin parameters (in kPa) b_1 = 2.756e-5 d_1 = 43.373 p_max = 73.0
def psi_linear_elasticity(epsilon, lamda, mu): return lamda / 2 * fe.tr(epsilon)**2 + mu * fe.inner(epsilon, epsilon)