def SecondPiolaStress(self, F, p=None, deviatoric=False): import dolfin from pulse import kinematics material = self.material I = kinematics.SecondOrderIdentity(F) f0 = material.f0 f0f0 = dolfin.outer(f0, f0) I1 = dolfin.variable(material.active.I1(F)) I4f = dolfin.variable(material.active.I4(F)) Fe = material.active.Fe(F) Fa = material.active.Fa Ce = Fe.T * Fe # fe = Fe*f0 # fefe = dolfin.outer(fe, fe) # Elastic volume ratio J = dolfin.variable(dolfin.det(Fe)) # Active volume ration Ja = dolfin.det(Fa) dim = self.geometry.dim() Ce_bar = pow(J, -2.0 / float(dim)) * Ce w1 = material.W_1(I1, diff=1, dim=dim) w4f = material.W_4(I4f, diff=1) # Total Stress S_bar = Ja * (2 * w1 * I + 2 * w4f * f0f0) * dolfin.inv(Fa).T if material.is_isochoric: # Deviatoric Dev_S_bar = S_bar - (1.0 / 3.0) * dolfin.inner( S_bar, Ce_bar) * dolfin.inv(Ce_bar) S_mat = J**(-2.0 / 3.0) * Dev_S_bar else: S_mat = S_bar # Volumetric if p is None or deviatoric: S_vol = dolfin.zero((dim, dim)) else: psi_vol = material.compressibility(p, J) S_vol = J * dolfin.diff(psi_vol, J) * dolfin.inv(Ce) # Active stress wactive = material.active.Wactive(F, diff=1) eta = material.active.eta S_active = wactive * (f0f0 + eta * (I - f0f0)) S = S_mat + S_vol + S_active return S
def FirstPiolaStress(self, F, p=None, *args, **kwargs): F = dolfin.variable(F) # First Piola Kirchoff psi_iso = self.strain_energy(F) P = dolfin.diff(psi_iso, F) if p is not None: J = dolfin.variable(kinematics.Jacobian(F)) psi_vol = self.compressibility(p, J) # PiolaTransform P_vol = J * dolfin.diff(psi_vol, J) * dolfin.inv(F).T P += P_vol return P
def Cauchy1(self): #Joy added this u = self.parameters["displacement_variable"] d = u.geometric_dimension() I = Identity(d) F = I + grad(u) f0 = self.parameters["fiber"] s0 = self.parameters["sheet"] n0 = self.parameters["sheet-normal"] Cff=self.parameters["StrainEnergyDensityFunction_Cff"] Css=self.parameters["StrainEnergyDensityFunction_Css"] Cnn=self.parameters["StrainEnergyDensityFunction_Cnn"] Cns=self.parameters["StrainEnergyDensityFunction_Cns"] Cfs=self.parameters["StrainEnergyDensityFunction_Cfs"] Cfn=self.parameters["StrainEnergyDensityFunction_Cfn"] #Kappa = self.parameters["Kappa"] #isincomp = self.parameters["incompressible"] p = self.parameters["pressure_variable"] Cstrain=self.parameters["StrainEnergyDensityFunction_Coef"] F = dolfin.variable(F) J = det(F) Ea = 0.5*(as_tensor(F[k,i]*F[k,j] - I[i,j], (i,j))) Eff = f0[i]*Ea[i,j]*f0[j] Ess = s0[i]*Ea[i,j]*s0[j] Enn = n0[i]*Ea[i,j]*n0[j] Efs = f0[i]*Ea[i,j]*s0[j] Efn = f0[i]*Ea[i,j]*n0[j] Ens = n0[i]*Ea[i,j]*s0[j] #QQ = bff*pow(Eff,2.0) + bfx*(pow(Ess,2.0)+ pow(Enn,2.0)+ 2.0*pow(Ens,2.0)) + bxx*(2.0*pow(Efs,2.0) + 2.0*pow(Efn,2.0)) QQ = Cff*Eff**2.0 + Css*Ess**2.0 + Cnn*Enn**2.0 + Cns**Ens**2.0 + Cfs**Efs**2.0 + Cfn*Efn**2.0 Wp = Cstrain*(exp(QQ) - 1.0) - p*(J - 1.0) #E = dolfin.variable(Ea) sigma = (1.0/J)*dolfin.diff(Wp,F)*F.T return sigma
def initialize_with_field(self, u): super().initialize_with_field(u) d = self.deformation_measures.d F = self.deformation_measures.F J = self.deformation_measures.J I1 = self.deformation_measures.I1 # I2 = self.deformation_measures.I2 # I3 = self.deformation_measures.I3 for m in self.material_parameters: E = m.get('E', None) nu = m.get('nu', None) mu = m.get('mu', None) lm = m.get('lm', None) if mu is None: if E is None or nu is None: raise RuntimeError( 'Material model requires parameter "mu"; ' 'otherwise, require parameters "E" and "nu".') mu = E / (2 * (1 + nu)) if lm is None: if E is None or nu is None: raise RuntimeError( 'Material model requires parameter "lm"; ' 'otherwise, require parameters "E" and "nu".') lm = E * nu / ((1 + nu) * (1 - 2 * nu)) psi = (mu / 2) * (I1 - d - 2 * ln(J)) + (lm / 2) * ln(J)**2 pk1 = diff(psi, F) pk2 = dot(inv(F), pk1) self.psi.append(psi) self.pk1.append(pk1) self.pk2.append(pk2)
I = dolfin.Identity(d) F = dolfin.variable(I + dolfin.grad(u)) C = F.T * F J = dolfin.det(F) I1 = dolfin.tr(C) # Lame material parameters lm = E * nu / ((1.0 + nu) * (1.0 - 2.0 * nu)) mu = E / (2.0 + 2.0 * nu) # Energy density of a Neo-Hookean material model psi = (mu / 2.0) * (I1 - d - 2.0 * dolfin.ln(J)) + (lm / 2.0) * dolfin.ln(J)**2 # First Piola-Kirchhoff pk1 = dolfin.diff(psi, F) # Boundary traction N = dolfin.FacetNormal(mesh) PN = dolfin.dot(pk1, N) # Potential energy Pi = psi * dx # NOTE: There is no external force potential # Equilibrium problem F = dolfin.derivative(Pi, u) ### Model cost and constraints # Observed displacement u_obs = u # NOTE: Generally a vector-valued sub-function
def test_potentials(scheme, N, dim, th): model, DS, bcs = prepare_model_and_bcs(scheme, N, dim, th) prm = model.parameters["sigma"] prm.add("12", 2.0) if N == 3: prm.add("13", 2.0) prm.add("23", 2.0) #info(model.parameters, True) # Prepare arguments for obtaining multi-well potential phi = DS.primitive_vars_ctl(indexed=True)["phi"] phi0 = DS.primitive_vars_ptl(indexed=True)["phi"] phi_te = DS.test_functions()["phi"] dw = DoublewellFactory.create(model.parameters["doublewell"]) S, A, iA = model.build_stension_matrices() # Define piece of form containing derivative of the multiwell potential dF dF_list = [] # -- there are at least 3 alternative ways how to do that: # 1st -- automatic differentiation via diff _phi = variable(phi) F_auto = multiwell(dw, _phi, S) dF_auto = diff(F_auto, _phi) dF_list.append(inner(dot(iA, dF_auto), phi_te)*dx) # 2nd -- manual specification of dF dF_man = multiwell_derivative(dw, phi, phi0, S, semi_implicit=True) dF_list.append(inner(dot(iA, dF_man), phi_te)*dx) # 3rd -- automatic differentiation via derivative F = multiwell(dw, phi, S)*dx # will be used below dF_list.append(derivative(F, phi, tuple(dot(iA.T, phi_te)))) # UFL ISSUE: # The above tuple is needed as long as `ListTensor` type is not # explicitly treated in `ufl/formoperators.py:211`, # cf. `ufl/formoperators.py:168` # FIXME: check if this is a bug and report it del F_auto, dF_auto, dF_man for dF in dF_list: # Check that the size of the domain is 1 mesh = DS.function_spaces()[0].mesh() assert near(assemble(Constant(1.0)*dx(domain=mesh)), 1.0) # Assemble inner(\vec{1}, phi_)*dx (for later check of the derivative) phi_ = DS.test_functions()["phi"] # FIXME: 'FullyDecoupled' DS requires "assembly by parts" b1 = assemble(inner(as_vector(len(phi_)*[Constant(1.0),]), phi_)*dx) if N == 2: # Check that F(0.2) == 0.0512 [== F*dx] assert near(assemble(F), 0.0512, 1e-10) # Check the derivative # --- scale b1 by dFd1(0.2) == 0.096 as_backend_type(b1).vec().scale(0.096) # --- assemble "inner(dFd1, phi_)*dx" b2 = assemble(dF) # --- check that both vectors nearly coincides b2.axpy(-1.0, b1) assert b2.norm("l2") < 1e-10 if N == 3: # Check that F(0.2, 0.2) == 0.1088 [== F*dx] assert near(assemble(F), 0.1088, 1e-10) # Check the derivative # --- scale b1 by dFdj(0.2, 0.2) == 0.048 [j = 1,2] as_backend_type(b1).vec().scale(0.048) # --- assemble "inner(dFdj, phi_)*dx" b2 = assemble(dF) # --- check that both vectors nearly coincides b2.axpy(-1.0, b1) assert b2.norm("l2") < 1e-10
def u(t, x, y): return 0.5 * (t**2 + 1) * sin(2 * x * pi) * sin(2 * y * pi) # Declare also a numpy version of the solution (handy for plotting and evaluation) def u_numpy(t, x, y): return 0.5 * (t**2+1) * \ np.sin(2*x*pi) * np.sin(2*y*pi) def u_T_numpy(x, y): return u_numpy(T[1], x, y) # Define right-hand side u_x = u(t_, x, y_) by_x = by(t_, x, y_) f = diff(u_x, t_) + c * u_x + inner(bx, grad(u_x)) + \ by_x * diff(u_x, y_) + inner(ax, grad(grad(u_x))) # We have to use at least quadratic polynomials here Vx = FunctionSpace(mx, 'CG', 2) Vy = FunctionSpace(my, 'CG', 1) phi = TrialFunction(Vx) psi = TestFunction(Vx) v = Function(Vx) gamma = 1.0 # Jump penalty term stab1 = 2.