Exemplo n.º 1
0
def test_formulation_1_extrap_1_material():
    '''
    Test function formulation() with 1 extrinsic trap
    and 1 material
    '''
    dt = 1
    traps = [{
        "energy": 1,
        "materials": [1],
        "type": "extrinsic"
        }]
    materials = [{
            "alpha": 1,
            "beta": 2,
            "density": 3,
            "borders": [0, 1],
            "E_diff": 4,
            "D_0": 5,
            "id": 1
            }]
    
    mesh = fenics.UnitIntervalMesh(10)
    V = fenics.VectorFunctionSpace(mesh, 'P', 1, 2)
    W = fenics.FunctionSpace(mesh, 'P', 1)
    u = fenics.Function(V)
    u_n = fenics.Function(V)
    v = fenics.TestFunction(V)
    n = fenics.interpolate(fenics.Expression('1', degree=0), W)
    solutions = list(fenics.split(u))
    previous_solutions = list(fenics.split(u_n))
    testfunctions = list(fenics.split(v))
    extrinsic_traps = [n]
    mf = fenics.MeshFunction('size_t', mesh, 1, 1)
    dx = fenics.dx(subdomain_data=mf)
    temp = fenics.Expression("300", degree=0)
    flux_ = fenics.Expression("10000", degree=0)

    F, expressions = FESTIM.formulation(
        traps, extrinsic_traps, solutions, testfunctions,
        previous_solutions, dt, dx, materials, temp, flux_)
    expected_form = ((solutions[0] - previous_solutions[0]) / dt) * \
        testfunctions[0]*dx
    expected_form += 5 * fenics.exp(-4/8.6e-5/temp) * \
        fenics.dot(
            fenics.grad(solutions[0]), fenics.grad(testfunctions[0]))*dx(1)
    expected_form += -flux_*testfunctions[0]*dx + \
        ((solutions[1] - previous_solutions[1]) / dt) * \
        testfunctions[1]*dx
    expected_form += - 5 * fenics.exp(-4/8.6e-5/temp)/1/1/2 * \
        solutions[0] * (extrinsic_traps[0] - solutions[1]) * \
        testfunctions[1]*dx(1)
    expected_form += 1e13*fenics.exp(-1/8.6e-5/temp)*solutions[1] * \
        testfunctions[1]*dx(1)
    expected_form += ((solutions[1] - previous_solutions[1]) / dt) * \
        testfunctions[0]*dx

    assert expected_form.equals(F) is True
    def extract_all_info(self, general_inputs, liquid_properties):
        """
        Extract all the important data generated from the electrostatics simulation.
        Args:
            general_inputs: Object containing the SimulationGeneralParameters class.
            liquid_properties: Object obtained from the Liquid_Parameters class, which is located at Liquids.py

        Returns:

        """
        self.potential = self.class_caller.phi
        self.vacuum_electric_field = self.class_caller.E_v  # Vacuum electric field.
        self.normal_component_vacuum = self.class_caller.E_v_n  # Normal component of the electric field @interface
        self.tangential_component = self.class_caller.E_t  # @interface
        self.surface_charge_density = self.class_caller.sigma  # Surface charge density at interface.

        # Get coordinates of the nodes and midpoints.
        r_nodes, z_nodes = general_inputs.get_nodepoints(self.mesh, self.boundaries, self.boundaries_ids['Interface'])
        self.coords_nodes = [r_nodes, z_nodes]
        r_mids, z_mids = general_inputs.get_midpoints(self.boundaries, self.boundaries_ids['Interface'])
        self.coords_mids = [r_mids, z_mids]

        # Split the electric field into radial and axial components.
        self.radial_component_vacuum, self.axial_component_vacuum = \
            PostProcessing.extract_from_function(self.vacuum_electric_field, self.coords_nodes)

        # E_v_n_array = PostProcessing.extract_from_function(Electrostatics.normal_component_vacuum, coords_mids)
        E_t_array = PostProcessing.extract_from_function(self.tangential_component, self.coords_mids)

        # Define an auxiliary term for the computations.
        K = 1 + general_inputs.Lambda * (general_inputs.T_h - 1)

        self.normal_component_liquid = (self.normal_component_vacuum - self.surface_charge_density) / \
                                       liquid_properties.eps_r
        E_l_n_array = PostProcessing.extract_from_function(self.normal_component_liquid, self.coords_mids)

        # Get components of the liquid field.
        self.radial_component_liquid, self.axial_component_liquid = \
            Poisson.get_liquid_electric_field(mesh=self.mesh, subdomain_data=self.boundaries,
                                              boundary_id=self.boundaries_ids['Interface'], normal_liquid=E_l_n_array,
                                              tangential_liquid=E_t_array)
        self.radial_component_liquid.append(self.radial_component_liquid[-1])
        self.axial_component_liquid.append(self.axial_component_liquid[-1])

        # Calculate the non-dimensional evaporated charge and current.
        self.evaporated_charge = (self.surface_charge_density * general_inputs.T_h) / (liquid_properties.eps_r *
                                                                                       general_inputs.Chi) \
                                 * fn.exp(-general_inputs.Phi / general_inputs.T_h * (1 - pow(general_inputs.B, 1 / 4) *
                                                                                      fn.sqrt(
                                                                                          self.normal_component_vacuum))
                                          )
        self.conducted_charge = K * self.normal_component_liquid

        # Calculate the emitted current through the interface.
        self.emitted_current = self.class_caller.get_nd_current(self.evaporated_charge)

        # Compute the normal component of the electric stress at the meniscus (electric pressure).
        self.normal_electric_stress = (self.normal_component_vacuum ** 2 - liquid_properties.eps_r *
                                       self.normal_component_liquid ** 2) + \
                                      (liquid_properties.eps_r - 1) * self.tangential_component ** 2
