Example #1
0
def test_closed_boundary(advection_scheme):
    # FIXME: rk3 scheme does not bounces off the wall properly
    xmin, xmax = 0., 1.
    ymin, ymax = 0., 1.

    mesh = RectangleMesh(Point(xmin, ymin), Point(xmax, ymax), 10, 10)

    # Particle
    x = np.array([[0.975, 0.475]])

    # Given velocity field:
    vexpr = Constant((1., 0.))
    # Given time do_step:
    dt = 0.05
    # Then bounced position is
    x_bounced = np.array([[0.975, 0.475]])

    p = particles(x, [x, x], mesh)

    V = VectorFunctionSpace(mesh, "CG", 1)
    v = Function(V)
    v.assign(vexpr)

    # Different boundary parts
    bound_left = UnitSquareLeft()
    bound_right = UnitSquareRight()
    bound_top = UnitSquareTop()
    bound_bottom = UnitSquareBottom()

    # Mark all facets
    facet_marker = MeshFunction('size_t', mesh, mesh.topology().dim() - 1)
    facet_marker.set_all(0)

    # Mark as closed
    bound_right.mark(facet_marker, 1)

    # Mark other boundaries as open
    bound_left.mark(facet_marker, 2)
    bound_top.mark(facet_marker, 2)
    bound_bottom.mark(facet_marker, 2)

    if advection_scheme == 'euler':
        ap = advect_particles(p, V, v, facet_marker)
    elif advection_scheme == 'rk2':
        ap = advect_rk2(p, V, v, facet_marker)
    elif advection_scheme == 'rk3':
        ap = advect_rk3(p, V, v, facet_marker)
    else:
        assert False

    # Do one timestep, particle must bounce from wall of
    ap.do_step(dt)
    xpE = p.positions()

    # Check if particle correctly bounced off from closed wall
    xpE_root = comm.gather(xpE, root=0)
    if comm.rank == 0:
        xpE_root = np.float64(np.vstack(xpE_root))
        error = np.linalg.norm(x_bounced - xpE_root)
        assert(error < 1e-10)
Example #2
0
def test_advect_periodic(advection_scheme):
    # FIXME: this unit test is sensitive to the ordering of the particle
    # array, i.e. xp0_root and xpE_root may contain exactly the same entries
    # but only in a different order. This will return an error right now

    xmin, xmax = 0., 1.
    ymin, ymax = 0., 1.
    pres = 3

    mesh = RectangleMesh(Point(xmin, ymin), Point(xmax, ymax), 10, 10)

    lims = np.array([[xmin, xmin, ymin, ymax], [xmax, xmax, ymin, ymax],
                     [xmin, xmax, ymin, ymin], [xmin, xmax, ymax, ymax]])

    vexpr = Constant((1., 1.))
    V = VectorFunctionSpace(mesh, "CG", 1)

    x = RandomRectangle(Point(0.05, 0.05), Point(0.15, 0.15)).generate([pres, pres])
    x = comm.bcast(x, root=0)
    dt = 0.05

    v = Function(V)
    v.assign(vexpr)

    p = particles(x, [x*0, x**2], mesh)

    if advection_scheme == 'euler':
        ap = advect_particles(p, V, v, 'periodic', lims.flatten())
    elif advection_scheme == 'rk2':
        ap = advect_rk2(p, V, v, 'periodic', lims.flatten())
    elif advection_scheme == 'rk3':
        ap = advect_rk3(p, V, v, 'periodic', lims.flatten())
    else:
        assert False

    xp0 = p.positions()
    t = 0.
    while t < 1.-1e-12:
        ap.do_step(dt)
        t += dt
    xpE = p.positions()

    # Check if position correct
    xp0_root = comm.gather(xp0, root=0)
    xpE_root = comm.gather(xpE, root=0)

    num_particles = p.number_of_particles()

    if comm.Get_rank() == 0:
        xp0_root = np.float32(np.vstack(xp0_root))
        xpE_root = np.float32(np.vstack(xpE_root))

        # Sort on x positions
        xp0_root = xp0_root[xp0_root[:, 0].argsort(), :]
        xpE_root = xpE_root[xpE_root[:, 0].argsort(), :]

        error = np.linalg.norm(xp0_root - xpE_root)
        assert error < 1e-10
        assert num_particles - pres**2 == 0
