ds = df.Measure("ds", domain=mesh, subdomain_data=subd)

F_chi = (n[0] * psi * ds(1) + df.inner(df.grad(chi), df.grad(psi)) * df.dx +
         Pe * psi * df.dot(U_, df.grad(chi)) * df.dx + Pe *
         (U_[0] - df.Constant(1.)) * psi * df.dx)

a_chi, L_chi = df.lhs(F_chi), df.rhs(F_chi)

solver_chi = df.PETScKrylovSolver("gmres")
nullvec = df.Vector(chi_.vector())
S.dofmap().set(nullvec, 1.0)
nullvec *= 1.0 / nullvec.norm("l2")
nullspace = df.VectorSpaceBasis([nullvec])

problem_chi2 = df.LinearVariationalProblem(a_chi, L_chi, chi_, bcs=[])
solver_chi2 = df.LinearVariationalSolver(problem_chi2)

solver_chi2.parameters["krylov_solver"]["absolute_tolerance"] = 1e-15

logPe_arr = np.linspace(args.logPe_min, args.logPe_max, args.logPe_N)

if rank == 0:
    data = np.zeros((len(logPe_arr), 3))

for iPe, logPe in enumerate(logPe_arr):
    Pe_loc = 10**logPe
    Pe.assign(Pe_loc)

    solver_chi2.solve()
#time derivative of Brenner
B_CN = 0.5 * (B + B_1)

#calculate mean velocity
ux_CN_mean = df.Expression("ux", degree=1, ux=0.)

F_chi = ((B - B_1) * psi / dt * df.dx +
         D * df.inner(df.grad(B_CN), df.grad(psi)) * df.dx +
         psi * df.dot(u_CN_, df.grad(B_CN)) * df.dx -
         (u_CN_[0] - ux_CN_mean) * psi * df.dx - n[0] * psi * ds(1))

#define linear and bi-linear form
a_chi, L_chi = df.lhs(F_chi), df.rhs(F_chi)

#define problem for u and P
problem = df.LinearVariationalProblem(a, L, w_, bcs=bcs)
solver = df.LinearVariationalSolver(problem)

#define problem for B, with no BCs
problem_B = df.LinearVariationalProblem(a_chi, L_chi, B_, bcs=[])
solver_B = df.LinearVariationalSolver(problem_B)
solver_B.parameters["krylov_solver"]["absolute_tolerance"] = 1e-14

one = df.interpolate(df.Constant(1.), S)
V_Omega = df.assemble(
    one * df.dx)  # calculate unit cell volume (should always be 2*lambda)
r = df.SpatialCoordinate(mesh)