Exemplo n.º 3
0
 def compute_analytical_solutions_fully_broken(self, x):
     x1 = x[0]
     x2 = x[1]
     u1 = fe.Constant(0.)
     u2 = fe.conditional(fe.gt(x2, self.height / 2.), self.fix_load,
                         fe.Constant(0.))
     u_exact = fe.as_vector([u1, u2])
     distance_field, _ = distance_function_segments_ufl(
         x, self.control_points, self.impact_radii)
     d_exact = fe.exp(-distance_field / (self.l0))
     return u_exact, d_exact
Exemplo n.º 4
0
        def obj(x):
            p = fe.Constant(x)
            x_coo = fe.SpatialCoordinate(self.mesh)
            control_points = list(self.control_points)
            control_points.append(p)
            pseudo_radii = np.zeros(len(control_points))
            distance_field, _ = distance_function_segments_ufl(
                x_coo, control_points, pseudo_radii)
            d_artificial = fe.exp(-distance_field / self.l0)

            d_clipped = fe.conditional(fe.gt(self.d_new, 0.5), self.d_new, 0.)

            L_tape = fe.assemble((d_clipped - d_artificial)**2 *
                                 fe.det(self.grad_gamma) * fe.dx)
            # L_tape = fe.assemble((self.d_new - d_artificial)**2 * fe.det(self.grad_gamma) * fe.dx)

            L = float(L_tape)
            return L
Exemplo n.º 5
0
 def expFun():
     sqrterm = E_v_n_aux
     expterm = (self.Phi /
                self.T_h) * (1 - pow(self.B, 0.25) * fn.sqrt(sqrterm))
     return fn.exp(expterm)