def test_advect_periodic(advection_scheme):
    xmin, ymin, zmin = 0., 0., 0.
    xmax, ymax, zmax = 1., 1., 1.
    pres = 10

    mesh = UnitCubeMesh(10, 10, 10)

    lims = np.array([[xmin, xmin, ymin, ymax, zmin, zmax],
                     [xmax, xmax, ymin, ymax, zmin, zmax],
                     [xmin, xmax, ymin, ymin, zmin, zmax],
                     [xmin, xmax, ymax, ymax, zmin, zmax],
                     [xmin, xmax, ymin, ymax, zmin, zmin],
                     [xmin, xmax, ymin, ymax, zmax, zmax]])

    vexpr = Constant((1., 1., 1.))
    V = VectorFunctionSpace(mesh, "CG", 1)
    v = Function(V)
    v.assign(vexpr)

    x = RandomBox(Point(0., 0., 0.), Point(1., 1.,
                                           1.)).generate([pres, pres, pres])
    x = comm.bcast(x, root=0)
    dt = 0.05

    p = particles(x, [x * 0, x**2], mesh)

    if advection_scheme == 'euler':
        ap = advect_particles(p, V, v, 'periodic', lims.flatten())
    elif advection_scheme == 'rk2':
        ap = advect_rk2(p, V, v, 'periodic', lims.flatten())
    elif advection_scheme == 'rk3':
        ap = advect_rk3(p, V, v, 'periodic', lims.flatten())
    else:
        assert False

    xp0 = p.positions()
    t = 0.
    while t < 1. - 1e-12:
        ap.do_step(dt)
        t += dt
    xpE = p.positions()

    xp0_root = comm.gather(xp0, root=0)
    xpE_root = comm.gather(xpE, root=0)

    assert len(xp0) == len(xpE)
    num_particles = p.number_of_particles()

    if comm.Get_rank() == 0:
        xp0_root = np.float32(np.vstack(xp0_root))
        xpE_root = np.float32(np.vstack(xpE_root))

        # Sort on x positions
        xp0_root = xp0_root[xp0_root[:, 0].argsort(), :]
        xpE_root = xpE_root[xpE_root[:, 0].argsort(), :]

        error = np.linalg.norm(xp0_root - xpE_root)
        assert error < 1e-10
        assert num_particles - pres**3 == 0
def test_open_boundary(advection_scheme):
    xmin, xmax = 0.0, 1.0
    ymin, ymax = 0.0, 1.0
    pres = 3

    mesh = RectangleMesh(Point(xmin, ymin), Point(xmax, ymax), 10, 10)

    # Particle
    x = RandomRectangle(Point(0.955, 0.45), Point(1.0,
                                                  0.55)).generate([pres, pres])
    x = comm.bcast(x, root=0)

    # Given velocity field:
    vexpr = Constant((1.0, 1.0))
    # Given time do_step:
    dt = 0.05

    p = particles(x, [x, x], mesh)

    V = VectorFunctionSpace(mesh, "CG", 1)
    v = Function(V)
    v.assign(vexpr)

    # Different boundary parts
    bound_left = UnitSquareLeft()
    bound_right = UnitSquareRight()
    bound_top = UnitSquareTop()
    bound_bottom = UnitSquareBottom()

    # Mark all facets
    facet_marker = MeshFunction("size_t", mesh, mesh.topology().dim() - 1)
    facet_marker.set_all(0)

    # Mark as open
    bound_right.mark(facet_marker, 2)

    # Mark other boundaries as closed
    bound_left.mark(facet_marker, 1)
    bound_top.mark(facet_marker, 1)
    bound_bottom.mark(facet_marker, 1)

    if advection_scheme == "euler":
        ap = advect_particles(p, V, v, facet_marker)
    elif advection_scheme == "rk2":
        ap = advect_rk2(p, V, v, facet_marker)
    elif advection_scheme == "rk3":
        ap = advect_rk3(p, V, v, facet_marker)
    else:
        assert False

    # Do one timestep, particle must bounce from wall of
    ap.do_step(dt)
    num_particles = p.number_of_particles()

    # Check if all particles left domain
    if comm.rank == 0:
        assert (num_particles == 0)
