コード例 #1
0
ファイル: ellipticCauchyPro.py プロジェクト: jjx323/VIfIP
    def eva(self, num):
        # construct basis functions, Set num points corresponding to num basis functions
        basPoints = np.linspace(0, 1, num)
        dx = basPoints[1] - basPoints[0]
        aa, bb, cc = -dx, 0.0, dx
        for x_p in basPoints:
            self.theta.append(
                fe.interpolate(
                    fe.Expression(
                        'x[0] < a || x[0] > c ? 0 : (x[0] >=a && x[0] <= b ? (x[0]-a)/(b-a) : 1-(x[0]-b)/(c-b))',
                        degree=2,
                        a=aa,
                        b=bb,
                        c=cc), self.Vc))
            aa, bb, cc = aa + dx, bb + dx, cc + dx

        u_trial, u_test = fe.TrialFunction(self.Vu), fe.TestFunction(self.Vu)
        left = fe.inner(self.al * fe.nabla_grad(u_trial),
                        fe.nabla_grad(u_test)) * fe.dx
        right = self.f * u_test * fe.dx

        def boundaryD(x, on_boundary):
            return on_boundary and fe.near(x[1], 1.0)

        for i in range(num):
            uH = fe.Function(self.Vu)
            bcD = fe.DirichletBC(self.Vu, self.theta[i], boundaryD)
            left_m, right_m = fe.assemble_system(left, right, bcD)
            fe.solve(left_m, uH.vector(), right_m)
            self.sol.append(uH)
コード例 #2
0
 def geneForwardMatrix(self, q_fun=fe.Constant(0.0), fR=fe.Constant(0.0), \
                       fI=fe.Constant(0.0)):
     if self.haveFunctionSpace == False:
         self.geneFunctionSpace()
         
     xx, yy, dPML, sig0_, p_ = self.domain.xx, self.domain.yy, self.domain.dPML,\
                               self.domain.sig0, self.domain.p
     # define the coefficents induced by PML
     sig1 = fe.Expression('x[0] > x1 && x[0] < x1 + dd ? sig0*pow((x[0]-x1)/dd, p) : (x[0] < 0 && x[0] > -dd ? sig0*pow((-x[0])/dd, p) : 0)', 
                  degree=3, x1=xx, dd=dPML, sig0=sig0_, p=p_)
     sig2 = fe.Expression('x[1] > x2 && x[1] < x2 + dd ? sig0*pow((x[1]-x2)/dd, p) : (x[1] < 0 && x[1] > -dd ? sig0*pow((-x[1])/dd, p) : 0)', 
                  degree=3, x2=yy, dd=dPML, sig0=sig0_, p=p_)
     
     sR = fe.as_matrix([[(1+sig1*sig2)/(1+sig1*sig1), 0.0], [0.0, (1+sig1*sig2)/(1+sig2*sig2)]])
     sI = fe.as_matrix([[(sig2-sig1)/(1+sig1*sig1), 0.0], [0.0, (sig1-sig2)/(1+sig2*sig2)]])
     cR = 1 - sig1*sig2
     cI = sig1 + sig2
     
     # define the coefficients with physical meaning
     angl_fre = self.kappa*np.pi
     angl_fre2 = fe.Constant(angl_fre*angl_fre)
     
     # define equations
     u_ = fe.TestFunction(self.V)
     du = fe.TrialFunction(self.V)
     
     u_R, u_I = fe.split(u_)
     duR, duI = fe.split(du)
     
     def sigR(v):
         return fe.dot(sR, fe.nabla_grad(v))
     def sigI(v):
         return fe.dot(sI, fe.nabla_grad(v))
     
     F1 = - fe.inner(sigR(duR)-sigI(duI), fe.nabla_grad(u_R))*(fe.dx) \
         - fe.inner(sigR(duI)+sigI(duR), fe.nabla_grad(u_I))*(fe.dx) \
         - fR*u_R*(fe.dx) - fI*u_I*(fe.dx)
     
     a2 = fe.inner(angl_fre2*q_fun*(cR*duR-cI*duI), u_R)*(fe.dx) \
          + fe.inner(angl_fre2*q_fun*(cR*duI+cI*duR), u_I)*(fe.dx) \
     
     # define boundary conditions
     def boundary(x, on_boundary):
         return on_boundary
     
     bc = [fe.DirichletBC(self.V.sub(0), fe.Constant(0.0), boundary), \
           fe.DirichletBC(self.V.sub(1), fe.Constant(0.0), boundary)]
     
     a1, L1 = fe.lhs(F1), fe.rhs(F1)
     self.u = fe.Function(self.V)
     self.A1 = fe.assemble(a1)
     self.b1 = fe.assemble(L1)
     self.A2 = fe.assemble(a2)
     bc[0].apply(self.A1, self.b1)
     bc[1].apply(self.A1, self.b1)
     bc[0].apply(self.A2)
     bc[1].apply(self.A2)
     self.A = self.A1 + self.A2