#write xdmf
xdmf_u = df.XDMFFile(mesh.mpi_comm(), "{}/u.xdmf".format(folder))
xdmf_B = df.XDMFFile(mesh.mpi_comm(), "{}/B.xdmf".format(folder))
    def __init__(self,
                 J,
                 U,
                 u,
                 m,
                 bcs,
                 dx_m=None,
                 dims_m=None,
                 use_nonlinear_solver=False):
        '''
        Parameters
        ----------
        J : ufl.Form
            Objective functional to maximize, e.g. linear-elastic strain energy.
        U : ufl.Form
            Linear-elastic strain energy.
        u : dolfin.Function
            Displacement field.
        m : dolfin.Function
            Vector-valued "body force" like traction field.
        bcs : (list of) dolfin.DirichletBC('s)
            Dirichlet boundary conditions.
        dx_m : dolfin.Measure or None (optional)
            "Body force" integration measure. Can be of cell type or exterior
            facet type; the default is cell type. Note, the integration measure
            can be defined on a subdomain (not necessarily on the whole domain).
        kappa : float or None (optional)
            Diffusion-like constant for smoothing the solution (`m`) increment.

        Notes
        -----
        If the "body force" integration measure `dx_m` concerns cells (as
        opposed to exterior facets), the gradient smoothing constant `kappa`
        can be `None`. Usually, `kappa` will need to be some small positive
        value if `dx_m` concerns exterior facets.

        '''

        if not isinstance(J, ufl_form_t):
            raise TypeError('Parameter `J`')

        if not isinstance(U, ufl_form_t):
            raise TypeError('Parameter `U`')

        if not isinstance(u, Function):
            raise TypeError('Parameter `u`')

        if not isinstance(m, Function):
            raise TypeError('Parameter `m`')

        if len(u) != len(m):
            raise ValueError(
                'Functions `u` and `m` must live in the same dimension space')

        if bcs is None:
            bcs = ()
        elif not isinstance(bcs, (list, tuple)):
            bcs = (bcs, )
        if not all(isinstance(bc, DirichletBC) for bc in bcs):
            raise TypeError('Parameter `bcs` must contain '
                            'homogenized `DirichletBC`(\'s)')

        if dims_m is not None:
            if not isinstance(bcs, (list, tuple, range)):
                dims_m = (dims_m, )
            if not all(isinstance(dim_i, int) for dim_i in dims_m):
                raise TypeError('Parameter `dims_m`')
            if not all(0 <= dim_i < len(m) for dim_i in dims_m):
                raise ValueError('Parameter `dims_m`')

        if dx_m is None:
            dx_m = dx
        elif not isinstance(dx_m, dolfin.Measure):
            raise TypeError('Parameter `dx_m`')

        bcs_zro = []
        for bc in bcs:
            bc_zro = DirichletBC(bc)
            bc_zro.homogenize()
            bcs_zro.append(bc_zro)

        V_u = u.function_space()
        V_m = m.function_space()

        v0_u = dolfin.TestFunction(V_u)
        v0_m = dolfin.TestFunction(V_m)

        v1_u = dolfin.TrialFunction(V_u)
        v1_m = dolfin.TrialFunction(V_m)

        self._u = u
        self._m = m
        self._z = z = Function(V_u)  # Adjoint solution

        self._J = J
        dJ_u = derivative(J, u, v0_u)
        self._dJ_m = derivative(J, m, v0_m)

        dU_u = derivative(U, u, v0_u)  # Internal force
        d2U_uu = a = derivative(dU_u, u, v1_u)  # Stiffness

        if dims_m is None: dW_u = L = dot(v0_u, m) * dx_m
        else: dW_u = L = sum(v0_u[i] * m[i] for i in dims_m) * dx_m

        self._ufl_norm_m = dolfin.sqrt(m**2) * dx_m  # equiv. L1-norm
        self._assembled_adj_dW_um = assemble(dot(v0_m, v1_u) * dx_m)
        self._dimdofs_V_m = tuple(
            np.array(V_m_sub_i.dofmap().dofs()) for V_m_sub_i in V_m.split())

        if use_nonlinear_solver:

            self._equilibrium_solver = dolfin.NonlinearVariationalSolver(
                dolfin.NonlinearVariationalProblem(dU_u - dW_u, u, bcs,
                                                   d2U_uu))

            self._adjoint_solver = dolfin.LinearVariationalSolver(
                dolfin.LinearVariationalProblem(d2U_uu, dJ_u, z, bcs_zro))
            # NOTE: `d2U_uu` is equivalent to `adjoint(d2U_uu)` due to symmetry

            self._equilibrium_solver.parameters["symmetric"] = True
            self._adjoint_solver.parameters["symmetric"] = True

        else:

            self._equilibrium_solver = LinearEquilibriumSolver(a, L, u, bcs)
            self._adjoint_solver = LinearAdjointSolver(None, dJ_u, z, bcs_zro)
            self._adjoint_solver._solver = self._equilibrium_solver.solver
            self._equilibrium_solver.parameters['symmetric'] = True
            # NOTE: `a` is equivalent to `adjoint(a)` due to symmetry; however,
            #       the LU factorization can be reused in the adjoint solver.

        if dx_m.integral_type() == 'cell':
            kappa = None
        else:
            # Compute scale factor for `kappa` based on domain size
            mesh = V_m.mesh()
            xs = mesh.coordinates()
            domain_volume = assemble(1.0 * dx(mesh))
            domain_length = (xs.max(0) - xs.min(0)).max()
            scale_factor = domain_volume / domain_length
            kappa = Constant(scale_factor * SMOOTHING_SOLVER_KAPPA)

        self._smoothing_solver = SmoothingSolver(V_m, kappa)