def test_advect_periodic_facet_marker(advection_scheme):
    xmin, xmax = 0.0, 1.0
    ymin, ymax = 0.0, 1.0

    mesh = RectangleMesh(Point(xmin, ymin), Point(xmax, ymax), 10, 10)
    facet_marker = MeshFunction("size_t", mesh, mesh.topology().dim() - 1)
    facet_marker.set_all(0)
    boundaries = Boundaries()
    boundaries.mark(facet_marker, 3)

    lims = np.array([
        [xmin, xmin, ymin, ymax],
        [xmax, xmax, ymin, ymax],
        [xmin, xmax, ymin, ymin],
        [xmin, xmax, ymax, ymax],
    ])

    vexpr = Constant((1.0, 1.0))
    V = VectorFunctionSpace(mesh, "CG", 1)

    x = RandomRectangle(Point(0.05, 0.05), Point(0.15, 0.15)).generate([3, 3])
    x = comm.bcast(x, root=0)
    dt = 0.05

    v = Function(V)
    v.assign(vexpr)

    p = particles(x, [x * 0, x**2], mesh)

    if advection_scheme == "euler":
        ap = advect_particles(p, V, v, facet_marker, lims.flatten())
    elif advection_scheme == "rk2":
        ap = advect_rk2(p, V, v, facet_marker, lims.flatten())
    elif advection_scheme == "rk3":
        ap = advect_rk3(p, V, v, facet_marker, lims.flatten())
    else:
        assert False

    xp0 = p.positions()
    t = 0.0
    while t < 1.0 - 1e-12:
        ap.do_step(dt)
        t += dt
    xpE = p.positions()

    # Check if position correct
    xp0_root = comm.gather(xp0, root=0)
    xpE_root = comm.gather(xpE, root=0)

    if comm.Get_rank() == 0:
        xp0_root = np.float32(np.vstack(xp0_root))
        xpE_root = np.float32(np.vstack(xpE_root))
        error = np.linalg.norm(xp0_root - xpE_root)
        assert error < 1e-10
def test_bounded_domain_boundary(xlims, ylims, advection_scheme):
    xmin, xmax = xlims
    ymin, ymax = ylims
    pres = 1

    mesh = RectangleMesh(Point(xmin, ymin), Point(xmax, ymax), 10, 10)

    ymin += 0.0025
    lims = np.array([xmin, xmax, ymin, ymax])

    v_arr = np.array([-1.0, -1.0])
    vexpr = Constant(v_arr)
    V = VectorFunctionSpace(mesh, "CG", 1)

    x = RandomRectangle(Point(0.05, 0.05), Point(0.15,
                                                 0.15)).generate([pres, pres])
    dt = 0.005

    v = Function(V)
    v.assign(vexpr)

    p = particles(x, [x], mesh)

    if advection_scheme == 'euler':
        ap = advect_particles(p, V, v, 'bounded', lims.flatten())
    elif advection_scheme == 'rk2':
        ap = advect_rk2(p, V, v, 'bounded', lims.flatten())
    elif advection_scheme == 'rk3':
        ap = advect_rk3(p, V, v, 'bounded', lims.flatten())
    else:
        assert False

    original_num_particles = p.number_of_particles()
    t = 0.
    while t < 3.0 - 1e-12:
        ap.do_step(dt)
        t += dt

        assert p.number_of_particles() == original_num_particles

        xpn = np.array(p.get_property(0)).reshape((-1, 2))
        x0 = np.array(p.get_property(1)).reshape((-1, 2))

        analytical_position = x0 + t * v_arr

        analytical_position[:, 0] = np.maximum(
            np.minimum(xmax, analytical_position[:, 0]), xmin)
        analytical_position[:, 1] = np.maximum(
            np.minimum(ymax, analytical_position[:, 1]), ymin)

        error = np.abs(xpn - analytical_position)

        assert np.all(np.abs(error) < 1e-12)
def test_advect_open(advection_scheme):
    pres = 3

    mesh = UnitCubeMesh(10, 10, 10)

    # Particle
    x = RandomBox(Point(0.955, 0.45, 0.5),
                  Point(0.99, 0.55, 0.6)).generate([pres, pres, pres])
    x = comm.bcast(x, root=0)

    # Given velocity field:
    vexpr = Constant((1.0, 1.0, 1.0))
    # Given time do_step:
    dt = 0.05

    p = particles(x, [x, x], mesh)

    V = VectorFunctionSpace(mesh, "CG", 1)
    v = Function(V)
    v.assign(vexpr)

    # Different boundary parts
    bounds = Boundaries()
    bound_right = UnitCubeRight()

    # Mark all facets
    facet_marker = MeshFunction("size_t", mesh, mesh.topology().dim() - 1)
    facet_marker.set_all(0)
    bounds.mark(facet_marker, 1)
    bound_right.mark(facet_marker, 2)

    # Mark as open
    bound_right.mark(facet_marker, 2)

    if advection_scheme == "euler":
        ap = advect_particles(p, V, v, facet_marker)
    elif advection_scheme == "rk2":
        ap = advect_rk2(p, V, v, facet_marker)
    elif advection_scheme == "rk3":
        ap = advect_rk3(p, V, v, facet_marker)
    else:
        assert False

    # Do one timestep, particle must bounce from wall of
    ap.do_step(dt)
    num_particles = p.number_of_particles()

    # Check if all particles left domain
    if comm.rank == 0:
        assert num_particles == 0