コード例 #3
0
ファイル: ellipticCauchyPro.py プロジェクト: jjx323/VIfIP
def calTrueSol(para):
    nx, ny = para['mesh_N'][0], para['mesh_N'][1]
    mesh = fe.UnitSquareMesh(nx, ny)
    Vu = fe.FunctionSpace(mesh, 'P', para['P'])
    Vc = fe.FunctionSpace(mesh, 'P', para['P'])
    al = fe.Constant(para['alpha'])
    f = fe.Expression(para['f'], degree=5)
    q1 = fe.interpolate(fe.Expression(para['q1'], degree=5), Vc)
    q2 = fe.interpolate(fe.Expression(para['q2'], degree=5), Vc)
    q3 = fe.interpolate(fe.Expression(para['q3'], degree=5), Vc)
    theta = fe.interpolate(fe.Expression(para['q4'], degree=5), Vc)

    class BoundaryX0(fe.SubDomain):
        def inside(self, x, on_boundary):
            return on_boundary and fe.near(x[0], 0.0)

    class BoundaryX1(fe.SubDomain):
        def inside(self, x, on_boundary):
            return on_boundary and fe.near(x[0], 1.0)

    class BoundaryY0(fe.SubDomain):
        def inside(self, x, on_boundary):
            return on_boundary and fe.near(x[1], 0.0)

    class BoundaryY1(fe.SubDomain):
        def inside(self, x, on_boundary):
            return on_boundary and fe.near(x[1], 1.0)

    boundaries = fe.MeshFunction('size_t', mesh, mesh.topology().dim() - 1)
    boundaries.set_all(0)
    bc0, bc1, bc2, bc3 = BoundaryX0(), BoundaryX1(), BoundaryY0(), BoundaryY1()
    bc0.mark(boundaries, 1)
    bc1.mark(boundaries, 2)
    bc2.mark(boundaries, 3)
    bc3.mark(boundaries, 4)

    domains = fe.MeshFunction("size_t", mesh, mesh.topology().dim())
    domains.set_all(0)

    bcD = fe.DirichletBC(Vu, theta, boundaries, 4)
    dx = fe.Measure('dx', domain=mesh, subdomain_data=domains)
    ds = fe.Measure('ds', domain=mesh, subdomain_data=boundaries)

    u_trial, u_test = fe.TrialFunction(Vu), fe.TestFunction(Vu)
    u = fe.Function(Vu)
    left = fe.inner(al * fe.nabla_grad(u_trial), fe.nabla_grad(u_test)) * dx
    right = f * u_test * dx + (q1 * u_test * ds(1) + q2 * u_test * ds(2) +
                               q3 * u_test * ds(3))

    left_m, right_m = fe.assemble_system(left, right, bcD)
    fe.solve(left_m, u.vector(), right_m)

    return u
