def update_multimesh(self, step): move_norm = [] hmins = [] move_max = [] for i in range(1, self.N): s_move = self.deformation[i - 1].copy(True) s_move.vector()[:] *= step # Approximate geodesic distance dDeform = Measure("ds", subdomain_data=self.mfs[i]) n_i = FacetNormal(self.multimesh.part(i)) geo_dist_i = inner(s_move, s_move)*\ dDeform(self.move_dict[i]["Deform"]) move_norm.append(assemble(geo_dist_i)) # move_max.append(project(sqrt(s_move[0]**2 + s_move[1]**2), # FunctionSpace(self.multimesh.part(i),"CG",1) # ).vector().max()) # hmins.append(self.multimesh.part(i).hmin()) ALE.move(self.multimesh.part(i), s_move) # Compute L2 norm of movement self.move_norm = sqrt(sum(move_norm)) # self.move_max = max(move_max) # print(hmins, move_max) self.multimesh.build() for key in self.cover_points.keys(): self.multimesh.auto_cover(key, self.cover_points[key])
def test_HarmonicSmoothing(): # Create some mesh and its boundary mesh = UnitSquareMesh(10, 10) boundary = BoundaryMesh(mesh, 'exterior') # Move boundary disp = Expression(("0.3*x[0]*x[1]", "0.5*(1.0-x[1])")) ALE.move(boundary, disp) # Move mesh according to given boundary ALE.move(mesh, boundary) # Check that new boundary topology corresponds to given one boundary_new = BoundaryMesh(mesh, 'exterior') assert boundary.topology().hash() == boundary_new.topology().hash() # Check that coordinates are almost equal err = sum(sum(abs(boundary.coordinates() \ - boundary_new.coordinates()))) / mesh.num_vertices() print("Current CG solver produced error in boundary coordinates", err) assert round(err - 0.0, 5) == 0 # Check mesh quality magic_number = 0.35 rmin = MeshQuality.radius_ratio_min_max(mesh)[0] assert rmin > magic_number
def solve(self, dt): self.u = Function(self.V0) self.w = TestFunction(self.V0) self.du = TrialFunction(self.V0) x = SpatialCoordinate(self.mesh0) L = inner( self.S(), self.eps(self.w) )*dx(degree=4)\ - inner( self.b, self.w )*dx(degree=4)\ - inner( self.h, self.w )*ds(degree=4)\ + inner( 1e-6*self.u, self.w )*ds(degree=4)\ - inner( min_value(x[2]+self.ut[2]+self.u[2], 0) * Constant((0,0,-1.0)), self.w )*ds(degree=4) a = derivative(L, self.u, self.du) problem = NonlinearVariationalProblem(L, self.u, bcs=[], J=a) solver = NonlinearVariationalSolver(problem) solver.solve() self.ut.vector()[:] = self.ut.vector()[:] + self.u.vector()[:] ALE.move(self.mesh, Function(self.V, self.u.vector())) self.v.vector()[:] = self.u.vector()[:] / dt self.n = FacetNormal(self.mesh)
def steepest_descent_update(self, step, out=False): """ Updates the mesh in the steepest descent direction with steplength 'step' """ s_descent = self.perturbation.copy(deepcopy=True) if out: sm_def << s_descent s_descent.vector()[:] *= step ALE.move(self.mesh, s_descent)
def test_ale(): # Create some mesh mesh = UnitSquareMesh(4, 5) # Make some cell function # FIXME: Initialization by array indexing is probably # not a good way for parallel test cellfunc = CellFunction('size_t', mesh) cellfunc.array()[0:4] = 0 cellfunc.array()[4:] = 1 # Create submeshes - this does not work in parallel submesh0 = SubMesh(mesh, cellfunc, 0) submesh1 = SubMesh(mesh, cellfunc, 1) # Move submesh0 disp = Constant(("0.1", "-0.1")) ALE.move(submesh0, disp) # Move and smooth submesh1 accordignly ALE.move(submesh1, submesh0) # Move mesh accordingly parent_vertex_indices_0 = \ submesh0.data().array('parent_vertex_indices', 0) parent_vertex_indices_1 = \ submesh1.data().array('parent_vertex_indices', 0) mesh.coordinates()[parent_vertex_indices_0[:]] = \ submesh0.coordinates()[:] mesh.coordinates()[parent_vertex_indices_1[:]] = \ submesh1.coordinates()[:] # If test passes here then it is probably working # Check for cell quality for sure magic_number = 0.28 rmin = MeshQuality.radius_ratio_min_max(mesh)[0] assert rmin > magic_number
u_expre_neg.t = step * float(dt) uh.assign(u_expr) # Compute area at old configuration old_area = assemble(phih0*dx) # Pre-assemble rhs pde_projection.assemble_state_rhs() # Advect the particles ap.do_step(float(dt)) # Move mesh umesh.assign(u_expre_neg) ALE.move(mesh, project(umesh * dt, Vcg)) # Relocate particles as a result of mesh motion ap.update_facets_info() p.relocate() # Assemble left-hand side on new config, but not the right-hand side pde_projection.assemble(True, False) pde_projection.solve_problem(phibar, phih, 'mumps', 'none') # Area on new configuration new_area = assemble(phih*dx) # Update solution assign(phih0, phih)
def move_mesh(self): displacement = self.compute_displacement() ALE.move(self.mesh, displacement)
}, 'neumann': { 'values': [[0., -1e5]], 'regions': [2], 'types': ['cauchy'] } } } } # First solve the inverse elastostatics problem. problem = fm.SolidMechanicsProblem(config) solver = fm.SolidMechanicsSolver(problem, fname_disp="results/unloaded_config.pvd") solver.full_solve() # Move the mesh using dolfin's ALE functionality from dolfin import ALE, Mesh ALE.move(problem.mesh, problem.displacement) mesh_copy = Mesh(problem.mesh) # Only need to change relevant entries in config config['mesh']['mesh_file'] = mesh_copy config['formulation']['inverse'] = False # Solve a 'forward' problem. problem = fm.SolidMechanicsProblem(config) solver = fm.SolidMechanicsSolver(problem, fname_disp="results/loaded_config.pvd") solver.full_solve()
else: values[0] = 0.0 mesh = BoxMesh.create( comm, [Point(0.0, 0.0, 0.0), Point(float(lmbdax), 1.0, float(lmbdaz))], [nx, ny, nz], CellType.Type.tetrahedron) # Shift the mesh to line up with the initial step function condition scale = db * (1.0 - db) shift = Expression(("0.0", "x[1]*(H - x[1])/S*A*cos(pi/Lx*x[0])*cos(pi/Lz*x[2])", "0.0"), A=0.02, Lx=lmbdax, Lz=lmbdaz, H=1.0, S=scale, degree=4) V = VectorFunctionSpace(mesh, "CG", 1) displacement = interpolate(shift, V) ALE.move(mesh, displacement) # Entrainment functional measures de = 1 cf = MeshFunction("size_t", mesh, mesh.topology().dim(), 0) CompiledSubDomain("x[1] > db - DOLFIN_EPS", db=db).mark(cf, de) dx = Measure("dx", subdomain_data=cf) # Setup particles pres = 25 x = RandomBox(Point(xmin, ymin, zmin), Point(xmax, ymax, zmax)).generate([pres, pres, pres]) s = np.zeros((len(x), 1), dtype=np.float_) # Interpolate initial function onto particles, index slot 1 property_idx = 1 ptcls = particles(x, [s], mesh)
def update_mesh_from_boundary_nodes(self, perturbation): """ Deform mesh with boundary perturbation (a numpy array) given as Neumann input in an linear elastic mesh deformation. """ # Reset mesh self.mesh.coordinates()[:] = self.backup volume_function = Function(self.S) for i in self.design_map.keys(): volume_function.vector()[self.design_map[i]] = perturbation[i] u, v = TrialFunction(self.S), TestFunction(self.S) def compute_mu(constant=True): """ Compute mu as according to arxiv paper https://arxiv.org/pdf/1509.08601.pdf """ mu_min=Constant(1) mu_max=Constant(500) if constant: return mu_max else: V = FunctionSpace(self.mesh, "CG",1) u, v = TrialFunction(V), TestFunction(V) a = inner(grad(u),grad(v))*dx l = Constant(0)*v*dx bcs = [] for marker in self.move_dict["Fixed"]: bcs.append(DirichletBC(V, mu_min, self.mf, marker)) for marker in self.move_dict["Deform"]: bcs.append(DirichletBC(V, mu_max, self.mf, marker)) mu = Function(V) solve(a==l, mu, bcs=bcs) return mu mu = compute_mu(False) def epsilon(u): return sym(grad(u)) def sigma(u,mu=500, lmb=0): return 2*mu*epsilon(u) + lmb*tr(epsilon(u))*Identity(2) a = inner(sigma(u,mu=mu), grad(v))*dx L = inner(Constant((0,0)), v)*dx bcs = [] for marker in self.move_dict["Fixed"]: bcs.append(DirichletBC(self.S, Constant([0]*mesh.geometric_dimension()), self.mf, marker)) dStress = Measure("ds", subdomain_data=self.mf) from femorph import VolumeNormal n = VolumeNormal(mesh) # Enforcing node movement through elastic stress computation # NOTE: This strategy does only work for the first part of the deformation for marker in self.move_dict["Deform"]: L += inner(volume_function, v)*dStress(marker) # Direct control of boundary nodes # for marker in self.move_dict["Deform"]: # bcs.append(DirichletBC(self.S, volume_function, self.mf, marker)) s = Function(self.S) solve(a==L, s, bcs=bcs) self.perturbation = s ALE.move(self.mesh, self.perturbation)
dJ1_bottom += 2 * inner(dot(s_bottom, grad(T)), T) * dX J = a1 + J1 + a2 + a3 + a4 dJds = assemble_multimesh(da1_top + da1_bottom + dJ1_top + dJ1_bottom + da2 + da3 + da4) # Do a taylor test for deformation of the top mesh Js = [assemble_multimesh(J)] epsilons = [0.1 * 0.5**i for i in range(5)] errors = {"0": [], "1": []} for eps in epsilons: s_eps = deformation_vector() s_eps.vector()[:] *= eps for i in range(2): plot(multimesh.part(i)) ALE.move(multimesh.part(i), s_eps.part(i)) plot(multimesh.part(i), color="r") show() multimesh.build() multimesh.auto_cover(0, Point(1.25, 0.875)) J_eps = assemble_multimesh(J) Js.append(J_eps) errors["0"].append(abs(J_eps - Js[0])) errors["1"].append(abs(J_eps - Js[0] - eps * dJds)) s_eps.vector()[:] *= -1 for i in range(2): ALE.move(multimesh.part(i), s_eps.part(i)) multimesh.build() multimesh.auto_cover(0, Point(1.25, 0.875)) print(errors["0"]) print(errors["1"])
def move_mesh(self): log(PROGRESS, "moving mesh") displacement = self.compute_displacement() ALE.move(self.mesh, displacement)
def test_moving_mesh(): t = 0. dt = 0.025 num_steps = 20 xmin, ymin = 0., 0. xmax, ymax = 2., 2. xc, yc = 1., 1. nx, ny = 20, 20 pres = 150 k = 1 mesh = RectangleMesh(Point(xmin, ymin), Point(xmax, ymax), nx, ny) n = FacetNormal(mesh) # Class for mesh motion dU = PeriodicVelocity(xmin, xmax, dt, t, degree=1) Qcg = VectorFunctionSpace(mesh, 'CG', 1) boundaries = MeshFunction("size_t", mesh, mesh.topology().dim()-1) boundaries.set_all(0) leftbound = Left(xmin) leftbound.mark(boundaries, 99) ds = Measure('ds', domain=mesh, subdomain_data=boundaries) # Create function spaces Q_E_Rho = FiniteElement("DG", mesh.ufl_cell(), k) T_1 = FunctionSpace(mesh, 'DG', 0) Qbar_E = FiniteElement("DGT", mesh.ufl_cell(), k) Q_Rho = FunctionSpace(mesh, Q_E_Rho) Qbar = FunctionSpace(mesh, Qbar_E) phih, phih0 = Function(Q_Rho), Function(Q_Rho) phibar = Function(Qbar) # Advective velocity uh = Function(Qcg) uh.assign(Constant((0., 0.))) # Mesh velocity umesh = Function(Qcg) # Total velocity uadvect = uh-umesh # Now throw in the particles x = RandomRectangle(Point(xmin, ymin), Point(xmax, ymax)).generate([pres, pres]) s = assign_particle_values(x, GaussianPulse(center=(xc, yc), sigma=float(0.25), U=[0, 0], time=0., height=1., degree=3)) x = comm.bcast(x, root=0) s = comm.bcast(s, root=0) p = particles(x, [s], mesh) # Define projections problem FuncSpace_adv = {'FuncSpace_local': Q_Rho, 'FuncSpace_lambda': T_1, 'FuncSpace_bar': Qbar} FormsPDE = FormsPDEMap(mesh, FuncSpace_adv, ds=ds) forms_pde = FormsPDE.forms_theta_linear(phih0, uadvect, dt, Constant(1.0), zeta=Constant(0.)) pde_projection = PDEStaticCondensation(mesh, p, forms_pde['N_a'], forms_pde['G_a'], forms_pde['L_a'], forms_pde['H_a'], forms_pde['B_a'], forms_pde['Q_a'], forms_pde['R_a'], forms_pde['S_a'], [], 1) # Initialize the initial condition at mesh by an l2 projection lstsq_rho = l2projection(p, Q_Rho, 1) lstsq_rho.project(phih0.cpp_object()) for step in range(num_steps): # Compute old area at old configuration old_area = assemble(phih0*dx) # Pre-assemble rhs pde_projection.assemble_state_rhs() # Move mesh dU.compute_ubc() umesh.assign(project(dU, Qcg)) ALE.move(mesh, project(dU * dt, Qcg)) dU.update() # Relocate particles as a result of mesh motion # NOTE: if particles were advected themselve, # we had to run update_facets_info() here as well p.relocate() # Assemble left-hand side on new config, but not the right-hand side pde_projection.assemble(True, False) pde_projection.solve_problem(phibar.cpp_object(), phih.cpp_object(), 'mumps', 'none') # Needed to compute conservation, note that there # is an outgoing flux at left boundary new_area = assemble(phih*dx) gamma = conditional(ge(dot(uadvect, n), 0), 0, 1) bflux = assemble((1-gamma) * dot(uadvect, n) * phih * ds) # Update solution assign(phih0, phih) # Put assertion on (global) mass balance, local mass balance is # too time consuming but should pass also assert new_area - old_area + bflux * dt < 1e-12 # Assert that max value of phih stays close to 2 and # min value close to 0. This typically will fail if # we do not do a correct relocate of particles assert np.amin(phih.vector().get_local()) > -0.015 assert np.amax(phih.vector().get_local()) < 1.04