Example #4
0
    def linear_solver(self, u_k):
        r"""
        Solves the (linear) Newton iteration Eq. :eq:`Eq_linear_solver` for the UV theory.

        For the UV theory, the form of the Newton iteration is:

        .. math::  & \int \hat{Y} v_1 \hat{r}^2 d\hat{r}
                   - \left(\frac{m}{M_n}\right)^2 \int \hat{\phi} v_1 \hat{r}^2 d\hat{r}
                   - \alpha \int \hat{Z} v_1 \hat{r}^2 d\hat{r} + 

                   & + \int \hat{Z} v_2 \hat{r}^2 d\hat{r}
                   - \left(\frac{M}{M_n}\right)^2 \int \hat{H} v_2 \hat{r}^2 d\hat{r}
                   - \alpha \int \hat{Y} v_2 \hat{r}^2 d\hat{r} 
                   - \frac{\lambda}{2} \int {\hat{H}_k}^2 \hat{H} v_2 \hat{r}^2 d\hat{r} +

                   & - \int \hat{\nabla}\hat{\phi} \cdot \hat{\nabla} v_3 \hat{r}^2 d\hat{r}
                   - \int \hat{Y} v_3 \hat{r}^2 d\hat{r}
                   - \int \hat{\nabla}\hat{H} \cdot \hat{\nabla} v_4 \hat{r}^2 d\hat{r}
                   - \int \hat{Z} v_4 \hat{r}^2 d\hat{r} = 

                   & = \frac{M_n}{M_{f1}} \int \frac{\hat{\rho}}{M_P} v_1 \hat{r}^2 d\hat{r}
                   - \int \frac{\lambda}{3} {\hat{H}_k}^3 v_2 \hat{r}^2 d\hat{r}


        *Arguments*
            u_k  
                solution at the previous iteration

        """

        # get the boundary conditions
        Dirichlet_bc = self.get_Dirichlet_bc()

        # create a vector (phi,h) with the two trial functions for the fields
        u = d.TrialFunction(self.V)
        # ... and split it into phi and h
        phi, h, y, z = d.split(u)

        # define test functions over the function space
        v1, v2, v3, v4 = d.TestFunctions(self.V)

        # split solution at current iteration into phi_k, h_k, y_k, z_k
        phi_k, h_k, y_k, z_k = d.split(u_k)

        # cast params as constant functions so that, if they are set to 0,
        # fenics still understand what it is integrating
        m, M, Mp = Constant(self.fields.m), Constant(self.fields.M), Constant(
            self.fields.Mp)
        alpha, lam = Constant(self.fields.alpha), Constant(self.fields.lam)
        Mn, Mf1, Mf2 = Constant(self.Mn), Constant(self.Mf1), Constant(
            self.Mf2)

        # r^2
        r2 = Expression('pow(x[0],2)', degree=self.fem.func_degree)

        # define bilinear form
        # Eq.1
        a1 = y * v1 * r2 * dx - ( m / Mn )**2 * phi * v1 * r2 * dx \
             - alpha * ( Mf2/Mf1 ) * z * v1 * r2 * dx

        # Eq.2
        a2 = z * v2 * r2 * dx - ( M / Mn )**2 * h * v2 * r2 * dx \
             - alpha * ( Mf1/Mf2 ) * y * v2 * r2 * dx \
             - lam/2. * ( Mf2 / Mn )**2 * h_k**2 * h * v2 * r2 * dx

        # Laplacian of phi
        a3 = -inner(grad(phi), grad(v3)) * r2 * dx - y * v3 * r2 * dx

        # Laplacian of H
        a4 = -inner(grad(h), grad(v4)) * r2 * dx - z * v4 * r2 * dx

        # all equations
        a = a1 + a2 + a3 + a4

        # define linear form
        L1 = self.source.rho / Mp * Mn / Mf1 * v1 * r2 * dx  # Eq.1
        L2 = -lam / 3. * (Mf2 / Mn)**2 * h_k**3 * v2 * r2 * dx  # Eq.2
        L = L1 + L2  # all equations

        # define a vector with the solution
        sol = d.Function(self.V)

        # solve linearised system
        pde = d.LinearVariationalProblem(a, L, sol, Dirichlet_bc)
        solver = d.LinearVariationalSolver(pde)
        solver.solve()

        return sol