コード例 #4
0
ファイル: ellipticCauchyPro.py プロジェクト: jjx323/VIfIP
    def eva(self):
        # construct solutions corresponding to the basis functions
        class BoundaryX0(fe.SubDomain):
            def inside(self, x, on_boundary):
                return on_boundary and fe.near(x[0], 0.0)

        class BoundaryX1(fe.SubDomain):
            def inside(self, x, on_boundary):
                return on_boundary and fe.near(x[0], 1.0)

        class BoundaryY0(fe.SubDomain):
            def inside(self, x, on_boundary):
                return on_boundary and fe.near(x[1], 0.0)

        class BoundaryY1(fe.SubDomain):
            def inside(self, x, on_boundary):
                return on_boundary and fe.near(x[1], 1.0)

        boundaries = fe.MeshFunction('size_t', self.mesh,
                                     self.mesh.topology().dim() - 1)
        boundaries.set_all(0)
        bc0, bc1, bc2, bc3 = BoundaryX0(), BoundaryX1(), BoundaryY0(
        ), BoundaryY1()
        bc0.mark(boundaries, 1)
        bc1.mark(boundaries, 2)
        bc2.mark(boundaries, 3)
        bc3.mark(boundaries, 4)

        domains = fe.MeshFunction("size_t", self.mesh,
                                  self.mesh.topology().dim())
        domains.set_all(0)

        dx = fe.Measure('dx', domain=self.mesh, subdomain_data=domains)
        ds = fe.Measure('ds', domain=self.mesh, subdomain_data=boundaries)

        u_trial, u_test = fe.TrialFunction(self.Vu), fe.TestFunction(self.Vu)
        left = fe.inner(fe.nabla_grad(u_trial), fe.nabla_grad(u_test)) * dx
        right = self.f * u_test * dx + (self.q1 * u_test * ds(1) +
                                        self.q2 * u_test * ds(2) +
                                        self.q3 * u_test * ds(3))
        bcD = fe.DirichletBC(self.Vu, self.theta, boundaries, 4)
        left_m, right_m = fe.assemble_system(left, right, bcD)
        fe.solve(left_m, self.u.vector(), right_m)
コード例 #5
0
f   = fs.Constant((0, 0))
k   = fs.Constant(dt)
mu  = fs.Constant(mu)
rho = fs.Constant(rho)

# Define strain-rate tensor
def epsilon(u):
    return fs.sym(fs.nabla_grad(u))

# Define stress tensor
def sigma(u, p):
    return 2*mu*epsilon(u) - p*fs.Identity(len(u))

# Define variational problem for step 1 (Tentative velocity step)
F1 = rho*fs.dot((u - u_n) / k, v)*fs.dx + \
    rho*fs.dot(fs.dot(u_n, fs.nabla_grad(u_n)), v)*fs.dx \
  + fs.inner(sigma(U, p_n), epsilon(v))*fs.dx \
  + fs.dot(p_n*n, v)*fs.ds - fs.dot(mu*fs.nabla_grad(U)*n, v)*fs.ds \
  - fs.dot(f, v)*fs.dx
a1 = fs.lhs(F1)
L1 = fs.rhs(F1)

# Define variational problem for step 2 (Pressure correction step)
a2 = fs.dot(fs.nabla_grad(p),   fs.nabla_grad(q))*fs.dx
L2 = fs.dot(fs.nabla_grad(p_n), fs.nabla_grad(q))*fs.dx \
        - (1/k)*fs.div(u_)*q*fs.dx

# Define variational problem for step 3 (Velocity correction step)
a3 = fs.dot(u,  v)*fs.dx
L3 = fs.dot(u_, v)*fs.dx - k*fs.dot(fs.nabla_grad(p_ - p_n), v)*fs.dx
コード例 #6
0
 def b(u, v, w):
     return 0.5 * (fn.inner(fn.dot(u, fn.nabla_grad(v)), w) -
                   fn.inner(fn.dot(u, fn.nabla_grad(w)), v))
コード例 #7
0
 def contract(u, v):
     return fn.inner(fn.nabla_grad(u), fn.nabla_grad(v))