Exemplo n.º 6
0
    def xest_implement_1d_myosin(self):
        #Parameters
        total_time = 10.0
        number_of_time_steps = 1000
        #         delta_t = fenics.Constant(total_time/number_of_time_steps)
        delta_t = total_time / number_of_time_steps
        nx = 1000
        domain_size = 1.0
        b = fenics.Constant(6.0)
        k = fenics.Constant(0.5)
        z_1 = fenics.Constant(-10.5)  #always negative
        #         z_1 = fenics.Constant(0.0) #always negative
        z_2 = 0.1  # always positive
        xi_0 = fenics.Constant(1.0)  #always positive
        xi_1 = fenics.Constant(1.0)  #always positive
        xi_2 = 0.001  #always positive
        xi_3 = 0.0001  #always negative
        d = fenics.Constant(0.15)
        alpha = fenics.Constant(1.0)
        c = fenics.Constant(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 bool(-fenics.DOLFIN_EPS < x[0] < fenics.DOLFIN_EPS
                            and on_boundary)

            def map(self, x, y):
                y[0] = x[0] - 1

        periodic_boundary_condition = PeriodicBoundary()

        #Set up finite elements
        mesh = fenics.IntervalMesh(nx, 0.0, 1.0)
        vector_element = fenics.FiniteElement('P', fenics.interval, 1)
        single_element = fenics.FiniteElement('P', fenics.interval, 1)
        mixed_element = fenics.MixedElement(vector_element, single_element)
        V = fenics.FunctionSpace(
            mesh,
            mixed_element,
            constrained_domain=periodic_boundary_condition)
        #         V = fenics.FunctionSpace(mesh, mixed_element)
        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)
        u_initial = fenics.Constant(0.0)
        #         rho_initial = fenics.Expression('1.0*sin(pi*x[0])*sin(pi*x[0])+1.0/k0', degree=2,k0 = k)
        rho_initial = fenics.Expression('1/k0', degree=2, k0=k)
        u_n = fenics.interpolate(u_initial, V.sub(0).collapse())
        rho_n = fenics.interpolate(rho_initial, V.sub(1).collapse())
        #         perturbation = np.zeros(rho_n.vector().size())
        #         perturbation[:int(perturbation.shape[0]/2)] = 1.0
        rho_n.vector().set_local(
            np.array(rho_n.vector()) + 1.0 *
            (0.5 - np.random.random(rho_n.vector().size())))
        #         u_n.vector().set_local(np.array(u_n.vector())+4.0*(0.5-np.random.random(u_n.vector().size())))
        fenics.assign(full_trial_function_n, [u_n, rho_n])
        u_n, rho_n = fenics.split(full_trial_function_n)

        F = (u * v * fenics.dx - u_n * v * fenics.dx + delta_t *
             (b + (z_1 * rho) /
              (1 + z_2 * rho) * c * xi_1) * u.dx(0) * v.dx(0) * fenics.dx -
             delta_t * (z_1 * rho) / (1 + z_2 * rho) * c * c * xi_2 / 2.0 *
             u.dx(0) * u.dx(0) * v.dx(0) * fenics.dx + delta_t * (z_1 * rho) /
             (1 + z_2 * rho) * c * c * c * xi_3 / 6.0 * u.dx(0) * u.dx(0) *
             u.dx(0) * v.dx(0) * fenics.dx - delta_t * z_1 * rho /
             (1 + z_2 * rho) * xi_0 * v.dx(0) * fenics.dx +
             u.dx(0) * v.dx(0) * fenics.dx - u_n.dx(0) * v.dx(0) * fenics.dx +
             rho * r * fenics.dx - rho_n * r * fenics.dx -
             rho * u * r.dx(0) * fenics.dx + rho * u_n * r.dx(0) * fenics.dx +
             delta_t * d * rho.dx(0) * r.dx(0) * fenics.dx +
             delta_t * k * fenics.exp(alpha * u.dx(0)) * rho * r * fenics.dx -
             delta_t * r * fenics.dx + delta_t * c * u.dx(0) * r * fenics.dx)

        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)
        #         print('initial u and rho')
        #         print(u_n.vector())
        #         print(rho_n.vector())

        time = 0.0
        not_initialised = True
        plt.figure()
        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()
            plt.subplot(311)
            fenics.plot(vis_u, color='blue')
            plt.ylim(-0.5, 0.5)
            plt.subplot(312)
            fenics.plot(-vis_u.dx(0), color='blue')
            plt.ylim(-2, 2)
            plt.title('actin density change')
            plt.subplot(313)
            fenics.plot(vis_rho, color='blue')
            plt.title('myosin density')
            plt.ylim(0, 7)
            plt.tight_layout()
            if not_initialised:
                animation_camera = celluloid.Camera(plt.gcf())
                not_initialised = False
            animation_camera.snap()
            print('time is')
            print(time)
            #             plt.savefig(os.path.join(os.path.dirname(__file__),'output','this_output_at_time_' + '{:04d}'.format(time_index) + '.png'))
            #             print('this u and rho')
            #             print(np.array(vis_u.vector()))
            #             print(np.array(vis_rho.vector()))
            #             vtkfile_rho << (vis_rho, time)
            #             vtkfile_u << (vis_u, time)
            full_trial_function_n.assign(full_trial_function)

        animation = animation_camera.animate()
        animation.save(
            os.path.join(os.path.dirname(__file__), 'output', 'myosin_1D.mp4'))
Exemplo n.º 7
0
    Ct4 = fe.Constant(2)

    d1 = fe.Expression('x[0] - 0', degree=1)
    #d2 = fe.Expression('1 - x[0]', degree=1)
    #d3 = fe.Expression('1 - x[1]', degree=1)
    d4 = fe.Expression('x[1] - 0', degree=1)

    d = fe.Constant(10)
    #d = Min(d1, d4)

    xi = nu_trial / nu
    fv1 = fe.elem_pow(xi, 3) / (fe.elem_pow(xi, 3) + Cv1 * Cv1 * Cv1)
    #fv2 = fe.Constant(1)
    fv2 = 1 - xi / (1 + xi * fv1)
    #ft2 = fe.Constant(1)
    ft2 = Ct3 * fe.exp(-Ct4 * xi * xi)
    Omega = fe.Constant(0.5) * (fe.grad(u) - fe.grad(u).T)
    #S = fe.Constant(2) * fe.inner(Omega, Omega)
    S = fe.sqrt(fe.Constant(2) * fe.inner(Omega, Omega))
    #Stilde = fe.Constant(1)
    #Stilde = nu_trial /(kappa * kappa * d * d) * fv2
    #Stilde = nu_trial * fe.Constant(1000)
    Stilde = S + nu_trial / (kappa * kappa * d * d) * fv2
    ft2 = Ct3 * fe.exp(fe.Constant(-1) * Ct4 * xi * xi)
    #ft2 = fe.Constant(0)
    #r =fe.Constant(1)
    #r = nu_trial / (Stilde * kappa * kappa * d * d)
    r = Max(Min(nu_trial / (Stilde * kappa * kappa * d * d), fe.Constant(10)),
            -10)
    #r = fe.Constant(0.1)
    #g = fe.Constant(0.01)
