Hello,
I am trying to solve a 3D elasticity problem with an additional field for eigenstrains. Geometry is hemisphere with tetrahedral meshing. I have checked the code for syntax: no errors, tuning/relaxing the tolerance parameters and also varied other solver parameters.
When I monitor convergence, the norm either does not decrease or in very rare cases decreases very very slowly. Although the weak form is mathematically correct, I believe there is some problem with the conditioning of stiffness (or global tangent) matrix of the mixed system. I am not sure how to approach this issue.
A MWE is given here: (most of the code is packed in functions)
from copy import deepcopy
from statistics import mode
from numpy import infty, iinfo, int32, argwhere, min, max
from dolfin import *
def sphere_geometry(db_mesh_folder, mesh_file):
#R, mesh_size = geo_parameters
mymesh = Mesh()
#db_mesh_folder = "/Users/dhariwal/Library/CloudStorage/OneDrive-VirginiaTech/Zirconia/Particle_SIMULATION/Code/single_variant/meshes/"
#mesh_file = "mesh3D_R_" + str(int(self.R)) + "_size_" + str(int(mesh_size)) + ".xdmf"
with XDMFFile(db_mesh_folder + mesh_file) as infile:
infile.read(mymesh)
print("Domain created, meshing done")
print("Radius = ", R)
print("mesh_size = ", mesh_size)
print("Number of cells = ", mymesh.num_cells())
print("Number of vertices = ", mymesh.num_vertices())
# Characteristic size of the elements of the mesh
hMESH = CellDiameter(mymesh)
meshSIZE = 0.5*(mymesh.hmax() + mymesh.hmin())
print("meshSIZE = ", meshSIZE)
return mymesh, hMESH, meshSIZE
x1, y1, z1 = geo_parameters[0]
nx, ny, nz = geo_parameters[1]
corner1 = Point(0.0, 0.0, 0.0)
corner2 = Point(x1, y1, z1)
mymesh = BoxMesh(corner1, corner2, nx, ny, nz)
print("Number of cells = ", mymesh.num_cells())
print("Number of vertices = ", mymesh.num_vertices())
return mymesh
def cuboid_geometry(geo_parameters):
x1, y1, z1 = geo_parameters[0]
nx, ny, nz = geo_parameters[1]
corner1 = Point(0.0, 0.0, 0.0)
corner2 = Point(x1, y1, z1)
mymesh = BoxMesh(corner1, corner2, nx, ny, nz)
print("Number of cells = ", mymesh.num_cells())
print("Number of vertices = ", mymesh.num_vertices())
# Characteristic size of the elements of the mesh
hMESH = CellDiameter(mymesh)
meshSIZE = 0.5*(mymesh.hmax() + mymesh.hmin())
return mymesh, hMESH, meshSIZE
def func_spaces(mesh, basis):
if basis == 'linear':
shape_func = 1
else:
shape_func = 2
# basis for 'vector' displacement
P1 = VectorElement("Lagrange", mesh.ufl_cell(), shape_func)
# basis for 'scalar' monovariant phase field
P2 = FiniteElement("Lagrange", mesh.ufl_cell(), shape_func)
W1 = FunctionSpace(mesh, P1)
W2 = FunctionSpace(mesh, P2)
from db_variant import Variant
shape_strains_list = Variant.CuAlNi()
shape_strains_list = as_tensor(shape_strains_list[0])
num_variants = 1
# single variant
element = MixedElement([P1, P2])
# create the space of solutions over the domain
W = FunctionSpace(mesh, element)
# a generic function from W
w = Function(W)
dw = TrialFunction(W)
wx = TestFunction(W)
print("Total D.O.F. = ", W.dim())
return W, W1, W2, w, dw, wx, num_variants, shape_strains_list
if basis == 'linear':
shape_func = 1
else:
shape_func = 2
# basis for 'vector' displacement
P1 = VectorElement("Lagrange", mesh.ufl_cell(), shape_func)
W = FunctionSpace(mesh, P1)
w = Function(W) # a generic function from W
dw = TrialFunction(W)
v = TestFunction(W) # test function for variational problem
num_variants = 0
print("This is a pure elastic problem.\n No. of variants = ", num_variants)
print("Total D.O.F. = ", W.dim())
return W, w, dw, v, P1
# Spatial coordinates of mesh
x = SpatialCoordinate(mesh)
# Definition of tolerance
tol = DOLFIN_EPS # FEniCS tolerance - necessary for "boundary_markers" and the correct definition of the boundaries
#class Bottom(SubDomain):
# def inside(self, x, on_boundary):
# return near(x[2], 0.0)
#bottom = Bottom()
bT = CompiledSubDomain('near(x[2], R, tol) && on_boundary', R = R, tol = tol)
bP = CompiledSubDomain('sqrt(x[0]*x[0] + x[1]*x[1]) < meshSIZE \
&& near(x[2], R, tol) \
&& on_boundary', meshSIZE = meshSIZE, R=R, tol = tol)
# Definition of contact zones
bC = CompiledSubDomain('on_boundary && x[2] < compression + tol', R = R, tol=tol, compression = compression) # Contact search - contact part of the boundary
boundaries = MeshFunction("size_t", mesh, mesh.topology().dim()-1)
boundaries.set_all(0)
print("Markers for all boundary facets are set")
bT.mark(boundaries, 2) # bottom
bP.mark(boundaries, 4) # lateral_penalty
bC.mark(boundaries, 6) # contact_zone
print(boundaries.array()[boundaries.array() > 0])
cells = MeshFunction("size_t", mesh, mesh.topology().dim())
cells.set_all(1)
print("Marker for all internal cells is set to 1")
bc1 = DirichletBC(W.sub(2), Constant((-compression)), boundaries, 2)
bc2 = DirichletBC(W.sub(0), Constant((0)), boundaries, 4)
bc3 = DirichletBC(W.sub(1), Constant((0)), boundaries, 4)
bcs = [bc1,bc2,bc3]
dx = Measure('dx', subdomain_data=cells)
ds = Measure('ds', subdomain_data=boundaries)
return dx, ds, boundaries, bcs
lower_bound = Function(W)
upper_bound = Function(W)
#W00 = W.sub(0).collapse()
#W11 = W.sub(1).collapse()
#ninfty, pinfty = Function(W00), Function(W00)
#_lower, c_upper = Function(W11), Function(W11)
if u_min is None:
lower_bound.sub(0).vector()[:] = - infty
lower_bound.sub(1).vector()[:] = - infty
lower_bound.sub(2).vector()[:] = - infty
upper_bound.sub(0).vector()[:] = infty
upper_bound.sub(1).vector()[:] = infty
upper_bound.sub(2).vector()[:] = infty
#lower_bound.vector()[:] = -infty
#upper_bound.vector()[:] = infty
else:
lower_bound.vector()[:] = u_min
upper_bound.vector()[:] = u_max
#fa = FunctionAssigner(W, [W00, W11])
#fa.assign(lower_bound, [ninfty, c_lower])
#fa.assign(upper_bound, [pinfty, c_upper])
return lower_bound, upper_bound
# Form compiler options
parameters["form_compiler"]["optimize"] = True
parameters["form_compiler"]["cpp_optimize"] = True
from db_compliance import Compliance
compliance_phase1, compliance_phase2 = Compliance.CuAlNi()
Compliance_tetragonal = as_tensor(compliance_phase1)
#Compliance_monoclinic = as_tensor(compliance_phase2)
# Definition of normal vectors to the elastic body and to the rigid half-space
nRIGID = Constant((0.0, 0.0, 1.0))
n = FacetNormal(mesh)
# matrix-to-vector transform
def strain3voigt(e):
return as_vector(
[e[0, 0],
e[1, 1],
e[2, 2],
e[1, 2] * 2,
e[0, 2] * 2,
e[0, 1] * 2]
)
# vector-to-matrix transform
def voigt3stress(s):
return as_tensor(
[[s[0], s[5], s[4]],
[s[5], s[1], s[3]],
[s[4], s[3], s[2]]]
)
def epsilon(u, strain=None):
if strain is None:
e = 0.5 * (grad(u) + grad(u).T)
return e
elif strain=='lagrangian':
I = Identity(3)
Fgrad = I + grad(u)
C = Fgrad.T * Fgrad
E = 0.5*(C - I)
return E
elif strain=='hencky_order_22':
I = Identity(3)
Fgrad = I + grad(u)
C = Fgrad.T * Fgrad
a = C*C - I
b = (C*C) + 4*C + I
H = 1.5 * a * inv(b)
return H
def Vstrain(w):
return strain3voigt(epsilon(w))
def Vsigma(w):
return dot(Compliance_tetragonal, Vstrain(w))
def sigma(w):
return voigt3stress(Vsigma(w))
def gap(w): # Definition of gap function
x = SpatialCoordinate(mesh)
return x[2]+w[2]
def maculay(x): # Definition of Maculay bracket
return (x+abs(x))/2
def pN(w):
return dot(dot(nRIGID,sigma(w)),nRIGID)
def convert_to_integer(a):
"Convert to a 32-bit int. Raise exception if this will cause an overflow"
if abs(a) <= iinfo(int32).max:
return int32(a)
else:
raise OverflowError("Cannot safely convert to a 32-bit int.")
def elastic(w):
elastic_energy = 0.5 * inner(sigma(w), epsilon(w))
return elastic_energy
# The displacement u must be such that the current configuration x+u
# remains in the box [xmin = -inf,xmax = inf] x [ymin = 0,ymax = inf]
# constraint_u = Expression(("xmax - x[0]","ymax - x[1]","zmax - x[2]"),
# xmax=infty, ymax=infty, zmax=infty, degree=1)
# constraint_l = Expression(("xmin - x[0]","ymin - x[1]","zmin - x[2]"),
# xmin=-infty, ymin=-infty, zmin=0.0, degree=1)
# umin = interpolate(constraint_l, W)
# umax = interpolate(constraint_u, W)
#w_converged = Function(W)
time_end = 1.0
t_curr = 0.0
t_curr = t_curr + time_step
d_step = compression * t_curr
# Define the solver parameters
while t_curr <= time_end:
dx, ds, boundaries, bcs = pureElastic_sphere_boundaries(mesh, meshSIZE, R, d_step, W)
print("Current displacement at boundary = ", d_step, " nm")#, " and i_count = ", i_count)
#w = w_converged
# Stored strain energy density (linear elasticity model)
psi = elastic(w)
# Total potential energy
Pi = psi*dx + (0.5 * penalty * (E/hMESH) * inner(maculay(-gap(w)), maculay(-gap(w)))) * ds(6)
# Compute first variation of Pi (directional derivative about u in the direction of v)
F = derivative(Pi, w, v)
# Compute Jacobian of F for iterative "newton_solver"
J = derivative(F, w, dw)
problem = NonlinearVariationalProblem(F, w, bcs, J=J)
umin, umax = PureElastic_func_space_bounds(W)
problem.set_bounds(umin, umax)
solver = NonlinearVariationalSolver(problem)
snes_solver_parameters = {"nonlinear_solver": "snes",
"snes_solver": {"linear_solver": "lu",# "preconditioner": "ilu",
"maximum_iterations": 100,
"absolute_tolerance": 1E-9,
"relative_tolerance": 1E-9,
"report": False,
"method":'vinewtonrsls',
"error_on_nonconvergence": True}}
# ,"krylov_solver": {"divergence_limit": 1e10}
solver.parameters.update(snes_solver_parameters)
# Solve the nonlinear problem
(iter, converged) = solver.solve()
t_curr = t_curr + time_step
d_step = compression * t_curr
if not converged:
t_curr = t_curr - time_step
time_step = time_step/2.0
continue
# WT = TensorFunctionSpace(mesh, "Lagrange", degree=0)
# # strain field
# EPS = Function(WT, name="Strain")
# EPS.assign(project(epsilon(w), WT))
# # stress field
# SIGMA = Function(WT, name="Strain")
# SIGMA.assign(project(sigma(w), WT))
return w, boundaries
def func_space_bounds(W, u_min=None, u_max=None, c_min=None, c_max=None):
lower_bound = Function(W)
upper_bound = Function(W)
S = [W.sub(i).collapse() for i in range(num_variants + 1)]
ninfty, pinfty = Function(S[0]), Function(S[0])
c_lower = [Function(S[i+1]) for i in range(num_variants)]
c_upper = [Function(S[i+1]) for i in range(num_variants)]
if u_min is None:
ninfty.vector()[:] = - 50
pinfty.vector()[:] = 50
if c_min is None:
for i in range(num_variants):
c_lower[i].vector()[:] = - 0.1
c_upper[i].vector()[:] = 1
else:
ninfty.vector()[:] = u_min
pinfty.vector()[:] = u_max
for i in range(num_variants):
c_lower[i].vector()[:] = c_min
c_upper[i].vector()[:] = c_max
fa = FunctionAssigner(W, S)
lb = [ninfty]
ub = [pinfty]
for i in c_lower: lb.append(i)
for i in c_upper: ub.append(i)
fa.assign(lower_bound, lb)
fa.assign(upper_bound, ub)
print(lower_bound.vector()[:], upper_bound.vector()[:])
return lower_bound, upper_bound
def sphere_boundaries(mesh, meshSIZE, R, compression, W):
# Spatial coordinates of mesh
x = SpatialCoordinate(mesh)
# Definition of tolerance
tol = DOLFIN_EPS # FEniCS tolerance - necessary for "boundary_markers" and the correct definition of the boundaries
bT = CompiledSubDomain('near(x[2], R, tol) && on_boundary', R = R, tol = tol)
bP = CompiledSubDomain('sqrt(x[0]*x[0] + x[1]*x[1]) < meshSIZE \
&& near(x[2], R, tol) \
&& on_boundary', meshSIZE = meshSIZE, R=R, tol = tol)
# Definition of contact zones
bC = CompiledSubDomain('on_boundary && x[2] < compression + tol', R = R, tol=tol, compression = compression) # Contact search - contact part of the boundary
boundaries = MeshFunction("size_t", mesh, mesh.topology().dim()-1)
boundaries.set_all(0)
bT.mark(boundaries, 2) # bottom
bP.mark(boundaries, 4) # lateral_penalty
bC.mark(boundaries, 6) # contact_zone
#print(boundaries.array()[boundaries.array() == 2])
print(boundaries.array()[boundaries.array() == 4])
print(boundaries.array()[boundaries.array() == 6])
cells = MeshFunction("size_t", mesh, mesh.topology().dim())
cells.set_all(1)
bc1 = DirichletBC(W.sub(0).sub(2), Constant((-compression)), boundaries, 2)
bc2 = DirichletBC(W.sub(0).sub(0), Constant((0)), boundaries, 4)
bc3 = DirichletBC(W.sub(0).sub(1), Constant((0)), boundaries, 4)
bc4 = DirichletBC(W.sub(1), Constant((0)), boundaries, 4)
# for more than one variants
#bc5 = DirichletBC(W.sub(2), Constant((0)), boundaries, 4)
#bc6 = DirichletBC(W.sub(3), Constant((0)), boundaries, 4)
#bc7 = DirichletBC(W.sub(4), Constant((0)), boundaries, 4)
#bc8 = DirichletBC(W.sub(5), Constant((0)), boundaries, 4)
#bc9 = DirichletBC(W.sub(6), Constant((0)), boundaries, 4)
# bcs = [bc1,bc2,bc3]
# bcs = [bc1,bc2,bc3, bc4, bc5, bc6, bc7, bc8, bc9]
bcs = [bc1,bc2,bc3, bc4] #, bc5, bc6, bc7, bc8, bc9]
dx = Measure('dx', subdomain_data=cells)
ds = Measure('ds', subdomain_data=boundaries)
return dx, ds, boundaries, bcs
def cuboid_boundaries(mesh, compression, W):
x = SpatialCoordinate(mesh)
tol = DOLFIN_EPS
bLEFT = CompiledSubDomain("near(x[0], 0.0, tol) && on_boundary", tol = tol)
bRIGHT = CompiledSubDomain("near(x[0], 200.0, tol) && on_boundary", tol = tol)
boundaries = MeshFunction("size_t", mesh, mesh.topology().dim()-1)
boundaries.set_all(0)
print("Markers for all boundary facets are set")
bLEFT.mark(boundaries, 2) # left
bRIGHT.mark(boundaries, 4) # right
#print(boundaries.array()[boundaries.array() == 2])
print(boundaries.array()[boundaries.array() == 2])
print(boundaries.array()[boundaries.array() == 4])
cells = MeshFunction("size_t", mesh, mesh.topology().dim())
cells.set_all(1)
print("Marker for all internal cells is set to 1")
bc1 = DirichletBC(W.sub(0).sub(0), Constant((compression)), boundaries, 4)
bc2 = DirichletBC(W.sub(0).sub(1), Constant((0)), boundaries, 4)
bc3 = DirichletBC(W.sub(0).sub(2), Constant((0)), boundaries, 4)
bc4 = DirichletBC(W.sub(0).sub(0), Constant((0)), boundaries, 2)
bc5 = DirichletBC(W.sub(0).sub(1), Constant((0)), boundaries, 2)
bc6 = DirichletBC(W.sub(0).sub(2), Constant((0)), boundaries, 2)
bcs = [bc1,bc2,bc3, bc4, bc5, bc6]
dx = Measure('dx', subdomain_data=cells)
ds = Measure('ds', subdomain_data=boundaries)
return dx, ds, boundaries, bcs
def constitutive_law(mesh, num_variants, R, W, w, dw, wx, compression, penalty, time_step, strain_approx=None):
#set_log_level(10)
# Form compiler options
parameters["form_compiler"]["optimize"] = True
parameters["form_compiler"]["cpp_optimize"] = True
parameters.parse()
from db_compliance import Compliance
compliance_phase1, compliance_phase2 = Compliance.CuAlNi()
Compliance_tetragonal = as_tensor(compliance_phase1)
Compliance_monoclinic = as_tensor(compliance_phase2)
# print(Compliance_monoclinic)
# print(Compliance_tetragonal)
# Definition of normal vectors to the elastic body and to the rigid half-space
nRIGID = Constant((0.0, 0.0, 1.0))
n = FacetNormal(mesh)
##################################
# Phase field definitions
##################################
def mar(c):
# tot_mar = sum(c)
# for one variant
tot_mar = c
return tot_mar
def aus(c):
return 1.0 - mar(c)
def trans_strain(c):
# strain = [c[i] * shape_strains_list[i] for i in range(num_variants)]
#tr_strain = sum(strain)
# for one variant
strain = c * shape_strains_list
#return tr_strain
return strain
def mixture_compliance(c):
return (aus(c) * Compliance_tetragonal) + (mar(c) * Compliance_monoclinic)
##################################
# Displacement field definitions
##################################
# matrix-to-vector transform
def strain3voigt(e):
return as_vector(
[e[0, 0],
e[1, 1],
e[2, 2],
e[1, 2] * 2,
e[0, 2] * 2,
e[0, 1] * 2]
)
# vector-to-matrix transform
def voigt3stress(s):
return as_tensor(
[[s[0], s[5], s[4]],
[s[5], s[1], s[3]],
[s[4], s[3], s[2]]]
)
def epsilon(u):
if strain_approx is None:
e = sym(grad(u))
return e
elif strain_approx =='lagrangian':
I = Identity(3)
Fgrad = I + grad(u)
C = Fgrad.T * Fgrad
E = 0.5*(C - I)
return E
elif strain_approx =='hencky_order_22':
I = Identity(3)
Fgrad = I + grad(u)
C = Fgrad.T * Fgrad
a = C*C - I
b = (C*C) + 4*C + I
H = 1.5 * a * inv(b)
return H
def epsilon_elastic(u, c):
#u, c = split(w)
return epsilon(u) - trans_strain(c)
def Vstrain(u, c):
return strain3voigt(epsilon_elastic(u, c))
def Vsigma(u, c):
#u, c = split(w)
return dot(mixture_compliance(c), Vstrain(u, c))
def sigma(u, c):
return voigt3stress(Vsigma(u, c))
def dilatation(c):
return det(trans_strain(c))
def gap(u): # Definition of gap function
x = SpatialCoordinate(mesh)
return x[2] + u[2]
def maculay(x): # Definition of Maculay bracket
return (x+abs(x))/2
def pN(u, c):
return dot(dot(nRIGID, sigma(u, c)), nRIGID)
def convert_to_integer(a):
"Convert to a 32-bit int. Raise exception if this will cause an overflow"
if abs(a) <= iinfo(int32).max:
return int32(a)
else:
raise OverflowError("Cannot safely convert to a 32-bit int.")
def psi(w):
u = split(w)[0]
c = split(w)[1]
#c = split(w)[1:]
def elastic(u, c):
elastic_energy = 0.5 * dilatation(c) * inner(sigma(u, c), epsilon_elastic(u, c))
# approximate energy without volume dilatation (det F = 1)
# elastic_energy = 0.5 * inner(sigma(u, c), epsilon_elastic(u, c))
return elastic_energy
def interface(c):
AM_surface_energy = 0.0020 # J/m^2 = Pa.m = Pa'.nm (no change in magnitude in new scaling)
AM_length_scale = 50.0 # nm
MM_surface_energy = 0.00 # J/m^2 = Pa.m (no change in magnitude in new scaling)
MM_length_scale = 1.00 # nm
AM_interface = (4.0/DOLFIN_PI) * (AM_surface_energy/AM_length_scale) * (aus(c)*mar(c))
#MM_interface = (4.0/DOLFIN_PI) * (MM_surface_energy/MM_length_scale) * diffuse
energy_cost = AM_interface #+ MM_interface
return energy_cost
def chemical(c):
phi = 5.0e-3 # MPa = 1e-3 * Pa'
chemical_energy = phi*mar(c)
return chemical_energy
def contact_pen(u):
pen = (0.5 * penalty *inner(maculay(-gap(u)),maculay(-gap(u))))
return pen
def phase_pen(c):
# penp1 = [inner(maculay(c[i] - 1), maculay(c[i] - 1)) for i in range(num_variants)]
# penp0 = [inner(maculay(-c[i]), maculay(-c[i])) for i in range(num_variants)]
#penp = sum(penp1) + sum(penp0)
# for one variant
penp1 = inner(maculay(c - 1), maculay(c - 1))
penp0 = inner(maculay(-c), maculay(-c))
penp = penp1 + penp0
return 0.5 * (10*penalty) * penp
# return elastic(u, c), contact_pen(u), phase_pen(c)
return elastic(u, c) + interface(c) + chemical(c), contact_pen(u), phase_pen(c)
time_end = 1.0
t_curr = 0.0
t_curr = t_curr + time_step
d_step = compression * t_curr
while t_curr <= time_end:
dx, ds, boundaries, bcs = sphere_boundaries(mesh, meshSIZE, R, d_step, W)
print("Current displacement at boundary = ", d_step, " nm")
# Total potential energy (linear elasticity, gradient-interface)
Pi = psi(w)[0]*dx + psi(w)[1]*ds(6) + psi(w)[2]*dx
# Compute first variation of Pi (directional derivative about u in the direction of v)
F = derivative(Pi, w, wx)
# Compute Jacobian of F for iterative "newton_solver"
J = derivative(F, w, dw)
wmin, wmax = func_space_bounds(W)
for bc in bcs:
bc.apply(wmin.vector())
bc.apply(wmax.vector())
# initial guess
w.vector()[:] = d_step
problem = NonlinearVariationalProblem(F, w, bcs, J=J)
problem.set_bounds(wmin, wmax)
solver = NonlinearVariationalSolver(problem)
snes_solver_parameters = {"nonlinear_solver": "snes",
"snes_solver": {"linear_solver": 'lu', #"lu",
"preconditioner": "petsc_amg", #"bjacobi",
"maximum_iterations": 10,
"absolute_tolerance": 1E-3,
"relative_tolerance": 1E-3,
"report": True,
"method":'vinewtonrsls',
"error_on_nonconvergence": True,
}}
solver.parameters.update(snes_solver_parameters)
#Solve the nonlinear problem
iter, converged = solver.solve()
class PhaseProblem(OptimisationProblem):
def __init__(self):
OptimisationProblem.__init__(self)
# Objective function
def f(self, x):
w.vector()[:] = x
return assemble(Pi)
# Gradient of the objective function
def F(self, b, x):
w.vector()[:] = x
assemble(F, tensor=b)
# Hessian of the objective function
def J(self, A, x):
w.vector()[:] = x
assemble(J, tensor=A)
# solver = PETScTAOSolver()
# tao_solver_parameters = {"method": "bqpip",
# #"line_search": "gpcg",
# #"linear_solver": "lu",
# #"preconditioner": "ilu",
# "gradient_absolute_tol": 1e-3,
# "gradient_relative_tol": 1e-3,
# "maximum_iterations": 150,
# "monitor_convergence": True,
# "report": True
# }
# solver.parameters.update(tao_solver_parameters)
# info(solver.parameters, True)
# iter, converged = solver.solve(PhaseProblem(), w.vector(), wmin.vector(), wmax.vector())
t_curr = t_curr + time_step
d_step = compression * t_curr
_u = w.split(deepcopy=True)[0]
_c = w.split(deepcopy=True)[1]
print("c_max = ", max(_c.vector()[:]), "c_min = ", min(_c.vector()[:]))
print("u_max = ", max(_u.vector()[:]), "u_min = ", min(_u.vector()[:]))
#from vedo.dolfin import plot
#plot(_u.sub(2))
return w, _u, _c, mar(_c), boundaries
hex = 0
R = 100 # nm
mesh_size = 5.0
mesh_folder = "./meshes/"
if hex == 1:
subfolder = 'hexahedral/'
else:
subfolder = "tetrahedral/"
mesh_folder = mesh_folder + subfolder
mesh_file = "mesh3D_R_" + str(int(R)) + "_size_" + str(int(mesh_size)) + ".xdmf"
# density = 25
# coordinates = (200.0, 100.0, 100.0)
# num_points = (density, density, density)
#mymesh, hMESH, meshSIZE, = cuboid_geometry((coordinates, num_points))
mymesh, hMESH, meshSIZE, = sphere_geometry(mesh_folder, mesh_file)
basis = 'linear'
W, W1, W2, w, dw, wx, num_variants, shape_strains_list = func_spaces(mymesh, basis)
compression = R/100.0
#dx, ds, boundaries, bcs = sphere_boundaries(mymesh, meshSIZE, R, compression, W)
penalty = 100
#E = 200 # GPa = Pa'
time_step = 5e-1
print("hMESH = ", hMESH)
_w, _u, _c, mar, boundaries = constitutive_law(mymesh, num_variants, R, W, w, dw, wx, compression, penalty, time_step)
from vedo.dolfin import plot
plot(_u)
file = File("./displacement-pen-phase.pvd")
file << project(_u, W1)
print(mar)
#file = File("./phase-pen-phase.pvd")
#file << project(mar, W2)
#w, boundaries = pureElastic_constitutive_law(mymesh, meshSIZE, hMESH, R, W, w, dw, v, compression, penalty, E, time_step)
#from vedo.dolfin import plot
#plot(w)
#with XDMFFile("u_PEN_" + ".xdmf") as xdmf:
# xdmf.write_checkpoint(w, "u", 0.0, XDMFFile.Encoding.HDF5, append=False)
# Savu u as .pvd
# file = File("./displacement-pen.pvd")
# file << w