コード例 #8
0
    def solve(self):
        # TODO: when FEniCS ported to Python3, this should be exist_ok
        try:
            os.makedirs('results')
        except OSError:
            pass

        z, w = (self.z, self.w)
        u0 = d.Constant(0.0)

        # Define the linear and bilinear forms
        L = u0 * w * dx

        # Define useful functions
        cond = d.Function(self.DV)
        U = d.Function(self.V)

        # Initialize the max_e vector, that will store the cumulative max e values
        max_e = d.Function(self.V)
        max_e.vector()[:] = 0.0
        max_e.rename("max_E", "Maximum energy deposition by location")
        max_e_file = d.File("results/%s-max_e.pvd" % input_mesh)
        max_e_per_step = d.Function(self.V)
        max_e_per_step_file = d.File("results/%s-max_e_per_step.pvd" % input_mesh)

        self.es = {}
        self.max_es = {}
        fi = d.File("results/%s-cond.pvd" % input_mesh)

        potential_file = d.File("results/%s-potential.pvd" % input_mesh)

        # Loop through the voltages and electrode combinations
        for i, (anode, cathode, voltage) in enumerate(v.electrode_triples):
            print("Electrodes %d (%lf) -> %d (0)" % (anode, voltage, cathode))

            cond = d.project(self.sigma_start, V=self.DV)

            # Define the Dirichlet boundary conditions on the active needles
            uV = d.Constant(voltage)
            term1_bc = d.DirichletBC(self.V, uV, self.patches, v.needles[anode])
            term2_bc = d.DirichletBC(self.V, u0, self.patches, v.needles[cathode])

            e = d.Function(self.V)
            e.vector()[:] = max_e.vector()

            # Re-evaluate conductivity
            self.increase_conductivity(cond, e)

            for j in range(v.max_restarts):
                # Update the bilinear form
                a = d.inner(d.nabla_grad(z), cond * d.nabla_grad(w)) * dx

                # Solve again
                print(" [solving...")
                d.solve(a == L, U, bcs=[term1_bc, term2_bc])
                print("  ....solved]")

                # Extract electric field norm
                for k in range(len(U.vector())):
                    if N.isnan(U.vector()[k]):
                        U.vector()[k] = 1e5

                e_new = d.project(d.sqrt(d.dot(d.grad(U), d.grad(U))), self.V)

                # Take the max of the new field and the established electric field
                e.vector()[:] = N.array([max(*X) for X in zip(e.vector(), e_new.vector())])

                # Re-evaluate conductivity
                fi << cond
                self.increase_conductivity(cond, e)

            potential_file << U

            # Save the max e function to a VTU
            max_e_per_step.vector()[:] = e.vector()[:]
            max_e_per_step_file << max_e_per_step

            # Store this electric field norm, for this triple, for later reference
            self.es[i] = e

            # Store the max of this electric field norm and that for all previous triples
            max_e_array = N.array([max(*X) for X in zip(max_e.vector(), e.vector())])
            max_e.vector()[:] = max_e_array

            # Create a new max_e function for storage, or it will be overwritten by the next iteration
            max_e_new = d.Function(self.V)
            max_e_new.vector()[:] = max_e_array

            # Store this max e function for the cumulative coverage curve calculation later
            self.max_es[i] = max_e_new

            # Save the max e function to a VTU
            max_e_file << max_e
            self.max_e_count = i
コード例 #9
0
def epsilon(u):
    return 0.5 * (fs.nabla_grad(u) + fs.nabla_grad(u).T)
コード例 #10
0
 def sigI(v):
     return fe.dot(sI, fe.nabla_grad(v))
コード例 #11
0
 def sigR(v):
     return fe.dot(sR, fe.nabla_grad(v))
コード例 #12
0
 def nabla_grad(self, arg):
     return FEN.nabla_grad(arg)
コード例 #13
0
ファイル: test_fenics.py プロジェクト: kursawe/forcedynamics
 def epsilon(u):
     return 0.5 * (fenics.nabla_grad(u) + fenics.nabla_grad(u).T
                   )  #return sym(nabla_grad(u))