Exemplo n.º 8
0
# Define an auxiliary term for the computations.
K = 1+Lambda*(T_h - 1)

E_l_n = (Electrostatics.E_v_n-Electrostatics.sigma)/LiquidInps.eps_r
E_l_n_array = PostProcessing.extract_from_function(E_l_n, coords_mids)
sigma_arr = PostProcessing.extract_from_function(Electrostatics.sigma, coords_mids)

# Get components of the liquid field.
E_l_r, E_l_z = Poisson.get_liquid_electric_field(mesh=mesh, subdomain_data=boundaries,
                                                 boundary_id=boundaries_ids['Interface'], normal_liquid=E_l_n_array,
                                                 tangential_liquid=E_t_array)
E_l_r.append(E_l_r[-1])
E_l_z.append(E_l_z[-1])

# Calculate the non-dimensional evaporated charge and current.
j_ev = (Electrostatics.sigma*T_h)/(LiquidInps.eps_r*Chi) * fn.exp(-Phi/T_h * (
        1-pow(B, 1/4)*fn.sqrt(Electrostatics.E_v_n)))
j_cond = K*E_l_n

I_h = Electrostatics.get_nd_current(j_ev)

j_ev_arr = PostProcessing.extract_from_function(j_ev, coords_mids)
j_cond_arr = PostProcessing.extract_from_function(j_cond, coords_mids)

# Compute the normal component of the electric stress at the meniscus (electric pressure).
n_taue_n = (Electrostatics.E_v_n**2-LiquidInps.eps_r*E_l_n**2) + (LiquidInps.eps_r-1)*Electrostatics.E_t**2
n_taue_n_arr = PostProcessing.extract_from_function(n_taue_n, coords_mids)

# %% DATA POSTPROCESSING.
# Check charge conservation.
charge_check = abs(j_ev_arr-j_cond_arr)/j_ev_arr
print(f'Maximum relative difference between evaporated and conducted charge is {max(charge_check)}')
Exemplo n.º 9
0
 def Diff(u):
     "Return nonlinear coefficient"
     #return 5.0E-6 * (1.0 - 0.36*u + ((0.36*u)**2.0)/2.0)
     return do * fenics.exp(-a * u)
Exemplo n.º 10
0
 def differentiated_apparent_viscosity(self, II):
     return self.ty / II**1.5 \
             * ((1 + sqrt(II)/self.eps) * exp(-sqrt(II) / self.eps) - 1)
Exemplo n.º 11
0
def R(n):
    return (1.0 - (1.0 - fn.exp(-Re)) * n ) / (1.0 - fn.exp(-Re))
Exemplo n.º 12
0
    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)
Exemplo n.º 13
0
 def apparent_viscosity(self, II):
     return 2 * self.mu + 2 * self.ty / sqrt(II) * (
         1 - exp(-sqrt(II) / self.eps))