Example #8
0
def test_advect_particle(advection_scheme):
    if comm.rank == 0:
        print('Run advect_particle')

    # Rotate one particle, and compute the error
    mesh = UnitSquareMesh(10, 10)

    # Particle
    x = np.array([[0.25, 0.25]])
    dt_list = [0.08, 0.04, 0.02, 0.01, 0.005]

    # Velocity field
    vexpr = Expression(('-pi*(x[1] - 0.5)', 'pi*(x[0]-0.5)'), degree=3)
    V = VectorFunctionSpace(mesh, "CG", 1)
    v = Function(V)
    v.assign(vexpr)

    error_list = []

    for dt in dt_list:
        p = particles(x, [x, x], mesh)
        if advection_scheme == 'euler':
            ap = advect_particles(p, V, v, 'closed')
        elif advection_scheme == 'rk2':
            ap = advect_rk2(p, V, v, 'closed')
        elif advection_scheme == 'rk3':
            ap = advect_rk3(p, V, v, 'closed')
        else:
            assert False

        xp_0 = p.positions()
        t = 0.
        while t < 2.-1e-12:
            ap.do_step(dt)
            t += dt

        xp_end = p.positions()
        error_list.append(np.linalg.norm(xp_0 - xp_end))

    if not all(eps == 0 for eps in error_list):
        rate = compute_convergence(dt_list, error_list)
        if advection_scheme == 'euler':
            # First order for euler
            assert any(i > 0.9 for i in rate)
        elif advection_scheme == 'rk2':
            # Second order for rk2
            assert any(i > 1.95 for i in rate)
        elif advection_scheme == 'rk3':
            # Third order for rk3
            assert any(i > 2.9 for i in rate)
# Function space and velocity field
W = FunctionSpace(mesh, 'DG', k)
psi_h = Function(W)

V = VectorFunctionSpace(mesh, 'DG', 3)
uh = Function(V)
uh.assign(Expression(('-Uh*x[1]', 'Uh*x[0]'), Uh=Uh, degree=3))

# Generate particles
x = RandomCircle(Point(x0, y0), r).generate([pres, pres])
s = assign_particle_values(x, psi0_expr)

p = particles(x, [s], mesh)
# Initialize advection class, use RK3 scheme
ap = advect_rk3(p, V, uh, 'closed')
# Init projection
lstsq_psi = l2projection(p, W, 1)

# Do projection to get initial field
lstsq_psi.project(psi_h.cpp_object(), lb, ub)
AD = AddDelete(p, 10, 20, [psi_h], [1], [lb, ub])

step = 0
t = 0.
area_0 = assemble(psi_h * dx)
timer = Timer()
timer.start()

outfile.write(psi_h, t)
while step < num_steps:
rhop = assign_particle_values(x, initial_density)

# Increment requires dup to be stored, init zero
dup = up

p = particles(x, [rhop, up, dup], mesh)

# Init rho0 field
lstsq_rho = l2projection(p, Q_Rho, 1)
lstsq_rho.project(rho0, float(rho2), float(rho1))

# Initialize l2 projection for specific momentum
lstsq_u = l2projection(p, W_2, 2)

# Initialize advection class
ap = advect_rk3(p, W_2, Udiv, "closed")

# Set-up boundary conditions (free slip)
boundaries = MeshFunction("size_t", mesh, mesh.topology().dim() - 1)
boundaries.set_all(0)
all_bounds = Boundaries()
all_bounds.mark(boundaries, 98)
ds = Measure("ds", domain=mesh, subdomain_data=boundaries)