コード例 #14
0
ファイル: test_fenics.py プロジェクト: kursawe/forcedynamics
    def xest_implement_2d_myosin(self):
        #Parameters
        total_time = 1.0
        number_of_time_steps = 100
        delta_t = total_time / number_of_time_steps
        nx = ny = 100
        domain_size = 1.0
        lambda_ = 5.0
        mu = 2.0
        gamma = 1.0
        eta_b = 0.0
        eta_s = 1.0
        k_b = 1.0
        k_u = 1.0
        #         zeta_1 = -0.5
        zeta_1 = 0.0
        zeta_2 = 1.0
        mu_a = 1.0
        K_0 = 1.0
        K_1 = 0.0
        K_2 = 0.0
        K_3 = 0.0
        D = 0.25
        alpha = 3
        c = 0.1

        # Sub domain for Periodic boundary condition
        class PeriodicBoundary(fenics.SubDomain):
            # Left boundary is "target domain" G
            def inside(self, x, on_boundary):
                # return True if on left or bottom boundary AND NOT on one of the two corners (0, 1) and (1, 0)
                return bool(
                    (fenics.near(x[0], 0) or fenics.near(x[1], 0)) and
                    (not ((fenics.near(x[0], 0) and fenics.near(x[1], 1)) or
                          (fenics.near(x[0], 1) and fenics.near(x[1], 0))))
                    and on_boundary)

            def map(self, x, y):
                if fenics.near(x[0], 1) and fenics.near(x[1], 1):
                    y[0] = x[0] - 1.
                    y[1] = x[1] - 1.
                elif fenics.near(x[0], 1):
                    y[0] = x[0] - 1.
                    y[1] = x[1]
                else:  # near(x[1], 1)
                    y[0] = x[0]
                    y[1] = x[1] - 1.

        periodic_boundary_condition = PeriodicBoundary()

        #Set up finite elements
        mesh = fenics.RectangleMesh(fenics.Point(0, 0),
                                    fenics.Point(domain_size, domain_size), nx,
                                    ny)
        vector_element = fenics.VectorElement('P', fenics.triangle, 2, dim=2)
        single_element = fenics.FiniteElement('P', fenics.triangle, 2)
        mixed_element = fenics.MixedElement(vector_element, single_element)
        V = fenics.FunctionSpace(
            mesh,
            mixed_element,
            constrained_domain=periodic_boundary_condition)
        v, r = fenics.TestFunctions(V)
        full_trial_function = fenics.Function(V)
        u, rho = fenics.split(full_trial_function)
        full_trial_function_n = fenics.Function(V)
        u_n, rho_n = fenics.split(full_trial_function_n)

        #Define non-linear weak formulation
        def epsilon(u):
            return 0.5 * (fenics.nabla_grad(u) + fenics.nabla_grad(u).T
                          )  #return sym(nabla_grad(u))

        def sigma_e(u):
            return lambda_ * ufl.nabla_div(u) * fenics.Identity(
                2) + 2 * mu * epsilon(u)

        def sigma_d(u):
            return eta_b * ufl.nabla_div(u) * fenics.Identity(
                2) + 2 * eta_s * epsilon(u)
#         def sigma_a(u,rho):
#             return ( -zeta_1*rho/(1+zeta_2*rho)*mu_a*fenics.Identity(2)*(K_0+K_1*ufl.nabla_div(u)+
#                                                                          K_2*ufl.nabla_div(u)*ufl.nabla_div(u)+K_3*ufl.nabla_div(u)*ufl.nabla_div(u)*ufl.nabla_div(u)))

        def sigma_a(u, rho):
            return -zeta_1 * rho / (
                1 + zeta_2 * rho) * mu_a * fenics.Identity(2) * (K_0)

        F = (gamma * fenics.dot(u, v) * fenics.dx -
             gamma * fenics.dot(u_n, v) * fenics.dx +
             fenics.inner(sigma_d(u), fenics.nabla_grad(v)) * fenics.dx -
             fenics.inner(sigma_d(u_n), fenics.nabla_grad(v)) * fenics.dx -
             delta_t *
             fenics.inner(sigma_e(u) + sigma_a(u, rho), fenics.nabla_grad(v)) *
             fenics.dx + rho * r * fenics.dx - rho_n * r * fenics.dx +
             ufl.nabla_div(rho * u) * r * fenics.dx -
             ufl.nabla_div(rho * u_n) * r * fenics.dx - D * delta_t *
             fenics.dot(fenics.nabla_grad(rho), fenics.nabla_grad(r)) *
             fenics.dx + delta_t *
             (-k_u * rho * fenics.exp(alpha * ufl.nabla_div(u)) + k_b *
              (1 - c * ufl.nabla_div(u))) * r * fenics.dx)

        #         F = ( gamma*fenics.dot(u,v)*fenics.dx - gamma*fenics.dot(u_n,v)*fenics.dx + fenics.inner(sigma_d(u),fenics.nabla_grad(v))*fenics.dx -
        #               fenics.inner(sigma_d(u_n),fenics.nabla_grad(v))*fenics.dx - delta_t*fenics.inner(sigma_e(u)+sigma_a(u,rho),fenics.nabla_grad(v))*fenics.dx
        #               +rho*r*fenics.dx-rho_n*r*fenics.dx + ufl.nabla_div(rho*u)*r*fenics.dx - ufl.nabla_div(rho*u_n)*r*fenics.dx -
        #               D*delta_t*fenics.dot(fenics.nabla_grad(rho),fenics.nabla_grad(r))*fenics.dx +delta_t*(-k_u*rho*fenics.exp(alpha*ufl.nabla_div(u))+k_b*(1-c*ufl.nabla_div(u))))

        vtkfile_rho = fenics.File(
            os.path.join(os.path.dirname(__file__), 'output', 'myosin_2d',
                         'solution_rho.pvd'))
        vtkfile_u = fenics.File(
            os.path.join(os.path.dirname(__file__), 'output', 'myosin_2d',
                         'solution_u.pvd'))

        #         rho_0 = fenics.Expression(((('0.0'),('0.0'),('0.0')),('sin(x[0])')), degree=1 )
        #         full_trial_function_n = fenics.project(rho_0, V)
        time = 0.0
        for time_index in range(number_of_time_steps):
            # Update current time
            time += delta_t
            # Compute solution
            fenics.solve(F == 0, full_trial_function)
            # Save to file and plot solution
            vis_u, vis_rho = full_trial_function.split()
            vtkfile_rho << (vis_rho, time)
            vtkfile_u << (vis_u, time)
            full_trial_function_n.assign(full_trial_function)