Exemplo n.º 14
0
    def solve(self, **kwargs):
        """
        Solves the variational form of the electrostatics as defined in the
        End of Master thesis from Ximo Gallud Cidoncha:
            A comprehensive numerical procedure for solving the Taylor-Melcher
            leaky dielectric model with charge evaporation.
        Parameters
        ----------
        **kwargs : dict
            Accepted kwargs are:
                - electrostatics_solver_settings: The user may define its own solver parameters. They must be defined
                as follows:
                solver_parameters = {"snes_solver": {"linear_solver": "mumps",
                                      "maximum_iterations": 50,
                                      "report": True,
                                      "error_on_nonconvergence": True,
                                      'line_search': 'bt',
                                      'relative_tolerance': 1e-4}}
                where:
                    - snes_solver is the type of solver to be used. In this
                    case, it is compulsory to use snes, since it's the solver
                    accepted by multiphenics. However, one may try other
                    options if only FEniCS is used. These are: krylov_solver
                    and lu_solver.
                    - linear_solver is the type of linear solver to be used.
                    - maximum_iterations is the maximum number of iterations
                    the solver will try to solve the problem. In case no
                    convergence is achieved, the variable
                    error_on_nonconvergence will raise an error in case this
                    is True. If the user preferes not to raise an error when
                    no convergence, the script will continue with the last
                    results obtained in the iteration process.
                    - line_search is the type of line search technique to be
                    used for solving the problem. It is stronly recommended to
                    use the backtracking (bt) method, since it has been proven
                    to be the most robust one, specially in cases where sqrt
                    are defined, where NaNs may appear due to a bad initial
                    guess or a bad step in the iteration process.
                    - relative_tolerance will tell the solver the parameter to
                    consider convergence on the solution.
                All this options, as well as all the other options available
                can be consulted by calling the method
                Poisson.check_solver_options().
                - initial_potential: Dolfin/FEniCS function which will be used as an initial guess on the iterative
                    process. This must be introduced along with kwarg initial_surface_charge_density. Optional.
                - initial_surface_charge_density: Dolfin/FEniCS function which will be used as an initial guess on the
                    iterative process. This must be introduced along with kwarg initial_potential. Optional.
        Raises
        ------
        TypeError
            This error will raise when the convection charge has not one of the
            following types:
                - Dolfin Function.
                - FEniCS UserExpression.
                - FEniCS Constant.
                - Integer or float number, which will be converted to a FEniCS
                Constant.
        Returns
        -------
        phi : dolfin.function.function.Function
            Dolfin function containing the potential solution.
        surface_charge_density : dolfin.function.function.Function
            Dolfin function conataining the surface charge density solution.
        """

        # --------------------------------------------------------------------
        # EXTRACT THE INPUTS #
        # --------------------------------------------------------------------

        # Check if the type of j_conv is the proper one.
        if not isinstance(self.j_conv, (int, float)) \
            and not Poisson.isDolfinFunction(self.j_conv) \
            and not Poisson.isfenicsexpression(self.j_conv) \
                and not Poisson.isfenicsconstant(self.j_conv):
            conv_type = type(self.j_conv)
            raise TypeError(
                f'Convection charge must be an integer, float, Dolfin function, FEniCS UserExpression or FEniCS constant, not {conv_type}.'
            )
        else:
            if isinstance(self.j_conv, (int, float)):
                self.j_conv = fn.Constant(float(self.j_conv))

        # Extract the solver parameters.
        solver_parameters = kwargs.get('electrostatics_solver_settings')

        # --------------------------------------------------------------------
        # FUNCTION SPACES #
        # --------------------------------------------------------------------
        # Extract the restrictions to create the function spaces.
        """ This variable will be used by multiphenics when creating function spaces. It will create function spaces
            on the introduced restrictions. 
        """
        restrictions_block = [
            self.restrictions_dict['domain_rtc'],
            self.restrictions_dict['interface_rtc']
        ]

        # Base Function Space.
        V = fn.FunctionSpace(self.mesh, 'Lagrange', 2)

        # Block Function Space.
        """ Block Function Spaces are similar to FEniCS function spaces. However, since we are creating function spaces
        based on the block of restrictions, we need to create a 'block of function spaces' for each of the restrictions.
        That block of functions is the list [V, V] from the line of code below this comment. They are assigned in the
        same order in which the block of restrictions has been created, that is:
            - V -> domain_rtc
            - V -> interface_rtc
        """
        W = mp.BlockFunctionSpace([V, V], restrict=restrictions_block)

        # Check the dimensions of the created block function spaces.
        for ix, _ in enumerate(restrictions_block):
            assert W.extract_block_sub_space(
                (ix, )).dim() > 0., f'Subdomain {ix} has dimension 0.'

        # --------------------------------------------------------------------
        # TRIAL/TEST FUNCTIONS #
        # --------------------------------------------------------------------
        # Trial Functions.
        dphisigma = mp.BlockTrialFunction(W)

        # Test functions.
        vl = mp.BlockTestFunction(W)
        (v, l) = mp.block_split(vl)

        phisigma = mp.BlockFunction(W)
        (phi, sigma) = mp.block_split(phisigma)

        # --------------------------------------------------------------------
        # MEASURES #
        # --------------------------------------------------------------------
        self.get_measures()
        self.dS = self.dS(
            self.boundaries_ids['Interface'])  # Restrict to the interface.

        # Check proper marking of the interface.
        assert fn.assemble(
            1 * self.dS(domain=self.mesh)
        ) > 0., "The length of the interface is zero, wrong marking. Check the files in Paraview."

        # --------------------------------------------------------------------
        # DEFINE THE F TERM #
        # --------------------------------------------------------------------
        n = fn.FacetNormal(self.mesh)
        t = fn.as_vector((n[1], -n[0]))

        # Define auxiliary terms.
        r = fn.SpatialCoordinate(self.mesh)[0]
        K = 1 + self.Lambda * (self.T_h - 1)

        E_v_n_aux = fn.dot(-fn.grad(phi("-")), n("-"))

        def expFun():
            sqrterm = E_v_n_aux
            expterm = (self.Phi /
                       self.T_h) * (1 - pow(self.B, 0.25) * fn.sqrt(sqrterm))
            return fn.exp(expterm)

        def sigma_fun():
            num = K * E_v_n_aux + self.eps_r * self.j_conv
            den = K + (self.T_h / self.Chi) * expFun()
            return r * num / den

        # Define the relative permittivity.

        class relative_perm(fn.UserExpression):
            def __init__(self, markers, subdomain_ids, relative, **kwargs):
                super().__init__(**kwargs)
                self.markers = markers
                self.subdomain_ids = subdomain_ids
                self.relative = relative

            def eval_cell(self, values, x, cell):
                if self.markers[cell.index] == self.subdomain_ids['Vacuum']:
                    values[0] = 1.
                else:
                    values[0] = self.relative

        rel_perm = relative_perm(self.subdomains,
                                 self.subdomains_ids,
                                 relative=self.eps_r,
                                 degree=0)

        # Define the variational form.
        # vacuum_int = r*fn.inner(fn.grad(phi), fn.grad(v))*self.dx(self.subdomains_ids['Vacuum'])
        # liquid_int = self.eps_r*r*fn.inner(fn.grad(phi), fn.grad(v))*self.dx(self.subdomains_ids['Liquid'])

        F = [
            r * rel_perm * fn.inner(fn.grad(phi), fn.grad(v)) * self.dx -
            r * sigma("-") * v("-") * self.dS,
            r * sigma_fun() * l("-") * self.dS -
            r * sigma("-") * l("-") * self.dS
        ]

        J = mp.block_derivative(F, phisigma, dphisigma)

        # --------------------------------------------------------------------
        # BOUNDARY CONDITIONS #
        # --------------------------------------------------------------------
        bcs_block = []
        for i in self.boundary_conditions:
            if 'Dirichlet' in self.boundary_conditions[i]:
                bc_val = self.boundary_conditions[i]['Dirichlet'][0]
                bc = mp.DirichletBC(W.sub(0), bc_val, self.boundaries,
                                    self.boundaries_ids[i])
                # Check the created boundary condition.
                assert len(bc.get_boundary_values()
                           ) > 0., f'Wrongly defined boundary {i}'
                bcs_block.append(bc)

        bcs_block = mp.BlockDirichletBC([bcs_block])

        # --------------------------------------------------------------------
        # SOLVE #
        # --------------------------------------------------------------------
        # Define and assign the initial guesses.
        if kwargs.get('initial_potential') is None:
            """
            Check if the user is introducing a potential from a previous
            iteration.
            """
            phiv, phil, sigma_init = self.solve_initial_problem()
            # phi_init = self.solve_initial_problem_v2()
            phi.assign(phiv)
            sigma.assign(sigma_init)
        else:
            phi.assign(kwargs.get('initial_potential'))
            sigma.assign(kwargs.get('initial_surface_charge_density'))

        # Apply the initial guesses to the main function.
        phisigma.apply('from subfunctions')

        # Solve the problem with the solver options (either default or user).
        problem = mp.BlockNonlinearProblem(F, phisigma, bcs_block, J)
        solver = mp.BlockPETScSNESSolver(problem)
        solver_type = [i for i in solver_parameters.keys()][0]
        solver.parameters.update(solver_parameters[solver_type])
        solver.solve()

        # Extract the solutions.
        (phi, _) = phisigma.block_split()
        self.phi = phi
        # --------------------------------------------------------------------

        # Compute the electric field at vacuum and correct the surface charge density.
        self.E_v = self.get_electric_field('Vacuum')
        self.E_v_n = self.get_normal_field(n("-"), self.E_v)
        self.E_t = self.get_tangential_component(t("+"), self.E_v)
        C = self.Phi / self.T_h * (1 - self.B**0.25 * fn.sqrt(self.E_v_n))
        self.sigma = (K * self.E_v_n) / (K + self.T_h / self.Chi * fn.exp(-C))
