if you want I can give you the code for that example, or I can give you the code for this similar example:
#!/usr/bin/env python
# -*- coding: UTF8 -*-
#
############################################################################
import numpy as np
import getfem as gf
gf.util_trace_level(1)
gf.util_warning_level(1)
PI = np.pi
# Input data
R = 50. # ring radius
r = 5. # cross section radius
NC = 26 # Number of elements along the ring circumference
Nr1 = 2 # Number of elements in the cross section core
Nr2 = 2 # Number of elements in the cross section peel
E = 1e5 # Young's modulus
nu = 0.45 # Poisson's ratio
mult_fem_order = 1 # contact multipliers finite element order
integration_degree = 5 # 27 gauss points per hexa
integration_contact_degree = 7 # 16 gauss points per quad
c_aug = 1e-2*E # Augmentation parameter
release_dist = r
# auxiliary constants
EXTERIOR_RG = 1
HANDLE1_RG = 2
HANDLE2_RG = 3
# Mesh generation:
# - create a 2D mesh for a circular disc
# - extrude the 2D mesh into a cylinder
# - wrap the cylinder into a closed ring
# - clone the ring mesh to get a second ring
m_ = gf.Mesh("import", "structured_ball",
"GT='GT_QK(2,2)';ORG=[0,0];SIZES=[%g];NSUBDIV=[%i,%i]"
% (r, Nr1, Nr2))
m0 = gf.Mesh("prismatic", m_, NC, 2) # second order
pts = m0.pts()
for i in range(pts.shape[1]):
x = pts[0,i]
z = pts[2,i]
pts[0,i] = (R+x)*np.cos(2*PI*z)
pts[2,i] = (R+x)*np.sin(2*PI*z)
m0.set_pts(pts)
m1 = gf.Mesh("empty", 3)
m1.merge(m0, tol=1e-3) # this trick is used just for gluing the open ends of the ring in m0
m1.set_region(EXTERIOR_RG, m1.outer_faces())
m1.set_region(HANDLE1_RG, m1.outer_faces_in_box([-R-1.1*r,-1.1*r,-0.3*R],
[-R+1.1*r, 1.1*r, 0.3*R]))
m1.set_region(HANDLE2_RG, m1.outer_faces_in_box([R-1.1*r,-1.1*r,-0.3*R],
[R+1.1*r, 1.1*r, 0.3*R]))
m1.optimize_structure()
m1.export_to_vtu("mesh1.vtu")
m2 = gf.Mesh("clone", m1)
m2.translate([-R,2.5*r,0])
m2.export_to_vtu("mesh2.vtu")
# Finite element spaces and integration methods
mf1 = gf.MeshFem(m1, 3)
mf1.set_fem(gf.Fem("FEM_Q2_INCOMPLETE(3)"))
mf2 = gf.MeshFem(m2, 3)
mf2.set_fem(gf.Fem("FEM_Q2_INCOMPLETE(3)"))
mfmult1 = gf.MeshFem(m1, 3)
mfmult1.set_classical_fem(mult_fem_order)
mfmult2 = gf.MeshFem(m2, 3)
mfmult2.set_classical_fem(mult_fem_order)
mim1 = gf.MeshIm(m1, integration_degree)
mim2 = gf.MeshIm(m2, integration_degree)
mim_contact1 = gf.MeshIm(m1, integration_contact_degree)
mim_contact2 = gf.MeshIm(m2, integration_contact_degree)
# Model object
md = gf.Model("real")
md.add_fem_variable("u1", mf1)
md.add_fem_variable("u2", mf2)
md.add_filtered_fem_variable("contact_mult1", mfmult1, EXTERIOR_RG)
md.add_filtered_fem_variable("contact_mult2", mfmult2, EXTERIOR_RG)
#mf_contact_mult = md.mesh_fem_of_variable("contact_mult")
# Elasticity
md.add_initialized_data("K", E/(3*(1-2*nu)))
md.add_initialized_data("G", E/(2*(1+nu)))
md.add_macro("F(u)", "Id(3)+Grad_u")
md.add_macro("tau(u)", "K*log(Det(F(u)))*Id(3)+G*pow(Det(F(u)),-2/3)*Deviator(F(u)*F(u)')")
md.add_nonlinear_term(mim1, "(tau(u1)*Inv(F(u1)')):Grad_Test_u1")
md.add_nonlinear_term(mim2, "(tau(u2)*Inv(F(u2)')):Grad_Test_u2")
# Lagrange multipliers for handles
md.add_variable("q11",3) # ring 1 handle 1
md.add_variable("q12",3) # ring 1 handle 2
md.add_variable("q21",3) # ring 2 handle 1
md.add_variable("q22",3) # ring 2 handle 2
md.add_initialized_data("p11", [0,0,0]) # we will keep this fixed
md.add_initialized_data("p12", [0,0,0]) # we will keep this fixed only at the beginning
md.add_initialized_data("p21", [0,0,0]) # we will drive this only at the beginning
md.add_initialized_data("p22", [0,0,0]) # we will drive this till the end
md.add_linear_term(mim1, "(u1-p11).q11", HANDLE1_RG)
md.add_linear_term(mim1, "(u1-p12).q12", HANDLE2_RG)
md.add_linear_term(mim2, "(u2-p21).q21", HANDLE1_RG)
md.add_linear_term(mim2, "(u2-p22).q22", HANDLE2_RG)
md.add_initialized_data("penal", 0.)
md.add_linear_term(mim1, "1e4*(u1-p11).Test_u1", HANDLE1_RG) # add some elastic support to handle 1 of ring 1 to avoid twisting
md.add_linear_term(mim1, "penal*(u1-p12).Test_u1", HANDLE2_RG) # add some elastic support to handle 2 of ring 1 to avoid twisting
md.add_linear_term(mim2, "penal*(u2-p21).Test_u2", HANDLE1_RG) # add some elastic support to handle 1 of ring 2 to avoid twisting
md.add_linear_term(mim2, "1e4*(u2-p22).Test_u2", HANDLE2_RG) # add some elastic support to handle 2 of ring 2 to avoid twisting
# Add contact terms to the model
md.add_initialized_data("c", c_aug)
if False: # use large sliding contact brick
md.add_initialized_data("alpha", 1.)
md.add_initialized_data("f", 0.)
ibc = md.add_integral_large_sliding_contact_brick_raytracing("c", release_dist, "f", "alpha", 1) # 1 stands for the more symmetric version
md.add_master_slave_contact_boundary_to_large_sliding_contact_brick(ibc, mim_contact1, EXTERIOR_RG, "u1", "contact_mult1", "")
md.add_master_slave_contact_boundary_to_large_sliding_contact_brick(ibc, mim_contact2, EXTERIOR_RG, "u2", "contact_mult2", "")
else: # implement the contact equations directly
md.add_raytracing_transformation("raytrace", release_dist)
md.define_variable_group("u", "u1", "u2")
md.add_master_contact_boundary_to_raytracing_transformation("raytrace", m1, "u", EXTERIOR_RG)
md.add_master_contact_boundary_to_raytracing_transformation("raytrace", m2, "u", EXTERIOR_RG)
md.add_nonlinear_term(mim_contact1, "-contact_mult1.Test_u1", EXTERIOR_RG)
md.add_nonlinear_term(mim_contact2, "-contact_mult2.Test_u2", EXTERIOR_RG)
md.add_nonlinear_term(mim_contact1, "-(1/c)*contact_mult1.Test_contact_mult1", EXTERIOR_RG)
md.add_nonlinear_term(mim_contact2, "-(1/c)*contact_mult2.Test_contact_mult2", EXTERIOR_RG)
md.add_macro("normal1", "Normalized(Inv(F(u1)').Normal)")
md.add_macro("normal2", "Normalized(Inv(F(u2)').Normal)")
md.add_macro("gap1", "(Interpolate(X,raytrace)+Interpolate(u,raytrace)-X-u1).normal1")
md.add_macro("gap2", "(Interpolate(X,raytrace)+Interpolate(u,raytrace)-X-u2).normal2")
md.add_nonlinear_term(mim_contact1,
"Interpolate_filter(raytrace,(-1/c)*neg_part(contact_mult1.normal1+c*gap1)*normal1.Test_contact_mult1, 1)", EXTERIOR_RG)
md.add_nonlinear_term(mim_contact2,
"Interpolate_filter(raytrace,(-1/c)*neg_part(contact_mult2.normal2+c*gap2)*normal2.Test_contact_mult2, 1)", EXTERIOR_RG)
md.add_nonlinear_term(mim_contact1,
"Interpolate_filter(raytrace, -neg_part(contact_mult1.normal1+c*gap1)*normal1.Interpolate(Test_u,raytrace), 1)",
EXTERIOR_RG)
md.add_nonlinear_term(mim_contact2,
"Interpolate_filter(raytrace, -neg_part(contact_mult2.normal2+c*gap2)*normal2.Interpolate(Test_u,raytrace), 1)",
EXTERIOR_RG)
# Perform the simulation
print("Model dofs: %i" % md.nbdof())
print("Displacement fem dofs: %i" % (mf1.nbdof()+mf2.nbdof()))
#print("Contact mult dofs: %i" % mf_contact_mult.nbdof())
for step in range(90):
if step <= 30: # initial phase
t = step/30
md.set_variable("p21", [1.8*R*(max(t,min(4*t,0.2))),
-5*r*min(t/0.4,1), #-5*r*(np.cos(PI*t)-1)/2,
0])
md.set_variable("p22", [1.8*R*max(0,(t-0.4)/0.6)**2,
-5*r*min(t/0.4,1),
0])
elif step <= 38: # second phase, releasing handles 21 and 22
if step == 31:
md.disable_variable("q12")
md.disable_variable("q21")
md.set_variable("q12", [0,0,0])
md.set_variable("q21", [0,0,0])
md.set_variable("penal", (1e2,3e1,1e1,3e0,1e0,1e-1,1e-3,0.)[step-31])
else: # final phase
t = 1+(step-38)/100
if t > 1.25: # slow down
t = 1.25 + 0.2*(t-1.25)
md.set_variable("p22", [1.8*R*max(0,(t-0.4)/0.6)**2,
-5*r,
0])
print("Step", step, "t =", t)
md.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"ring1_{step}.vtu", mf1, md.variable("u1"), "Displacements")
mf2.export_to_vtu(f"ring2_{step}.vtu", mf2, md.variable("u2"), "Displacements")