Example #5
0
def setup_NS(w_NS, u, p, v, q, p0, q0, dx, ds, normal, dirichlet_bcs,
             neumann_bcs, boundary_to_mark, u_1, phi_, rho_, rho_1, g_, M_,
             mu_, rho_e_, c_, V_, c_1, V_1, dbeta, solutes, per_tau, drho,
             sigma_bar, eps, dveps, grav, enable_PF, enable_EC,
             use_iterative_solvers, use_pressure_stabilization, p_lagrange,
             q_rhs):
    """ Set up the Navier-Stokes subproblem. """
    # F = (
    #     per_tau * rho_ * df.dot(u - u_1, v)*dx
    #     + rho_*df.inner(df.grad(u), df.outer(u_1, v))*dx
    #     + 2*mu_*df.inner(df.sym(df.grad(u)), df.grad(v))*dx
    #     - p * df.div(v)*dx
    #     + df.div(u)*q*dx
    #     - df.dot(rho_*grav, v)*dx
    # )
    mom_1 = rho_1 * u_1
    if enable_PF:
        mom_1 += -M_ * drho * df.nabla_grad(g_)

    F = (per_tau * rho_1 * df.dot(u - u_1, v) * dx + 2 * mu_ *
         df.inner(df.sym(df.nabla_grad(u)), df.sym(df.nabla_grad(v))) * dx -
         p * df.div(v) * dx - q * df.div(u) * dx +
         df.inner(df.nabla_grad(u), df.outer(mom_1, v)) * dx + 0.5 *
         (per_tau * (rho_ - rho_1) * df.dot(u, v) -
          df.dot(mom_1, df.nabla_grad(df.dot(u, v)))) * dx -
         rho_ * df.dot(grav, v) * dx)
    for boundary_name, slip_length in neumann_bcs["u"].iteritems():
        F += 1./slip_length * \
             df.dot(u, v) * ds(boundary_to_mark[boundary_name])

    for boundary_name, pressure in neumann_bcs["p"].iteritems():
        F += pressure * df.inner(normal, v) * ds(
            boundary_to_mark[boundary_name])

    if enable_PF:
        F += phi_ * df.dot(df.grad(g_), v) * dx

    if enable_EC:
        for ci_, ci_1, dbetai, solute in zip(c_, c_1, dbeta, solutes):
            zi = solute[1]
            F += df.dot(df.grad(ci_), v)*dx \
                + zi*ci_1*df.dot(df.grad(V_), v)*dx
            if enable_PF:
                F += ci_ * dbetai * df.dot(df.grad(phi_), v) * dx

    if p_lagrange:
        F += (p * q0 + q * p0) * dx

    if "u" in q_rhs:
        F += -df.dot(q_rhs["u"], v) * dx

    a, L = df.lhs(F), df.rhs(F)

    problem = df.LinearVariationalProblem(a, L, w_NS, dirichlet_bcs)
    solver = df.LinearVariationalSolver(problem)

    if use_iterative_solvers and use_pressure_stabilization:
        solver.parameters["linear_solver"] = "gmres"
        # solver.parameters["preconditioner"] = "ilu"

    return solver
Example #6
0
# geometric objects
n = dlfn.FacetNormal(mesh)
P = dlfn.Identity(dim) - dlfn.outer(n, n)
# Dirichlet boundary condition on exterior surface
bcA = dlfn.DirichletBC(Vh.sub(0), dlfn.Constant((0.0, 0.0, 0.0)), facetIds,
                       bndryId)
bcPhi = dlfn.DirichletBC(Vh.sub(1), dlfn.Constant(0.0), facetIds, bndryId)
# bilinear form
a = dlfn.dot(dlfn.curl(A), dlfn.curl(delA)) * dV() \
    + dlfn.dot(A, dlfn.grad(psi)) * dV() \
    + dlfn.dot(dlfn.grad(phi), delA) * dV()
# rhs form
l = dlfn.dot(dlfn.cross(n("+"), jumpM("+")), delA("+")) * dA(intrfcId)
# compute solution
sol = dlfn.Function(Vh)
lin_problem = dlfn.LinearVariationalProblem(a, l, sol, bcs=[bcA, bcPhi])
lin_solver = dlfn.LinearVariationalSolver(lin_problem)
lin_solver_parameters = lin_solver.parameters
lin_solver.solve()
# sub solutions
solA = sol.sub(0)
solPhi = sol.sub(1)
# output to pvd
pvd_A = dlfn.File("solution-A.pvd")
pvd_A << solA
# solving for magnetic field
Wh = dlfn.VectorFunctionSpace(mesh, "CG", 1)
curlA = dlfn.project(dlfn.curl(solA), Wh)
# output to pvd
pvd_H = dlfn.File("solution-curlA.pvd")
pvd_H << curlA
Example #7
0
    def __init__(self, V, viscosity=1e-2, penalty=1e5):
        '''
        Parameters
        ----------
        V : dolfin.FunctionSpace
            Function space for the distance function.
        viscosity: float or dolfin.Constant
            Stabilization for the unique solution of the distance problem.
        penalty: float or dolfin.Constant
            Penalty for weakly enforcing the zero-distance boundary conditions.

        '''

        if not isinstance(V, dolfin.FunctionSpace):
            raise TypeError('Parameter `V` must be a `dolfin.FunctionSpace`')

        if not isinstance(viscosity, Constant):
            if not isinstance(viscosity, (float, int)):
                raise TypeError('`Parameter `viscosity`')
            viscosity = Constant(viscosity)

        if not isinstance(penalty, Constant):
            if not isinstance(penalty, (float, int)):
                raise TypeError('Parameter `penalty`')
            penalty = Constant(penalty)

        self._viscosity = viscosity
        self._penalty = penalty

        mesh = V.mesh()
        xs = mesh.coordinates()
        l0 = (xs.max(0) - xs.min(0)).min()

        self._d = d = Function(V)
        self._Q = dolfin.FunctionSpace(mesh, 'DG', 0)

        self._mf = dolfin.MeshFunction('size_t', mesh,
                                       mesh.geometric_dimension())
        self._dx_penalty = dx(subdomain_id=1,
                              subdomain_data=self._mf,
                              domain=mesh)

        v0 = dolfin.TestFunction(V)
        v1 = dolfin.TrialFunction(V)

        target_gradient = Constant(1.0)
        scaled_penalty = penalty / mesh.hmax()

        lhs_F0 = l0*dot(grad(v0), grad(v1))*dx \
            + scaled_penalty*v0*v1*self._dx_penalty

        rhs_F0 = v0 * target_gradient * dx

        problem = dolfin.LinearVariationalProblem(lhs_F0, rhs_F0, d)
        self._linear_solver = dolfin.LinearVariationalSolver(problem)
        self._linear_solver.parameters["symmetric"] = True

        F = v0*(grad(d)**2-target_gradient)*dx \
            + viscosity*l0*dot(grad(v0), grad(d))*dx \
            + scaled_penalty*v0*d*self._dx_penalty

        J = dolfin.derivative(F, d, v1)

        problem = dolfin.NonlinearVariationalProblem(F, d, bcs=None, J=J)
        self._nonlinear_solver = dolfin.NonlinearVariationalSolver(problem)
        self._nonlinear_solver.parameters['nonlinear_solver'] = 'newton'
        self._nonlinear_solver.parameters['symmetric'] = False

        self._solve_initdist_problem = self._linear_solver.solve
        self._solve_distance_problem = self._nonlinear_solver.solve