Exemplo n.º 15
0
 def evaporated_charge():
     return (self.sigma * self.T_h) / (self.eps_r * self.Chi) * fn.exp(
         -self.Phi / self.T_h *
         (1 - self.B**0.25 * fn.sqrt(self.E_v_n)))
Exemplo n.º 16
0
    def parameters(h, dt, final_time, u, v):
        size = 1
        folder = 'Solution_Test'
        v_0 = 1e13
        E_t = 1.5
        T = 700
        density = 1 * 6.3e28
        beta = 6*density
        alpha = 1.1e-10
        n_trap = 1e-1*density
        E_diff = 0.39
        D_0 = 4.1e-7
        k_B = 8.6e-5
        D = D_0 * fenics.exp(-E_diff/k_B/T)
        v_i = v_0 * fenics.exp(-E_t/k_B/T)
        v_m = D/alpha/alpha/beta

        f = sp.diff(u, FESTIM.t) + sp.diff(v, FESTIM.t) - \
            D * sp.diff(u, FESTIM.x, 2)
        g = sp.diff(v, FESTIM.t) + v_i*v - v_m * u * (n_trap-v)
        parameters = {
            "materials": [
                {
                    "alpha": alpha,  # lattice constant ()
                    "beta": beta,  # number of solute sites per atom (6 for W)
                    "density": density,
                    "borders": [0, size],
                    "E_diff": E_diff,
                    "D_0": D_0,
                    "id": 1
                    }
                    ],
            "traps": [
                {
                    "energy": E_t,
                    "density": n_trap,
                    "materials": 1,
                    "source_term": g
                }
                ],
            "initial_conditions": [
                {
                    "value": u,
                    "component": 0
                },
                {
                    "value": v,
                    "component": 1
                }
            ],

            "mesh_parameters": {
                    "initial_number_of_cells": round(size/h),
                    "size": size,
                    "refinements": [
                    ],
                },
            "boundary_conditions": [
                    {
                        "surface": [1, 2],
                        "value": u,
                        "component": 0,
                        "type": "dc"
                    },
                    {
                        "surface": [1, 2],
                        "value": v,
                        "component": 1,
                        "type": "dc"
                    }
                ],
            "temperature": {
                    'type': "expression",
                    'value': T
                },
            "source_term": {
                'flux': f
                },
            "solving_parameters": {
                "final_time": final_time,
                "num_steps": round(1/dt),
                "adaptative_time_step": {
                    "stepsize_change_ratio": 1,
                    "t_stop": 0,
                    "stepsize_stop_max": dt,
                    "dt_min": 1e-5
                    },
                "newton_solver": {
                    "absolute_tolerance": 1e-10,
                    "relative_tolerance": 1e-9,
                    "maximum_it": 50,
                }
                },
            "exports": {
                "txt": {
                    "functions": [],
                    "times": [],
                    "labels": [],
                    "folder": folder
                },
                "xdmf": {
                    "functions": [],
                    "labels":  [],
                    "folder": folder
                },
                "TDS": {
                    "file": "desorption",
                    "TDS_time": 0,
                    "folder": folder
                    },
                "error": [
                    {
                        "exact_solution": [u, v],
                        "norm": 'error_max',
                        "degree": 4
                    }
                ]
                },
        }
        return parameters