# Set-up density projection
funcspaces_rho = {
    "FuncSpace_local": Q_Rho,
    "FuncSpace_lambda": T_1,
    "FuncSpace_bar": Qbar
}
forms_rho = FormsPDEMap(mesh, funcspaces_rho).forms_theta_linear(
Example #11
0
x = RandomRectangle(Point(xmin, ymin), Point(xmax,
                                             ymax)).generate([pres, pres])
s = assign_particle_values(x, u_exact)

lims = np.array([
    [xmin, xmin, ymin, ymax],
    [xmax, xmax, ymin, ymax],
    [xmin, xmax, ymin, ymin],
    [xmin, xmax, ymax, ymax],
])

# Particle specific momentum is stored at slot 1
# the second slot will be to store old velocities at particle level
property_idx = 1
p = particles(x, [s, s], mesh)
ap = advect_rk3(p, W_2, Udiv, "periodic", lims.flatten())

# Particle management
AD = AddDelete(p, 10, 20, [Udiv, duh0])

# Forms PDE map
funcspace_dict = {
    "FuncSpace_local": W_2,
    "FuncSpace_lambda": T_2,
    "FuncSpace_bar": Wbar_2
}
forms_adv = FormsPDEMap(mesh, funcspace_dict).forms_theta_nlinear(
    u0_a,
    ubar0_a,
    dt,
    theta_map=Constant(1.0),
Example #12
0
    if remesh_elastic == False:

        Vdg = FunctionSpace(model.mesh.mesh, 'DG', 1)
        Vcg = FunctionSpace(model.mesh.mesh, 'DG', 1)
        (xp, pstrain, ptemp,
         pepsII) = (p.return_property(mesh, 0), p.return_property(mesh, 1),
                    p.return_property(mesh, 2), p.return_property(mesh, 3))
        del p
        p = particles(xp, [pstrain, ptemp, pepsII], model.mesh.mesh)
    else:
        p.relocate()

    # Advect particles -- Turn this on to advect particles now that it is removed from Stokes script
    Vdg = FunctionSpace(model.mesh.mesh, 'DG', 1)
    ap = advect_rk3(p, model.vector2, model.u_k, "open")
    ap.do_step(time_step)
    AD = AddDelete(p, p_min, p_max, [
        interpolate(model.strain, Vdg),
        interpolate(model.temp, Vdg),
        interpolate(model.epsII, Vdg)
    ])  # Sweep over mesh to delete/insert particles
    AD.do_sweep()

    # Plotting
    (xp, pstrain, ptemp,
     pepsII) = (p.return_property(mesh, 0), p.return_property(mesh, 1),
                p.return_property(mesh, 2), p.return_property(mesh, 3))
    pstrain[xp[:, 0] < xyield_min] = 0.0
    p.change_property(pstrain, 1)
Example #13
0
                                        sigma=float(sigma),
                                        U=[Uh, Uh],
                                        time=0.0,
                                        height=1.0,
                                        degree=3)

        # Generate particles
        x = RandomCircle(Point(x0, y0), r).generate([pres, pres])
        s = np.zeros((len(x), 1), dtype=np.float_)

        # Initialize particles with position x and scalar property s at the mesh
        p = particles(x, [s], mesh)
        property_idx = 1  # Scalar quantity is stored at slot 1

        # Initialize advection class, use RK3 scheme
        ap = advect_rk3(p, V, uh, "open")

        # Define the variational (projection problem)
        W_e = FiniteElement("DG", mesh.ufl_cell(), k)
        T_e = FiniteElement("DG", mesh.ufl_cell(), 0)
        Wbar_e = FiniteElement("DGT", mesh.ufl_cell(), k)

        W = FunctionSpace(mesh, W_e)
        T = FunctionSpace(mesh, T_e)
        Wbar = FunctionSpace(mesh, Wbar_e)

        psi_h, psi0_h = Function(W), Function(W)
        lambda_h = Function(T)
        psibar_h = Function(Wbar)

        # Boundary conditions
                                         amplitude=1.0, degree=1))
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, beta_map=Constant(1e-8))
forms_pde = FormsPDE.forms_theta_linear(phih0, uadvect, dt, Constant(1.0), zeta=Constant(0.),
                                        h=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)

ap = advect_rk3(p, V, uh, 'open')

# Initialize the initial condition at mesh by an l2 projection
lstsq_rho = l2projection(p, Q_Rho, 1)
lstsq_rho.project(phih0)
outfile << phih0

for step in range(num_steps):
    u_expr.t = step * float(dt)
    u_expre_neg.t = step * float(dt)

    uh.assign(u_expr)

    # Compute area at old configuration
    old_area = assemble(phih0*dx)
rhop = assign_particle_values(x, initial_density)

# Increment requires dup to be stored, init zero
dup = up

p = particles(x, [rhop, up, dup], mesh)