コード例 #15
0
def epsilon(u):
    return fs.sym(fs.nabla_grad(u))
コード例 #16
0
def sigma(u):
    return lambda_ * fs.nabla_grad(u) * fs.Identity(d) + 2 * mu * epsilon(u)
コード例 #17
0
ファイル: solid.py プロジェクト: BenjaminRodenberg/tutorials
def epsilon(u):
    return 0.5 * (nabla_grad(u) + nabla_grad(u).T)
コード例 #18
0
    def solve(self):
        z, w = (self.z, self.w)
        u0 = d.Constant(0.0)

        # Define the linear and bilinear forms
        L = u0 * w * dx

        # Define useful functions
        cond = d.Function(self.DV)
        U = d.Function(self.V)

        # Initialize the max_e vector, that will store the cumulative max e values
        max_e = d.Function(self.V)
        max_e.vector()[:] = 0.0
        max_e.rename("max_E", "Maximum energy deposition by location")
        max_e_file = d.File("../%s-max_e.pvd" % input_mesh)
        max_e_per_step = d.Function(self.V)
        max_e_per_step_file = d.File("../%s-max_e_per_step.pvd" % input_mesh)

        self.es = {}
        self.max_es = {}
        fi = d.File("../%s-cond.pvd" % input_mesh)

        potential_file = d.File("../%s-potential.pvd" % input_mesh)

        # Loop through the voltages and electrode combinations
        for i, (anode, cathode, voltage) in enumerate(v.electrode_triples):
            print("Electrodes %d (%lf) -> %d (0)" % (anode, voltage, cathode))

            cond = d.project(self.sigma_start, V=self.DV)

            # Define the Dirichlet boundary conditions on the active needles
            uV = d.Constant(voltage)
            term1_bc = d.DirichletBC(self.V, uV, self.patches, anode)
            term2_bc = d.DirichletBC(self.V, u0, self.patches, cathode)

            e = d.Function(self.V)
            e.vector()[:] = max_e.vector()

            # Re-evaluate conductivity
            self.increase_conductivity(cond, e)

            for j in range(v.max_restarts):
                # Update the bilinear form
                a = d.inner(d.nabla_grad(z), cond * d.nabla_grad(w)) * dx

                # Solve again
                print(" [solving...")
                d.solve(a == L, U, bcs=[term1_bc, term2_bc])
                print("  ....solved]")

                # Extract electric field norm
                for k in range(len(U.vector())):
                    if N.isnan(U.vector()[k]):
                        U.vector()[k] = 1e5

                e_new = d.project(d.sqrt(d.dot(d.grad(U), d.grad(U))), self.V)

                # Take the max of the new field and the established electric field
                e.vector()[:] = N.array(
                    [max(*X) for X in zip(e.vector(), e_new.vector())])

                # Re-evaluate conductivity
                fi << cond
                self.increase_conductivity(cond, e)

            potential_file << U

            # Save the max e function to a VTU
            max_e_per_step.vector()[:] = e.vector()[:]
            max_e_per_step_file << max_e_per_step

            # Store this electric field norm, for this triple, for later reference
            self.es[i] = e

            # Store the max of this electric field norm and that for all previous triples
            max_e_array = N.array(
                [max(*X) for X in zip(max_e.vector(), e.vector())])
            max_e.vector()[:] = max_e_array

            # Create a new max_e function for storage, or it will be overwritten by the next iteration
            max_e_new = d.Function(self.V)
            max_e_new.vector()[:] = max_e_array

            # Store this max e function for the cumulative coverage curve calculation later
            self.max_es[i] = max_e_new

            # Save the max e function to a VTU
            max_e_file << max_e
            self.max_e_count = i