Exemplo n.º 17
0
def test_formulation_2_traps_1_material():
    '''
    Test function formulation() with 2 intrinsic traps
    and 1 material
    '''    
    # Set parameters
    dt = 1
    traps = [{
        "energy": 1,
        "density": 2,
        "materials": [1]
        },
        {
        "energy": 1,
        "density": 2,
        "materials": [1]
        }]
    materials = [{
            "alpha": 1,
            "beta": 2,
            "density": 3,
            "borders": [0, 1],
            "E_diff": 4,
            "D_0": 5,
            "id": 1
            }]
    extrinsic_traps = []

    # Prepare
    mesh = fenics.UnitIntervalMesh(10)
    V = fenics.VectorFunctionSpace(mesh, 'P', 1, len(traps)+1)
    u = fenics.Function(V)
    u_n = fenics.Function(V)
    v = fenics.TestFunction(V)

    solutions = list(fenics.split(u))
    previous_solutions = list(fenics.split(u_n))
    testfunctions = list(fenics.split(v))

    mf = fenics.MeshFunction('size_t', mesh, 1, 1)
    dx = fenics.dx(subdomain_data=mf)
    temp = fenics.Expression("300", degree=0)
    flux_ = fenics.Expression("1", degree=0)

    F, expressions = FESTIM.formulation(
        traps, extrinsic_traps, solutions, testfunctions,
        previous_solutions, dt, dx, materials, temp, flux_)
    # Transient sol
    expected_form = ((solutions[0] - previous_solutions[0]) / dt) * \
        testfunctions[0]*dx
    # Diffusion sol
    expected_form += 5 * fenics.exp(-4/8.6e-5/temp) * \
        fenics.dot(
            fenics.grad(solutions[0]), fenics.grad(testfunctions[0]))*dx(1)
    # Source sol
    expected_form += -flux_*testfunctions[0]*dx
    # Transient trap 1
    expected_form += ((solutions[1] - previous_solutions[1]) / dt) * \
        testfunctions[1]*dx
    # Trapping trap 1
    expected_form += - 5 * fenics.exp(-4/8.6e-5/temp)/1/1/2 * \
        solutions[0] * (2 - solutions[1]) * \
        testfunctions[1]*dx(1)
    # Detrapping trap 1
    expected_form += 1e13*fenics.exp(-1/8.6e-5/temp)*solutions[1] * \
        testfunctions[1]*dx(1)
    # Source detrapping sol
    expected_form += ((solutions[1] - previous_solutions[1]) / dt) * \
        testfunctions[0]*dx

    # Transient trap 2
    expected_form += ((solutions[2] - previous_solutions[2]) / dt) * \
        testfunctions[2]*dx
    # Trapping trap 2
    expected_form += - 5 * fenics.exp(-4/8.6e-5/temp)/1/1/2 * \
        solutions[0] * (2 - solutions[2]) * \
        testfunctions[2]*dx(1)
    # Detrapping trap 2
    expected_form += 1e13*fenics.exp(-1/8.6e-5/temp)*solutions[2] * \
        testfunctions[2]*dx(1)
    # Source detrapping 2 sol
    expected_form += ((solutions[2] - previous_solutions[2]) / dt) * \
        testfunctions[0]*dx

    assert expected_form.equals(F) is True
