Beispiel #1
0
 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])
Beispiel #2
0
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 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
Beispiel #4
0
    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)
Beispiel #5
0
 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)
Beispiel #6
0
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
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)
Beispiel #9
0
 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()
Beispiel #11
0
        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)
Beispiel #12
0
    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)
Beispiel #13
0
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"])
Beispiel #14
0
 def move_mesh(self):
     log(PROGRESS, "moving mesh")
     displacement = self.compute_displacement()
     ALE.move(self.mesh, displacement)
Beispiel #15
0
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