def test_scipy_uprime_integration_with_fenics():

    iterations = 0

    NB_OF_CELLS_X = NB_OF_CELLS_Y = 2
    mesh = df.UnitSquare(NB_OF_CELLS_X, NB_OF_CELLS_Y)
    V = df.FunctionSpace(mesh, 'CG', 1)

    u0 = df.Constant('1.0')
    uprime = df.TrialFunction(V)
    uprev = df.interpolate(u0, V)
    v = df.TestFunction(V)

    #ODE is du/dt= uprime = -2*u, exact solution is u(t)=exp(-2*t)

    a = uprime * v * dx
    L = -2 * uprev * v * dx

    uprime_solution = df.Function(V)
    uprime_problem = df.LinearVariationalProblem(a, L, uprime_solution)
    uprime_solver = df.LinearVariationalSolver(uprime_problem)

    def rhs_fenics(y, t):
        """A somewhat strange case where the right hand side is constant
        and thus we don't need to use the information in y."""
        #print "time: ",t
        uprev.vector()[:] = y
        uprime_solver.solve()
        return uprime_solution.vector().array()

    def rhs(y, t):
        """
        dy/dt = f(y,t) with y(0)=1
        dy/dt = -2y -> solution y(t) = c * exp(-2*t)"""
        print "time: %g, y=%.10g" % (t, y)
        tmp = iterations + 1

        return -2 * y

    T_MAX = 2
    ts = numpy.arange(0, T_MAX + 0.1, 0.5)
    ysfenics, stat = scipy.integrate.odeint(rhs_fenics,
                                            uprev.vector().array(),
                                            ts,
                                            printmessg=True,
                                            full_output=True)

    def exact(t, y0=1):
        return y0 * numpy.exp(-2 * t)

    print "With fenics:"
    err_abs = abs(ysfenics[-1][0] -
                  exact(ts[-1]))  #use value at mesh done 0 for check
    print "Error: abs=%g, rel=%g, y_exact=%g" % (err_abs, err_abs /
                                                 exact(ts[-1]), exact(ts[-1]))
    fenics_error = err_abs

    print "Without fenics:"
    ys = scipy.integrate.odeint(rhs, 1, ts)

    err_abs = abs(ys[-1] - exact(ts[-1]))
    print "Error: abs=%g, rel=%g, y_exact=%g" % (err_abs, err_abs /
                                                 exact(ts[-1]), exact(ts[-1]))

    non_fenics_error = float(err_abs)

    print("Difference between fenics and non-fenics calculation: %g" %
          abs(fenics_error - non_fenics_error))
    assert abs(fenics_error - non_fenics_error) < 7e-16

    #should also check that solution is the same on all mesh points
    for i in range(ysfenics.shape[0]):  #for all result rows
        #each row contains the data at all mesh points for one t in ts
        row = ysfenics[i, :]
        number_range = abs(row.min() - row.max())
        print "row: %d, time %f, range %g" % (i, ts[i], number_range)
        assert number_range < 10e-16

    if False:
        from IPython.Shell import IPShellEmbed
        ipshell = IPShellEmbed()
        ipshell()

    if False:
        import pylab
        pylab.plot(ts, ys, 'o')
        pylab.plot(ts, numpy.exp(-2 * ts), '-')
        pylab.show()

    return stat