Exemplo n.º 18
0
def test_formulation_1_trap_2_materials():
    '''
    Test function formulation() with 1 intrinsic trap
    and 2 materials
    '''
    def create_subdomains(x1, x2):
        class domain(FESTIM.SubDomain):
            def inside(self, x, on_boundary):
                return x[0] >= x1 and x[0] <= x2
        domain = domain()
        return domain
    dt = 1
    traps = [{
        "energy": 1,
        "density": 2,
        "materials": [1, 2]
        }]
    materials = [{
            "alpha": 1,
            "beta": 2,
            "density": 3,
            "borders": [0, 0.5],
            "E_diff": 4,
            "D_0": 5,
            "id": 1
            },
            {
            "alpha": 2,
            "beta": 3,
            "density": 4,
            "borders": [0.5, 1],
            "E_diff": 5,
            "D_0": 6,
            "id": 2
            }]
    extrinsic_traps = []
    mesh = fenics.UnitIntervalMesh(10)
    mf = fenics.MeshFunction("size_t", mesh, 1, 1)
    mat1 = create_subdomains(0, 0.5)
    mat2 = create_subdomains(0.5, 1)
    mat1.mark(mf, 1)
    mat2.mark(mf, 2)
    V = fenics.VectorFunctionSpace(mesh, 'P', 1, 2)
    u = fenics.Function(V)
    u_n = fenics.Function(V)
    v = fenics.TestFunction(V)

    solutions = list(fenics.split(u))
    previous_solutions = list(fenics.split(u_n))
    testfunctions = list(fenics.split(v))

    mf = fenics.MeshFunction('size_t', mesh, 1, 1)
    dx = fenics.dx(subdomain_data=mf)
    temp = fenics.Expression("300", degree=0)
    flux_ = fenics.Expression("1", degree=0)

    F, expressions = FESTIM.formulation(
        traps, extrinsic_traps, solutions, testfunctions,
        previous_solutions, dt, dx, materials, temp, flux_)

    # Transient sol
    expected_form = ((solutions[0] - previous_solutions[0]) / dt) * \
        testfunctions[0]*dx
    # Diffusion sol mat 1
    expected_form += 5 * fenics.exp(-4/8.6e-5/temp) * \
        fenics.dot(
            fenics.grad(solutions[0]), fenics.grad(testfunctions[0]))*dx(1)
    # Diffusion sol mat 2
    expected_form += 6 * fenics.exp(-5/8.6e-5/temp) * \
        fenics.dot(
            fenics.grad(solutions[0]), fenics.grad(testfunctions[0]))*dx(2)
    # Source sol
    expected_form += -flux_*testfunctions[0]*dx
    # Transient trap 1
    expected_form += ((solutions[1] - previous_solutions[1]) / dt) * \
        testfunctions[1]*dx
    # Trapping trap 1 mat 1
    expected_form += - 5 * fenics.exp(-4/8.6e-5/temp)/1/1/2 * \
        solutions[0] * (2 - solutions[1]) * \
        testfunctions[1]*dx(1)
    # Trapping trap 1 mat 2
    expected_form += - 6 * fenics.exp(-5/8.6e-5/temp)/2/2/3 * \
        solutions[0] * (2 - solutions[1]) * \
        testfunctions[1]*dx(2)
    # Detrapping trap 1 mat 1
    expected_form += 1e13*fenics.exp(-1/8.6e-5/temp)*solutions[1] * \
        testfunctions[1]*dx(1)
    # Detrapping trap 1 mat 2
    expected_form += 1e13*fenics.exp(-1/8.6e-5/temp)*solutions[1] * \
        testfunctions[1]*dx(2)
    # Source detrapping sol
    expected_form += ((solutions[1] - previous_solutions[1]) / dt) * \
        testfunctions[0]*dx

    assert expected_form.equals(F) is True