# Init rho0 field
lstsq_rho = l2projection(p, Q_Rho, 1)
lstsq_rho.project(rho0, float(rho2), float(rho1))

# Initialize l2 projection for specific momentum
lstsq_u = l2projection(p, W_2, 2)

# Initialize advection class
ap = advect_rk3(p, W_2, Udiv, 'closed')

# Set-up boundary conditions (free slip)
boundaries = MeshFunction("size_t", mesh, mesh.topology().dim() - 1)
boundaries.set_all(0)
all_bounds = Boundaries()
all_bounds.mark(boundaries, 98)
ds = Measure('ds', domain=mesh, subdomain_data=boundaries)

# Set-up density projection
funcspaces_rho = {
    'FuncSpace_local': Q_Rho,
    'FuncSpace_lambda': T_1,
    'FuncSpace_bar': Qbar
}
forms_rho = FormsPDEMap(mesh, funcspaces_rho).forms_theta_linear(
Example #16
0
ubar0_a.assign(u_exact)
Udiv.assign(u_exact)

# Initialize particles
x = RandomRectangle(Point(xmin, ymin), Point(xmax,
                                             ymax)).generate([pres, pres])
s = assign_particle_values(x, u_exact)

lims = np.array([[xmin, xmin, ymin, ymax], [xmax, xmax, ymin, ymax],
                 [xmin, xmax, ymin, ymin], [xmin, xmax, ymax, ymax]])

# Particle specific momentum is stored at slot 1
# the second slot will be to store old velocities at particle level
property_idx = 1
p = particles(x, [s, s], mesh)
ap = advect_rk3(p, W_2, Udiv, 'periodic', lims.flatten())

# Particle management
AD = AddDelete(p, 10, 20, [Udiv, duh0])

# Forms PDE map
funcspace_dict = {
    'FuncSpace_local': W_2,
    'FuncSpace_lambda': T_2,
    'FuncSpace_bar': Wbar_2
}
forms_adv = FormsPDEMap(mesh, funcspace_dict).forms_theta_nlinear(
    u0_a,
    ubar0_a,
    dt,
    theta_map=Constant(1.0),
Example #17
0
Rb = Constant(1.0)
eta_top = Constant(1.0)
eta_bottom = Constant(0.01)
eta = eta_bottom + phi * (eta_top - eta_bottom)
forms_stokes = FormsStokes(mesh, mixedL, mixedG, alpha) \
    .forms_steady(eta, Rb * phi * Constant((0, -1, 0)))

ssc = StokesStaticCondensation(mesh,
                               forms_stokes['A_S'], forms_stokes['G_S'],
                               forms_stokes['B_S'],
                               forms_stokes['Q_S'], forms_stokes['S_S'])

# Particle advector
C_CFL = 0.5
hmin = MPI.min(comm, mesh.hmin())
ap = advect_rk3(ptcls, u_vec.function_space(), u_vec, "closed")


# Write particles and their values to XDMF file
particles_directory = "./particles/"
points_list = list(Point(*pp) for pp in ptcls.positions())
particles_values = ptcls.get_property(property_idx)
XDMFFile(os.path.join(particles_directory, "step%.4d.xdmf" % 0)) \
    .write(points_list, particles_values)

n_particles = MPI.sum(comm, len(points_list))
info("Solving with %d particles" % n_particles)

# Write the intitial compostition field to XDMF file
XDMFFile("composition.xdmf").write_checkpoint(phi, "composition", float(t), append=False)
conservation0 = assemble(phi * dx)
# Function space and velocity field
W = FunctionSpace(mesh, "DG", k)
(psi_h0, psi_h) = (Function(W), Function(W))

V = VectorFunctionSpace(mesh, "DG", 3)
uh = Function(V)
uh.assign(Expression(("-Uh*x[1]", "Uh*x[0]"), Uh=Uh, degree=3))

# Generate particles
x = RandomCircle(Point(x0, y0), r).generate([pres, pres])
s = assign_particle_values(x, psi0_expr)
p = particles(x, [s], mesh)

# Initialize advection class, use RK3 scheme
ap = advect_rk3(p, V, uh, "closed")

# Init projection and get initial condition
lstsq_psi = l2projection(p, W, 1)
lstsq_psi.project(psi_h, lb, ub)
assign(psi_h0, psi_h)

step = 0
t = 0.0
area_0 = assemble(psi_h * dx)
(psi_h_min, psi_h_max) = (0.0, 0.0)

timer = Timer()
timer.start()

# Write initial field and dump initial particle field