# linear forms in interior domain
from dolfin import curl, inner, dot, grad
a =   dlfn.Constant(1. / dt) * dot(A, B) * dV(intId) \
    + dlfn.Constant(0.5 * eta) * inner(curl(A), curl(B)) * dV(intId) \
    + inner(curl(A), curl(B)) * dV(extId) \
    + dot(A, grad(psi)) * dV \
    + dot(grad(phi), B) * dV
l =   dlfn.Constant(1. / dt) * dot(sol_A0, B) * dV(intId) \
    - dlfn.Constant(0.5 * eta) * inner(curl(sol_A0), curl(B)) * dV(intId)
# boundary condition
bcA = dlfn.DirichletBC(Wh.sub(0), dlfn.Constant((0.0, 0.0, 0.0)), facetMeshFun,
                       bndryId)
#------------------------------------------------------------------------------#
# linear solver
#------------------------------------------------------------------------------#
problem = dlfn.LinearVariationalProblem(a, l, sol, bcs=bcA)
solver = dlfn.LinearVariationalSolver(problem)


#------------------------------------------------------------------------------#
# initial conditions
#------------------------------------------------------------------------------#
class ExactVectorPotential(dlfn.Expression):
    def __init__(self, **kwargs):
        # user input check
        assert isinstance(kwargs["cell_data"], dlfn.MeshFunctionSizet)
        self._cell_data = kwargs["cell_data"]
        assert isinstance(kwargs["interior_id"], int)
        assert isinstance(kwargs["exterior_id"], int)
        self._interior_id = kwargs["interior_id"]
        self._exterior_id = kwargs["exterior_id"]
Example #10
0
    def linear_solver(self, u_k):
        r"""
        Solves the (linear) Newton iteration Eq. :eq:`Eq_linear_solver` for the IR theory.

        For the IR theory, the form of the Newton iterations is:

        .. math:: & - \int \hat{\nabla}\hat{\pi} \cdot \hat{\nabla} v_1 \hat{r}^2 d\hat{r}
                   - \int \hat{Y} v_1 \hat{r}^2 d\hat{r} +

                  & + \int \hat{W} v_2 \hat{r}^2 d\hat{r} -n \int {\hat{Y}_k}^{n-1} \hat{Y} v_2 \hat{r}^2 d\hat{r} +

                  & + \int \hat{Y} v_3 \hat{r}^2 d\hat{r} 
                  - \int \left( \frac{m}{M_n} \right)^2 \hat{\pi} v_3 \hat{r}^2 d\hat{r}
                  + \epsilon \left( \frac{M_n}{\Lambda} \right)^{3n-1} \left( \frac{M_{f1}}{M_n} \right)^{n-1}
                  \int \nabla\hat{W} \cdot \nabla v_3 \hat{r}^2 d\hat{r}

                  & = (1-n) \int {\hat{Y}_k}^n v_2 \hat{r}^2 d\hat{r}
                  + \int \frac{\hat{\rho}}{M_P} \frac{M_n}{M_{f1}} v_3 \hat{r}^2 d\hat{r}

        *Arguments*
            u_k  
                solution at the previous iteration

        """

        # get the boundary conditions
        Dirichlet_bc = self.get_Dirichlet_bc()

        # create a vector (pi,w,y) with the three trial functions for the fields
        u = d.TrialFunction(self.V)
        # ... and split it into pi, w, y
        pi, w, y = d.split(u)

        # define test functions over the function space
        v1, v2, v3 = d.TestFunctions(self.V)

        # split solution at current iteration into pi_k, w_k, y_k - this is only really useful for y_k
        pi_k, w_k, y_k = d.split(u_k)

        # cast params as constant functions so that, if they are set to 0, FEniCS still understand
        # what is being integrated
        m, Lambda, Mp = Constant(self.fields.m), Constant(
            self.fields.Lambda), Constant(self.fields.Mp)
        epsilon = Constant(self.fields.epsilon)
        Mn, Mf1 = Constant(self.Mn), Constant(self.Mf1)
        n = self.fields.n

        # r^2
        r2 = Expression('pow(x[0],2)', degree=self.fem.func_degree)

        # define bilinear form
        a1 = -inner(grad(pi), grad(v1)) * r2 * dx - y * v1 * r2 * dx
        a2 = w * v2 * r2 * dx - n * y_k**(n - 1) * y * v2 * r2 * dx
        a3 = y * v3 * r2 * dx - ( m / Mn )**2 * pi * v3 * r2 * dx + \
             epsilon * ( Mn / Lambda )**(3*n-1) * ( Mf1 / Mn )**(n-1) * inner( grad(w), grad(v3) ) * r2 * dx

        a = a1 + a2 + a3

        # define linear form
        # we have L1 = 0.
        L2 = (1 - n) * y_k**n * v2 * r2 * dx
        L3 = self.source.rho / Mp * Mn / Mf1 * v3 * r2 * dx

        L = L2 + L3

        # define a vector with the solution
        sol = d.Function(self.V)

        # solve linearised system
        pde = d.LinearVariationalProblem(a, L, sol, Dirichlet_bc)
        solver = d.LinearVariationalSolver(pde)
        solver.solve()

        return sol
