-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
aradermacher
committed
Mar 21, 2024
1 parent
005a345
commit 16c1ca4
Showing
2 changed files
with
169 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
from __future__ import annotations | ||
|
||
import numpy as np | ||
|
||
from fenics_constitutive import Constraint, IncrSmallStrainModel, strain_from_grad_u | ||
|
||
|
||
class SpringKelvinModel(IncrSmallStrainModel): | ||
''' viscoelastic model based on 1D Three Parameter Model with spring and Kelvin body in row | ||
|--- E_1: spring ---| | ||
--- E_0: spring modulus ---| | | ||
|--- tau: relaxation time ---| | ||
with deviatoric assumptions for 3D generalization (volumetric part of visco strain == 0 damper just working on deviatoric part) | ||
time integration: backward Euler | ||
''' | ||
def __init__(self, parameters: dict[str, float], constraint: Constraint): | ||
self._constraint = constraint | ||
self.E0 = parameters["E0"] | ||
self.E1 = parameters["E1"] | ||
self.tau = parameters["tau"] | ||
self.nu = parameters["nu"] | ||
self.mu0 = self.E0 / (2.0 * (1.0 + self.nu)) | ||
self.lam0 = self.E0 * self.nu / ((1.0 + self.nu) * (1.0 - 2.0 * self.nu)) | ||
self.mu1 = self.E1 / (2.0 * (1.0 + self.nu)) | ||
self.lam1 = self.E1 * self.nu / ((1.0 + self.nu) * (1.0 - 2.0 * self.nu)) | ||
|
||
match constraint: | ||
case Constraint.FULL: | ||
self.D = None | ||
|
||
case Constraint.PLANE_STRAIN: | ||
self.D = None | ||
|
||
case Constraint.PLANE_STRESS: | ||
self.D = None | ||
|
||
case Constraint.UNIAXIAL_STRESS: | ||
self.D_E0 = np.array([[self.E0]]) | ||
case _: | ||
msg = "Constraint not implemented" | ||
raise NotImplementedError(msg) | ||
|
||
def evaluate( | ||
self, | ||
del_t: float, | ||
grad_del_u: np.ndarray, | ||
mandel_stress: np.ndarray, | ||
tangent: np.ndarray, | ||
history: np.ndarray | dict[str, np.ndarray] | None, | ||
) -> None: | ||
assert ( | ||
grad_del_u.size // (self.geometric_dim**2) | ||
== mandel_stress.size // self.stress_strain_dim | ||
== tangent.size // (self.stress_strain_dim**2) | ||
) | ||
# n_gauss = grad_del_u.size // (self.geometric_dim**2) | ||
mandel_view = mandel_stress.reshape(-1, self.stress_strain_dim) | ||
strain_increment = strain_from_grad_u(grad_del_u, self.constraint).reshape(-1, self.stress_strain_dim) | ||
strain_visco_n = history['strain_visko'].reshape(-1, self.stress_strain_dim) | ||
|
||
# loop over gauss points | ||
for n, eps in enumerate(strain_increment): | ||
|
||
print('eps', eps) | ||
print('n', n) | ||
stress_n = mandel_view[n] | ||
strain_visco_n = strain_visco_n[n] | ||
|
||
# compute visko strain 1D case only !!! | ||
factor = (1 / del_t + 1 / self.tau + self.E_0 / (self.tau * self.E_1)) | ||
deps_visko = (stress_n / (self.tau * self.E_1) + self.E_0 / (self.tau * self.E_1) * eps - | ||
strain_visco_n / self.tau) / factor | ||
dstress = self.E_0 * (eps - deps_visko) | ||
D = self.D_E0 * (1 - self.E0**2/(self.E1*self.tau *factor)) | ||
|
||
print('D', D) | ||
|
||
# update values | ||
mandel_view[n] += dstress | ||
history['strain_visco'][n] += deps_visko | ||
history['strain'][n] += eps | ||
tangent[n] = D.flatten() | ||
|
||
|
||
@property | ||
def constraint(self) -> Constraint: | ||
return self._constraint | ||
|
||
@property | ||
def history_dim(self) -> None: | ||
return {'strain_visco': self.stress_strain_dim, 'strain': self.stress_strain_dim} | ||
|
||
def update(self) -> None: | ||
pass | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
from __future__ import annotations | ||
|
||
import dolfinx as df | ||
import numpy as np | ||
import pytest | ||
import ufl | ||
from dolfinx.nls.petsc import NewtonSolver | ||
from spring_kelvin_model import SpringKelvinModel | ||
from linear_elasticity.linear_elasticity_model import LinearElasticityModel | ||
from mpi4py import MPI | ||
|
||
from fenics_constitutive import Constraint, IncrSmallStrainProblem | ||
|
||
youngs_modulus = 42.0 | ||
poissons_ratio = 0.3 | ||
visco_modulus = 10.0 | ||
relaxation_time = 10.0 | ||
|
||
|
||
def test_creep_uniaxial_stress(): | ||
mesh = df.mesh.create_unit_interval(MPI.COMM_WORLD, 2) | ||
V = df.fem.FunctionSpace(mesh, ("CG", 1)) | ||
u = df.fem.Function(V) | ||
law = SpringKelvinModel( | ||
parameters={"E0": youngs_modulus, "E1": visco_modulus, "tau": relaxation_time, "nu": poissons_ratio}, | ||
constraint=Constraint.UNIAXIAL_STRESS, | ||
) | ||
# law = LinearElasticityModel( | ||
# parameters={"E": youngs_modulus, "nu": poissons_ratio}, | ||
# constraint=Constraint.UNIAXIAL_STRESS, | ||
# ) | ||
|
||
def left_boundary(x): | ||
return np.isclose(x[0], 0.0) | ||
|
||
def right_boundary(x): | ||
return np.isclose(x[0], 1.0) | ||
|
||
displacement = df.fem.Constant(mesh, 0.01) | ||
dofs_left = df.fem.locate_dofs_geometrical(V, left_boundary) | ||
dofs_right = df.fem.locate_dofs_geometrical(V, right_boundary) | ||
bc_left = df.fem.dirichletbc(df.fem.Constant(mesh, 0.0), dofs_left, V) | ||
bc_right = df.fem.dirichletbc(displacement, dofs_right, V) | ||
|
||
problem = IncrSmallStrainProblem( | ||
law, | ||
u, | ||
[bc_left, bc_right], | ||
) | ||
|
||
solver = NewtonSolver(MPI.COMM_WORLD, problem) | ||
n, converged = solver.solve(u) | ||
# assert abs(problem.stress_1.x.array[0] - youngs_modulus * 0.01) < 1e-10 / ( | ||
# youngs_modulus * 0.01 | ||
# ) | ||
# | ||
# problem.update() | ||
# assert abs(problem.stress_0.x.array[0] - youngs_modulus * 0.01) < 1e-10 / ( | ||
# youngs_modulus * 0.01 | ||
# ) | ||
# assert np.max(problem._u0.x.array) == displacement.value | ||
# | ||
# displacement.value = 0.02 | ||
# n, converged = solver.solve(u) | ||
# assert abs(problem.stress_1.x.array[0] - youngs_modulus * 0.02) < 1e-10 / ( | ||
# youngs_modulus * 0.02 | ||
# ) | ||
|
||
|
||
if __name__ == "__main__": | ||
test_creep_uniaxial_stress() |