Dear Konstantinons,
Apologies for the delay. While reviewing our previous conversation, I realized that I had only sent the Gmsh code.
Please find attached a minimal working example (MWE) that I have prepared. I also took the opportunity to add an additional part, namely the construction of mechanical parameters from an image and their mapping onto the computational domain .
For this purpose, I relied on an example previously published in the discussion group, which I attempted to adapt to my specific case. The corresponding implementation is included directly in the code.
I apologize if some comments in the code are written in French.
import numpy as np
import getfem as gf
import os
import time
from PIL import Image, ImageOps
from scipy.ndimage import map_coordinates
start_time = time.time()
gf.util_trace_level(1)
gf.util_warning_level(1)
m = gf.Mesh('import', 'gmsh', 'GI.msh')
mf = gf.MeshFem(m, 1)
mf.set_fem(gf.Fem("FEM_PK(3,2)"))
mim = gf.MeshIm(m, 4)
integration_degree = 3 # 27 gauss points per hexa
#mesh coordinate
coords = m.pts()
print(coords.shape)
print(coords)
#----------------------- from gray scale image --------------------
# --- Charger image ---
img = Image.open("maze.jpg").convert("L")
data = np.array(img)/255.0
NY, NX = data.shape
######################
md1 = gf.Model("real")
mf1 = gf.MeshFem(m, 1)
mf1.set_fem(gf.Fem("FEM_PK(3,2)"))
mfu = gf.MeshFem(m, m.dim()) # displacement
mfu.set_fem(gf.Fem("FEM_PK(3,2)")) # displacement
mfp = gf.MeshFem(m, 1) # pressure
mfp.set_fem(gf.Fem("FEM_PK(3,1)")) # presssure
mim2 = gf.MeshIm(m, integration_degree)
md1.add_fem_variable("u", mfu) # displacement
md1.add_fem_variable('p', mfp) # pressure variable
# mechanical parameters
E = 10.0
nu = 0.3
mu = E / (2 * (1 + nu))
lmbda = 100*E * nu / ((1 + nu) * (1 - 2 * nu))
#Expression to project
mu_expr = (
"2.0 * (1 - Heaviside(sqrt(X(1)*X(1) + X(2)*X(2)) - (2.0 + 0.15))) + "
"0.5 * (Heaviside(sqrt(X(1)*X(1) + X(2)*X(2)) - (2.0 + 0.15)) - "
"Heaviside(sqrt(X(1)*X(1) + X(2)*X(2)) - (2.0 + 0.3))) + "
"2.5 * Heaviside(sqrt(X(1)*X(1) + X(2)*X(2)) - (2.0 + 0.3))"
)
#md1.add_macro("mu", mu_expr) # method 1
mfE = gf.MeshFem(m)
mfE.set_classical_fem(1)
md1.add_initialized_fem_data("mu", mfE, md1.interpolation(mu_expr, mfE)) # method 2
#md1.add_initialized_fem_data("mu", mfp, md1.interpolation(mu_expr, mfp)) # method 3
#mimd = gf.MeshImData(mim2, -1, 1) # -1 is the region, 1 is for storing a scalar field
#md1.add_im_data("mu", mimd)
#md1.set_variable("mu", md1.interpolation(mu_expr, mimd, -1)) # method 4
#md1.add_initialized_data("mu",2.5)
md1.add_initialized_data("pEpi", 0.0)
# for the projection
mf_mu = gf.MeshFem(m, 1)
mf_mu.set_fem(gf.Fem("FEM_PK(3,1)")) # mu
Muu = md1.interpolation(mu_expr, mfp) # use to visualize the Mu from expression
# ------------------- partant de l'image ------------------
# --- MeshFem pour rho ---
mfrho = gf.MeshFem(m, 1)
mfrho.set_classical_fem(0)
#mfrho.set_fem(gf.Fem("FEM_PK(3,1)"))
md1.add_fem_data("rho", mfrho)
# --- Coordonnées ---
Xp = md1.interpolation("X(1)", mfrho)
Yp = md1.interpolation("X(2)", mfrho)
Zp = md1.interpolation("X(3)", mfrho)
# --- Coord. cylindriques ---
theta = np.arctan2(Yp, Xp)
theta[theta < 0] += 2*np.pi
R = np.sqrt(Xp**2 + Yp**2)
L = Zp.max() - Zp.min()
# --- Mapping ---
i = (theta / (2*np.pi) * (NX-1)).astype(int)
j = ((Zp - Zp.min()) / L * (NY-1)).astype(int)
i = np.clip(i, 0, NX-1)
j = np.clip(j, 0, NY-1)
rho = data[NY-1-j, i]
pts = mfrho.basic_dof_nodes()
#pts = m.pts()
Xp, Yp, Zp = pts[0, :], pts[1, :], pts[2, :]
# --- Convert ---
theta = np.arctan2(Yp, Xp)
theta[theta < 0] += 2 * np.pi
R = np.sqrt(Xp**2 + Yp**2)
L = Zp.max() - Zp.min()
# --- Normalisation to image index ---
xi = (theta / (2 * np.pi)) * (NX - 1)
yi = ((Zp - Zp.min()) / L) * (NY - 1)
# --- map_coordinates ---
rho = map_coordinates(data, [NY - 1 - yi, xi], order=1, mode='nearest')
md1.set_variable("rho", rho) # set variable
# Kinematics
md1.add_macro("F", "Id(3)+Grad_u")
md1.add_macro("J", "Det(F)")
md1.add_macro("C", "F'*F")
md1.add_macro("B", "F*F'")
md1.add_macro("I1", "Trace(C)")
# Stress tensor
#md1.add_macro("sigma", "2*0.000035*rho*B - p*Id(3)")
md1.add_macro("sigma", "2*mu*B - p*Id(3)")
md1.add_initialized_data("stab", 100)
md1.add_macro("Piola", "J*sigma*Inv(F)'")
md1.add_nonlinear_term(mim2, "Piola:Grad_Test_u")
md1.add_nonlinear_term(mim2, "Test_p*(J-1)")
md1.add_nonlinear_term(mim2, "stab*(Grad_p.Grad_Test_p)")
md1.add_macro("normal2", "Normalized(Inv(F').Normal)")
md1.add_macro("normal3", "Inv(F').Normal")
md1.add_nonlinear_term(mim2, "-pEpi*Det(F)*normal2.Test_u", 93)
md1.add_initialized_data("end92", [0.0,0.0,0.0])
md1.add_initialized_data("end95", [0.0,0.0,0.0])
md1.add_Dirichlet_condition_with_multipliers(mim2, 'u', mfu, 92, 'end92')
md1.add_Dirichlet_condition_with_multipliers(mim2, 'u', mfu, 95, 'end95')
# Dossier de résultats
if not os.path.exists('outFW'):
os.makedirs('outFW')
tf = 2.0
to = 0.0
n = 0
dt = 0.1
while to <= tf:
print("time=: %i" % to)
#md.set_variable("p22", [0, -0*t, 0])
md1.set_variable("pEpi", -0.3*to)
md1.solve("noisy", "max_iter", 20, "max_res", 1e-8,
"lsearch", "simplest", "alpha max ratio", 3., "alpha min", 0.02, "alpha mult", 0.6)
#mf1.export_to_vtu(f"internalS/flat_tube_{step}.vtu", mf1, md.variable("u1"), "Displacements")
output = (mfu, md1.variable("u"), "u",
mfp, md1.variable("p"), "p",
mf_mu, Muu, "Mu",
mfE, md1.variable("mu"), "mu",
mfrho, md1.variable("rho"), "rho")
mfu.export_to_vtu(f"outFW/EM_{n:04d}.vtu", *output)
to += dt
n += 1
end_time = time.time() # fin du chronométrage
print("Temps d'exécution :", end_time - start_time, "secondes")