Example #11
0
    def NL_initial_guess(self, y_method='vector'):
        r"""
        Obtains an initial guess for the Galileon equation of motion by assuming the nonlinear term is
        dominant, i.e.:

        .. math:: -\frac{\epsilon}{\Lambda^{3n-1}}\nabla^2(\nabla^2\pi^n) \approx \frac{\rho}{M_P}

        The initial guess is computed by first solving the Poisson equation:

        .. math:: -\hat{\nabla}\hat{W} =\left( \frac{\Lambda}{M_n} \right)^{3n-1}
                  \left(\frac{M_n}{M_{f1}}\right)^n \frac{\hat{\rho}}{\epsilon M_P}

        and then obtaining :math:`\hat{Y}=\sqrt[n]{\hat{W}}` through one of three methods explained below.
        Finally, :math:`\hat{\pi}` is computed by solving the Poisson equation

        .. math:: \hat{\nabla}\hat{\pi} = \hat{Y}.

        The main methods to obtain :math:`\hat{Y}` from :math:`\hat{Z}` are interpolation and projection:
        the standard FEniCS implementation for both can be chosen by setting `y\_method='interpolate'` 
        and `y\_method='project'`.

        A third method (`y\_method='vector'`, default), formally identical to interpolation,
        consists in assigning :math:`\hat{Y}`'s value at all nodes through e.g.:

        .. code-block:: python
          
            y.vector().set_local( np.sqrt( np.abs( w.vector().get_local() ) ) )

        However, because of differences in the implementations of :math:`\sqrt[n]{\cdot}` called by
        the two methods, the latter generally gives better results compared to `'interpolate'`.

        *Arguments*
            y_method
                `'vector'` (default), `'interpolate'` or `'project'`

        """

        # cast params as constant functions so that, if they are set to 0, FEniCS still understand
        # what is being integrated
        m, Lambda, Mp = Constant(self.fields.m), Constant(
            self.fields.Lambda), Constant(self.fields.Mp)
        epsilon = Constant(self.fields.epsilon)
        Mn, Mf1 = Constant(self.Mn), Constant(self.Mf1)
        n = self.fields.n

        # get the boundary conditions for w only
        def boundary(x):
            return self.fem.mesh.r_max - x[0] < d.DOLFIN_EPS

        wD = Constant(0.)
        w_Dirichlet_bc = d.DirichletBC(self.fem.S,
                                       wD,
                                       boundary,
                                       method='pointwise')

        # define trial and test function
        w_ = d.TrialFunction(self.fem.S)
        v_ = d.TestFunction(self.fem.S)

        # for the measure
        r2 = Expression('pow(x[0],2)', degree=self.fem.func_degree)

        # bilinear and linear forms
        w_a = inner(grad(w_), grad(v_)) * r2 * dx
        w_L = (Lambda / Mn)**(3 * n - 1) * (
            Mn / Mf1)**n / epsilon * self.source.rho / Mp * v_ * r2 * dx

        # define a function for the solution
        w = d.Function(self.fem.S)

        # solve
        w_pde = d.LinearVariationalProblem(w_a, w_L, w, w_Dirichlet_bc)
        w_solver = d.LinearVariationalSolver(w_pde)
        print('Getting NL initial guess...')
        w_solver.solve()

        # now we have w. we can obtain y by projection or interpolation
        if y_method == 'interpolate':
            # I use the functions sqrt and cbrt because they're more precise than pow(w,1/n)
            if n == 2:
                code = "sqrt(fabs(w))"
            elif n == 3:
                code = "cbrt(w)"
            else:
                if n % 2 == 0:  # even power
                    code = "pow(fabs(w),1./n)"
                else:  # odd power
                    code = "pow(w,1./n)"
            y_expression = Expression(code,
                                      w=w,
                                      n=n,
                                      degree=self.fem.func_degree)
            y = d.interpolate(y_expression, self.fem.S)

        elif y_method == 'vector':
            # this should formally be identical to 'interpolate', but it's a workaround to this
            # potential FEniCS bug which occurs in the previous code block:
            # https://bitbucket.org/fenics-project/dolfin/issues/1079/interpolated-expression-gives-wrong-result
            y = d.Function(self.fem.S)
            if n == 2:
                y.vector().set_local(np.sqrt(np.abs(w.vector().get_local())))
            elif n == 3:
                y.vector().set_local(np.cbrt(np.abs(w.vector().get_local())))
            else:
                if n % 2 == 0:  # even power
                    y.vector().set_local(
                        np.abs(w.vector().get_local())**(1. / self.fields.n))
                else:  # odd power
                    y.vector().set_local(
                        w.vector().get_local()**(1. / self.fields.n))

        elif y_method == 'project':
            y = w**(1. / n)
            y = project(y, self.fem.S, self.fem.func_degree)

        # we obtain pi by solving Del pi = y
        piD = Constant(0.)
        pi_Dirichlet_bc = d.DirichletBC(self.fem.S,
                                        piD,
                                        boundary,
                                        method='pointwise')
        pi_ = d.TrialFunction(self.fem.S)
        v_ = d.TestFunction(self.fem.S)
        pi_a = -inner(grad(pi_), grad(v_)) * r2 * dx
        pi_L = y * v_ * r2 * dx
        pi = d.Function(self.fem.S)
        pi_pde = d.LinearVariationalProblem(pi_a, pi_L, pi, pi_Dirichlet_bc)
        pi_solver = d.LinearVariationalSolver(pi_pde)
        pi_solver.solve()

        # now let's pack pi, w, y into a single function
        guess = d.Function(self.V)
        fa = d.FunctionAssigner(self.V, [self.fem.S, self.fem.S, self.fem.S])
        fa.assign(guess, [pi, w, y])

        return guess
