def deformation_vector(): from femorph import VolumeNormal n1 = VolumeNormal(multimesh.part(1)) bc = DirichletBC(VectorFunctionSpace(multimesh.part(1), "CG", 1), Constant((0, 0)), mfs[1], 2) bc.apply(n1.vector()) S = MultiMeshVectorFunctionSpace(multimesh, "CG", 1) s = MultiMeshFunction(S) s.assign_part(1, n1) return s
def deformation_vector(): from femorph import VolumeNormal n0 = VolumeNormal(multimesh.part(0)) S = MultiMeshVectorFunctionSpace(multimesh, "CG", 1) s = MultiMeshFunction(S) s.assign_part(0, n0) return s
def recompute_dJ(self): """ Create gradient expression for deformation algorithm """ # FIXME: probably only works with one obstacle # Recalculate barycenter and volume of obstacle self.geometric_quantities() self.integrand_list = [] dJ = 0 solver.dJ_form = [] for i in range(1, self.N): # Integrand of gradient x = SpatialCoordinate(self.multimesh.part(i)) u_i = self.u.part(i) dJ_stokes = -inner(grad(u_i), grad(u_i)) dJ_vol = -Constant(2 * self.vfac) * (self.Vol - self.Vol0) dJ_bar = Constant(2 * self.bfac) / self.Vol * ( (self.bx - x[0]) * self.bxoff + (self.by - x[1]) * self.byoff) integrand = dJ_stokes + dJ_vol + dJ_bar dDeform = Measure("ds", subdomain_data=self.mfs[i]) from femorph import VolumeNormal n = VolumeNormal(self.multimesh.part(i)) s = TestFunction(self.S[i]) self.integrand_list.append(n * integrand) dJ = inner(s, n) * integrand * dDeform(self.move_dict[i]["Deform"]) self.dJ_form.append(dJ)
def deformation_vector(multimesh): from femorph import VolumeNormal n2 = VolumeNormal(multimesh.part(0)) S_sm = VectorFunctionSpace(multimesh.part(0), "CG", 1) bc = DirichletBC(S_sm, n2, mfs[0], 2) bc2 = DirichletBC(S_sm, Constant((0, 0)), mfs[0], 1) us, vs = TrialFunction(S_sm), TestFunction(S_sm) a_ = inner(grad(us), grad(vs)) * dx + inner(us, vs) * dx deformation = Function(S_sm) solve(lhs(a_) == rhs(a_), deformation, bcs=[bc, bc2]) return deformation
def deformation_vector(multimesh): from femorph import VolumeNormal n0 = VolumeNormal(multimesh.part(0)) n1 = VolumeNormal(multimesh.part(1)) S = MultiMeshVectorFunctionSpace(multimesh, "CG", 1) mfs = [] for i in range(2): mvc = MeshValueCollection("size_t", multimesh.part(i), 1) with XDMFFile("meshes/mf_%d.xdmf" % i) as infile: infile.read(mvc, "name_to_read") mfs.append(cpp.mesh.MeshFunctionSizet(multimesh.part(i), mvc)) mf_0 = mfs[0] mf_1 = mfs[1] bcs = [ MultiMeshDirichletBC(S, n1, mf_1, 2, 1), MultiMeshDirichletBC(S, Constant((0, 0)), mf_0, 1, 0) ] #n1 n = FacetNormal(multimesh) h = 2.0 * Circumradius(multimesh) h = (h('+') + h('-')) / 2 us, vs = TrialFunction(S), TestFunction(S) a_s = inner(grad(us), grad(vs)) * dX a_IP = (-inner(dot(avg(grad(us)), n("+")), jump(vs)) - inner(dot(avg(grad(vs)), n("+")), jump(us)) + alpha / h * inner(jump(us), jump(vs))) * dI a_O = inner(jump(grad(us)), jump(grad(vs))) * dO a = a_s + a_IP + a_O L = inner(Constant((0, 0)), vs) * dX A = assemble_multimesh(a) b = assemble_multimesh(L) [bc.apply(A, b) for bc in bcs] S.lock_inactive_dofs(A, b) perturbation = MultiMeshFunction(S) solve(A, perturbation.vector(), b, 'lu') plot(perturbation.part(0)) plot(perturbation.part(1)) return perturbation
def eval_dJ(cable_positions): # Update mesh eval_J(cable_positions) dJ = [] # Solve adjoint equation adj = TrialFunction(V) v = TestFunction(V) constraint = inner(lmb * grad(adj), grad(v)) * dX - c * v * adj * dX # FIXME: Add derivative of alpha in ext bc constraint,only works for alpha=1 constraint += adj * 1 * v * ds # alpha_heat_transfer(T)*v*ds constraint += - inner(avg(lmb*grad(adj)), jump(v, n))*dI \ - inner(avg(lmb*grad(v)), jump(adj, n))*dI \ + alpha/h*jump(adj)*jump(v)*dI \ + beta*lmb*inner(jump(grad(adj)), jump(grad(v)))*dO constraint += objdT * v * dX A, b = assemble_multimesh(lhs(constraint)), assemble_multimesh( rhs(constraint)) V.lock_inactive_dofs(A, b) solve(A, adjT.vector(), b, 'lu') for i, (cable_mesh, cable_facet, cable_subdomain) in enumerate( zip(cable_meshes, cable_facets, cable_subdomains)): T_cable = T.part(i + 1, deepcopy=True) adjT_cable = adjT.part(i + 1, deepcopy=True) lmb_cable = lmb.part(i + 1, deepcopy=True) f_cable = f.part(i + 1, deepcopy=True) from femorph import VolumeNormal normal = VolumeNormal(cable_mesh, [0], cable_facet, [16, 17]) dJ_Surf = WeakCableShapeGradSurf(T_cable, adjT_cable, lmb_cable, c, f_cable, n=normal) dSc1 = Measure("dS", subdomain_data=cable_facet, subdomain_id=16) dSc2 = Measure("dS", subdomain_data=cable_facet, subdomain_id=17) gradx = assemble(normal[0] * dJ_Surf * dSc1 + normal[0] * dJ_Surf * dSc2 + Constant(0) * dx(domain=cable_mesh, subdomain_data=cable_subdomain)) grady = assemble(normal[1] * dJ_Surf * dSc1 + normal[1] * dJ_Surf * dSc2 + Constant(0) * dx(domain=cable_mesh, subdomain_data=cable_subdomain)) dJ.append(gradx) dJ.append(grady) return numpy.array(dJ)
def deformation_vector(mesh, S_sm): from femorph import VolumeNormal n2 = VolumeNormal(mesh) # S_sm = VectorFunctionSpace(mesh, "CG", 1) mvc = MeshValueCollection("size_t", mesh, 1) with XDMFFile("meshes/mf.xdmf") as infile: infile.read(mvc, "name_to_read") mf = cpp.mesh.MeshFunctionSizet(mesh, mvc) bc = DirichletBC(S_sm, n2, mf, 2) bc2 = DirichletBC(S_sm, Constant((0, 0)), mf, 1) us, vs = TrialFunction(S_sm), TestFunction(S_sm) a_ = inner(grad(us), grad(vs)) * dx + inner(us, vs) * dx deformation = Function(S_sm) solve(lhs(a_) == rhs(a_), deformation, bcs=[bc, bc2]) return deformation
def deformation_vector(): from femorph import VolumeNormal n1 = VolumeNormal(multimesh.part(1)) S_sm = VectorFunctionSpace(multimesh.part(1), "CG", 1) bcs = [ DirichletBC(S_sm, Constant((0, 0)), mfs[1], 2), DirichletBC(S_sm, n1, mfs[1], 1) ] u, v = TrialFunction(S_sm), TestFunction(S_sm) a = inner(grad(u), grad(v)) * dx l = inner(Constant((0., 0.)), v) * dx n = Function(S_sm) solve(a == l, n, bcs=bcs) S = MultiMeshVectorFunctionSpace(multimesh, "CG", 1) s = MultiMeshFunction(S) s.assign_part(1, n) return s
def deformation_vector(): n1 = (1 + x1[0] * sin(2 * pi * x1[1])) * VolumeNormal(multimesh.part(1)) S_sm = VectorFunctionSpace(multimesh.part(1), "CG", 1) # Note removing 0 dirichlet at dI introduces problems with the change in # the cut cell and overlap cell part. We do not have any way of describing # this movement bcs = [ DirichletBC(S_sm, n1, mfs[1], 2), DirichletBC(S_sm, Constant((0, 0)), mfs[1], 1) ] u, v = TrialFunction(S_sm), TestFunction(S_sm) a = inner(grad(u), grad(v)) * dx l = inner(Constant((0., 0.)), v) * dx n = Function(S_sm) solve(a == l, n, bcs=bcs) S = MultiMeshVectorFunctionSpace(multimesh, "CG", 1) s = MultiMeshFunction(S) s.assign_part(1, n) return s
def recompute_dJ(self): """ Create gradient expression for deformation algorithm """ # Recalculate barycenter and volume of obstacle self.compute_volume_bary() # Integrand of gradient x = SpatialCoordinate(mesh) dJ_stokes = -inner(grad(self.u), grad(self.u)) dJ_vol = - Constant(2*self.vfac)*(self.Vol-self.Vol0) dJ_bar = Constant(2*self.bfac)/self.Vol*((self.bx-x[0])*self.bx_off + (self.by-x[1])*self.by_off) self.integrand = dJ_stokes + dJ_vol + dJ_bar dDeform = Measure("ds", subdomain_data=self.mf) from femorph import VolumeNormal n = VolumeNormal(mesh) s = TestFunction(self.S) dJ = 0 # Sum up over all moving boundaries for marker in self.move_dict["Deform"]: dJ += inner(s,n)*self.integrand*dDeform(marker) self.dJ_form = dJ
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)