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 calculate_darcy_flow(self): # equation 5a du = self.mech_velocity p = self.pressure rho = Constant(self.parameters['rho']) phi = [Constant(phi) for phi in self.parameters['phi']] F = df.variable(kinematics.DeformationGradient(self.displacement)) J = kinematics.Jacobian(F) dx = self.geometry.dx N = self.parameters['N'] # Calculate endo to epi permeability gradient w = [TrialFunction(self.vector_space) for i in range(N)] v = [TestFunction(self.vector_space) for i in range(N)] a = [(1 / phi[i]) * df.inner(F * J * df.inv(F) * w[i], v[i]) * dx for i in range(N)] # a = [phi[i]*df.inner((w[i]-du), v[i])*dx for i in range(N)] # porous dynamics if self.parameters['mechanics']: A = [-J * self.K[i] * df.inv(F.T) for i in range(N)] else: A = [self.K[i] for i in range(N)] L = [-df.dot(A[i] * df.grad(p[i]), v[i]) * dx for i in range(N)] [ df.solve(a[i] == L[i], self.darcy_flow[i], [], solver_parameters={ "linear_solver": "cg", "preconditioner": "sor" }) for i in range(N) ]
def _init_forms(self): logger.debug("Initialize forms mechanics problem") # Displacement and hydrostatic_pressure u, p = dolfin.split(self.state) v, q = dolfin.split(self.state_test) # Some mechanical quantities F = dolfin.variable(kinematics.DeformationGradient(u)) J = kinematics.Jacobian(F) dx = self.geometry.dx internal_energy = (self.material.strain_energy(F, ) + self.material.compressibility(p, J)) self._virtual_work = dolfin.derivative( internal_energy * dx, self.state, self.state_test, ) external_work = self._external_work(u, v) if external_work is not None: self._virtual_work += external_work self._set_dirichlet_bc() self._jacobian = dolfin.derivative( self._virtual_work, self.state, dolfin.TrialFunction(self.state_space), ) self._init_solver()
def _init_forms(self): u = self.state v = self.state_test F = dolfin.variable(DeformationGradient(u)) J = Jacobian(F) dx = self.geometry.dx # Add penalty term internal_energy = self.material.strain_energy(F) \ + self.kappa * (J * dolfin.ln(J) - J + 1) self._virtual_work \ = dolfin.derivative(internal_energy * dx, self.state, self.state_test) self._virtual_work += self._external_work(u, v) self._jacobian \ = dolfin.derivative(self._virtual_work, self.state, dolfin.TrialFunction(self.state_space)) self._set_dirichlet_bc()
def _init_forms(self): u, p, pinn = dolfin.split(self.state) v, q, qinn = dolfin.split(self.state_test) F = dolfin.variable(DeformationGradient(u)) J = Jacobian(F) ds = self.geometry.ds dsendo = ds(self.geometry.markers['ENDO']) dx = self.geometry.dx endoarea = dolfin.assemble(dolfin.Constant(1.0) * dsendo) internal_energy = self.material.strain_energy(F) * dx \ + self.material.compressibility(p, J) * dx \ + (pinn * (self._V0/endoarea - self._Vu)) * dsendo self._virtual_work \ = dolfin.derivative(internal_energy, self.state, self.state_test) self._virtual_work += self._external_work(u, v) self._jacobian \ = dolfin.derivative(self._virtual_work, self.state, dolfin.TrialFunction(self.state_space)) self._set_dirichlet_bc()
def _external_work(self, u, v): F = dolfin.variable(kinematics.DeformationGradient(u)) N = self.geometry.facet_normal ds = self.geometry.ds dx = self.geometry.dx external_work = [] for neumann in self.bcs.neumann: n = neumann.traction * ufl.cofac(F) * N external_work.append(dolfin.inner(v, n) * ds(neumann.marker)) for robin in self.bcs.robin: external_work.append( dolfin.inner(robin.value * u, v) * ds(robin.marker)) for body_force in self.bcs.body_force: external_work.append( -dolfin.derivative(dolfin.inner(body_force, u) * dx, u, v), ) if len(external_work) > 0: return list_sum(external_work) return None
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 CauchyStress(self, F, p=None, deviatoric=False): F = dolfin.variable(F) # First Piola Kirchoff if deviatoric: p = None P = self.FirstPiolaStress(F, p) # Cauchy stress T = kinematics.InversePiolaTransform(P, F) return T
def __init__(self, u): '''Deformation measures.''' self.d = d = len(u) self.I = I = Identity(d) self.F = F = variable(I + grad(u)) self.C = C = F.T * F self.E = 0.5 * (C - I) self.J = det(F) self.I1 = tr(C) self.I2 = 0.5 * (tr(C)**2 - tr(C * C)) self.I3 = det(C)
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 _init_forms(self): p, u, r = dolfin.split(self.state) q, v, w = dolfin.split(self.state_test) F = dolfin.variable(DeformationGradient(u)) J = Jacobian(F) dx = self.geometry.dx # Add penalty term internal_energy = self.material.strain_energy( F, ) + self.material.compressibility(p, J) self._virtual_work = dolfin.derivative( internal_energy * dx, self.state, self.state_test, ) self._virtual_work += dolfin.derivative( rigid_motion_term( mesh=self.geometry.mesh, u=u, r=r, ), self.state, self.state_test, ) self._jacobian = dolfin.derivative( self._virtual_work, self.state, dolfin.TrialFunction(self.state_space), ) self._init_solver()
def main(traction, outfile='displacement.json'): # Create the Beam geometry # Length L = 10 # Width W = 1 print('Got traction of {} kN'.format(traction)) # Create mesh mesh = dolfin.BoxMesh(dolfin.Point(0, 0, 0), dolfin.Point(L, W, W), 30, 3, 3) # Mark boundary subdomians left = dolfin.CompiledSubDomain("near(x[0], side) && on_boundary", side=0) bottom = dolfin.CompiledSubDomain("near(x[2], side) && on_boundary", side=0) boundary_markers = dolfin.MeshFunction("size_t", mesh, mesh.topology().dim() - 1) boundary_markers.set_all(0) left_marker = 1 bottom_marker = 2 left.mark(boundary_markers, left_marker) bottom.mark(boundary_markers, bottom_marker) f = dolfin.File('boundary_markers.pvd') f << boundary_markers P2 = dolfin.VectorElement("Lagrange", mesh.ufl_cell(), 2) P1 = dolfin.FiniteElement("Lagrange", mesh.ufl_cell(), 1) state_space = dolfin.FunctionSpace(mesh, P2 * P1) state = dolfin.Function(state_space) state_test = dolfin.TestFunction(state_space) u, p = dolfin.split(state) v, q = dolfin.split(state_test) # Some mechanical quantities I = dolfin.Identity(3) gradu = dolfin.grad(u) F = dolfin.variable(I + gradu) J = dolfin.det(F) # Material properites mu = dolfin.Constant(100.0) lmbda = dolfin.Constant(1.0) epsilon = 0.5 * (gradu + gradu.T) # Strain energy W = lmbda / 2 * (dolfin.tr(epsilon)**2) \ + mu * dolfin.tr(epsilon * epsilon) internal_energy = W - p * (J - 1) # Neumann BC N = dolfin.FacetNormal(mesh) p_bottom = dolfin.Constant(traction) external_work = dolfin.inner(v, p_bottom * dolfin.cofac(F) * N) \ * dolfin.ds(bottom_marker, subdomain_data=boundary_markers) # Virtual work G = dolfin.derivative(internal_energy * dolfin.dx, state, state_test) + external_work # Anchor the left side bcs = dolfin.DirichletBC(state_space.sub(0), dolfin.Constant((0.0, 0.0, 0.0)), left) # Traction at the bottom of the beam dolfin.solve(G == 0, state, [bcs]) # Get displacement and hydrostatic pressure u, p = state.split(deepcopy=True) point = np.array([10.0, 0.5, 1.0]) disp = np.zeros(3) u.eval(disp, point) print(('Get z-position of point ({}): {:.4f} mm' '').format(', '.join(['{:.1f}'.format(p) for p in point]), point[2] + disp[2])) with open(outfile, 'w') as f: json.dump({ 'point': point.tolist(), 'displacement': disp.tolist() }, f, indent=4) print('Output saved to {}'.format(outfile)) V = dolfin.VectorFunctionSpace(mesh, "CG", 1) u_int = dolfin.interpolate(u, V) moved_mesh = dolfin.Mesh(mesh) dolfin.ALE.move(mesh, u_int) f = dolfin.File('mesh.pvd') f << mesh f = dolfin.File('bending_beam.pvd') f << moved_mesh
def _init_form(self): m = TrialFunction(self.state_space) m_n = self.state_previous v = self.state_test u = self.displacement du = self.mech_velocity p = self.pressure N = self.parameters['N'] # Get parameters rho = Constant(self.parameters['rho']) beta = [Constant(beta) for beta in self.parameters['beta']] if isinstance(self.parameters['K'], float): K = [self.parameters['K']] else: K = self.parameters['K'] if self.geometry.f0 is not None: self.K = [self.permeability_tensor(k) for k in K] else: self.K = [Constant(k) for k in K] dt = self.parameters['dt'] / self.parameters['steps'] self.qi = self.inflow_rate(self.parameters['qi']) self.qo = self.inflow_rate(self.parameters['qo']) k = Constant(1 / dt) theta = self.parameters['theta'] # Crank-Nicolson time scheme M = Constant(theta) * m + Constant(1 - theta) * m_n # Mechanics from ufl import grad as ufl_grad dx = self.geometry.dx d = self.state.geometric_dimension() I = Identity(d) F = df.variable(kinematics.DeformationGradient(u)) J = kinematics.Jacobian(F) if N == 1: self._form = k * (m - m_n) * v * dx else: self._form = sum( [k * (m[i] - m_n[i]) * v[i] * dx for i in range(N)]) # porous dynamics if self.parameters['mechanics']: F = df.variable(kinematics.DeformationGradient(u)) J = kinematics.Jacobian(F) A = [J * df.inv(F) * K * df.inv(F.T) for K in self.K] else: A = [Constant(1.0) * K for K in self.K] if N == 1: self._form += -rho * df.div(A[0] * df.grad(p[0])) * v * dx else: self._form += -rho * sum( [df.div(A[i] * df.grad(p[i])) * v[i] * dx for i in range(N)]) # compartment coupling if N > 1: # forward self._form -= sum([ -J * beta[i] * (p[i] - p[i + 1]) * v[i] * dx for i in range(N - 1) ]) # backward self._form -= sum([ -J * beta[i - 1] * (p[i] - p[i - 1]) * v[i] * dx for i in range(1, N) ]) # add mechanics if self.parameters['mechanics']: if N == 1: self._form -= df.dot(df.grad(M), du) * v * dx else: self._form -= sum( [df.dot(df.grad(M[i]), du) * v[i] * dx for i in range(N)]) # Add inflow/outflow terms if N == 1: self._form -= rho * self.qi * v * dx + rho * self.qo * v * dx else: self._form -= rho * self.qi * v[0] * dx + rho * self.qo * v[-1] * dx
bcs.append(DirichletBC(Vx, zero, boundary_markers, id_subdomain_fix)) bcs.append(DirichletBC(Vx, uxD_msr, boundary_markers, id_subdomain_msr)) bcs.append(DirichletBC(V, zeros, fixed_vertex_000, "pointwise")) bcs.append(DirichletBC(Vz, zero, fixed_vertex_010, "pointwise")) ### Define hyperelastic material model material_parameters = {'E': Constant(1.0), 'nu': Constant(0.0)} E, nu = material_parameters.values() d = len(u) # Displacement dimension 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)
else: raise ValueError('Parameter `force_domain`') ### Material model E = Constant(1000.0) # Young's modulus nu = Constant(0.3) # Poisson's ratio # Lame material parameters lm = E * nu / ((1.0 + nu) * (1.0 - 2.0 * nu)) mu = E / (2.0 + 2.0 * nu) if large_deformations: I = dolfin.Identity(len(u)) F = dolfin.variable(I + dolfin.grad(u)) # Deformation gradient C = F.T * F # Right Cauchy-Green deformation tensor I1 = dolfin.tr(C) det_F = dolfin.det(F) # Strain energy density of a Neo-Hookean material psi = (mu / 2.0) * (I1 - len(u) - 2.0 * dolfin.ln(det_F)) + ( lm / 2.0) * dolfin.ln(det_F)**2 # First Piola-Kirchhoff stress tensor pk1 = dolfin.diff(psi, F) else: I = dolfin.Identity(len(u))
def calculate_pressure(self, displacement, solid_pressure): pspace = self.pprob.pressure_space F = df.variable(pulse.kinematics.DeformationGradient(displacement)) return df.project(-self.SecondPiolaStress(F, p=solid_pressure)[0, 0], pspace)
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