Example #12
0
    def KG_initial_guess(self):
        r"""
        Obtains an initial guess for the Galileon equation of motion by assuming the nonlinear term is
        subdominant, i.e.:

        .. math:: \Box\pi - m^2\pi \approx \frac{\rho}{Mp}

        The initial guess is computed by first solving the system of equations:

        .. math:: & \hat{\nabla}^2\hat{\pi} = \hat{Y} \\
                  & \hat{Y} - \left( \frac{m}{M_n} \right)^2\pi = \frac{\hat{\rho}}{M_p}

        and then obtaining :math:`\hat{W}=\hat{Y}^n` by projection.

        """

        # define a function space for (pi, y) only
        piy_E = d.MixedElement([self.fem.Pn, self.fem.Pn])
        piy_V = d.FunctionSpace(self.fem.mesh.mesh, piy_E)

        # get the boundary conditions for pi and y only
        piD, yD = Constant(0.), Constant(0.)

        def boundary(x):
            return self.fem.mesh.r_max - x[0] < d.DOLFIN_EPS

        bc_pi = d.DirichletBC(piy_V.sub(0), piD, boundary, method='pointwise')
        bc_y = d.DirichletBC(piy_V.sub(1), yD, boundary, method='pointwise')
        Dirichlet_bc = [bc_pi, bc_y]

        # Trial functions for pi and y
        u = d.TrialFunction(piy_V)
        pi, y = d.split(u)

        # test functions for the two equations
        v1, v3 = d.TestFunctions(piy_V)

        # cast params as constant functions so that, if they are set to 0, FEniCS still understand
        # what is being integrated
        m, Mp, Mn, Mf1 = Constant(self.fields.m), Constant(
            self.fields.Mp), Constant(self.Mn), Constant(self.Mf1)
        n = self.fields.n

        # r^2
        r2 = Expression('pow(x[0],2)', degree=self.fem.func_degree)

        # bilinear form
        a1 = -inner(grad(pi), grad(v1)) * r2 * dx - y * v1 * r2 * dx
        a3 = y * v3 * r2 * dx - (m / Mn)**2 * pi * v3 * r2 * dx
        a = a1 + a3

        # linear form (L1=0)
        L3 = self.source.rho / Mp * Mn / Mf1 * v3 * r2 * dx
        L = L3

        # solve system
        sol = d.Function(piy_V)
        pde = d.LinearVariationalProblem(a, L, sol, Dirichlet_bc)
        solver = d.LinearVariationalSolver(pde)
        print('Getting KG initial guess...')
        solver.solve()

        # split solution into pi and y - cast as independent functions, not components of a vector function
        pi, y = sol.split(deepcopy=True)

        # obtain w by projecting y**n
        w = y**n
        w = project(w, self.fem.S, self.fem.func_degree)

        # and now pack pi, w, y into one function...
        guess = d.Function(self.V)
        # this syntax is because, even though pi and y are effectively defined on fem.S, from fenics point
        # of view, they are obtained as splits of a function
        fa = d.FunctionAssigner(
            self.V, [pi.function_space(), self.fem.S,
                     y.function_space()])
        fa.assign(guess, [pi, w, y])

        return guess