예제 #1
0
def steady_state(u, **kwargs):
    z = firedrake.Function(u.function_space())
    J_diffusive = -k * S**2 / 2 * ln(1 - inner(grad(z), grad(z)) / S**2) * dx
    J_uplift = u * z * dx
    J = J_diffusive - J_uplift

    return _newton_solve(z, J, J_diffusive, **kwargs)
예제 #2
0
def hankel_function(expr, n=None):
    """
        Returns a :mod:`firedrake` expression approximation a hankel function
        of the first kind and order 0
        evaluated at :arg:`expr` by using the taylor
        series, expanded out to :arg:`n` terms.
    """
    if n is None:
        warn(
            "Default n to %s, this may cause errors."
            "If it bugs out on you, try setting n to something more reasonable"
            % MAX_N)
        n = MAX_N

    j_0 = 0
    for i in range(n):
        j_0 += (-1)**i * (1 / 4 * expr**2)**i / factorial(i)**2

    g = Constant(0.57721566490153286)
    y_0 = (ln(expr / 2) + g) * j_0
    h_n = 0
    for i in range(n):
        h_n += 1 / (i + 1)
        y_0 += (-1)**(i) * h_n * (expr**2 / 4)**(i + 1) / (factorial(i + 1))**2
    y_0 *= Constant(2 / pi)

    imag_unit = Constant((np.zeros(1, dtype=np.complex128) + 1j)[0])
    h_0 = j_0 + imag_unit * y_0
    return h_0
예제 #3
0
def solve(dt, z0, u, **kwargs):
    z = z0.copy(deepcopy=True)
    J_diffusive = -k * S**2 / 2 * ln(1 - inner(grad(z), grad(z)) / S**2) * dx
    J_uplift = u * z * dx
    J = J_diffusive - J_uplift

    E = 0.5 * (z - z0)**2 * dx + firedrake.Constant(dt) * J
    scale = 0.5 * z**2 * dx + firedrake.Constant(dt) * J_diffusive
    return _newton_solve(z, E, scale, **kwargs)
예제 #4
0
 def __init__(self):
     super().__init__()
     X = self.X
     # volume and boundary integrals
     self.name = "LevelSet Example 2"
     self.J = (sin(X[0]) * cos(X[1]) * dx +
               pow(1.3 + X[0], 4.2) * pow(1.4 + X[1], 3.3) * dx +
               exp(sin(X[0]) + cos(X[1])) * dx +
               ln(5 + sin(X[0]) + cos(X[1])) * ds)
     self.set_quadrature(8)
예제 #5
0
 def __init__(self):
     super().__init__()
     X = self.X
     # volume and boundary integrals
     self.name = "LevelSet Example 3"
     V = FunctionSpace(self.mesh, "CG", 1)
     u = interpolate(sin(X[0]) * cos(X[1])**2, V)
     n = FacetNormal(self.mesh)
     self.J = (sin(X[0]) * cos(X[1]) * dx +
               pow(1.3 + X[0], 4.2) * pow(1.4 + X[1], 3.3) * dx +
               exp(sin(X[0]) + cos(X[1])) * dx +
               ln(5 + sin(X[0]) + cos(X[1])) * ds + inner(grad(u), n) * ds)
     self.set_quadrature(8)
예제 #6
0
def T_dew(parameters, p, r_v):
    """
    Returns the dewpoint temperature as a function of
    temperature and the water vapour mixing ratio.

    :arg parameters: a CompressibleParameters object.
    :arg T: the temperature in K.
    :arg r_v: the water vapour mixing ratio.
    """

    R_d = parameters.R_d
    R_v = parameters.R_v
    T_0 = parameters.T_0
    e = p * r_v / (r_v + R_d / R_v)

    return 243.5 / ((17.67 / ln(e / 611.2)) - 1) + T_0
예제 #7
0
def eval_hankel_function(pt, n=MAX_N):
    """
        Evaluate a hankel function of the first kind of order 0
        at point :arg:`pt` using the Taylor series
        eptpanded out to degree :arg:`n`
    """
    j_0 = 0
    for i in range(n):
        j_0 += (-1)**i * (1 / 4 * e**2)**i / factorial(i)**2

    g = 0.57721566490153286
    y_0 = (ln(e / 2) + g) * j_0
    h_n = 0
    for i in range(n):
        h_n += 1 / (i + 1)
        y_0 += (-1)**(i) * h_n * (e**2 / 4)**(i + 1) / (factorial(i + 1))**2
    y_0 *= 2 / pi

    imag_unit = (np.zeros(1, dtype=np.complept128) + 1j)[0]
    h_0 = j_0 + imag_unit * y_0
    return h_0
예제 #8
0
def hankel_function(expr, n):
    """
        Returns a :mod:`firedrake` expression approximation a hankel function
        of the first kind and order 0
        evaluated at :arg:`expr` by using the taylor
        series, expanded out to :arg:`n` terms.
    """
    j_0 = 0
    for i in range(n):
        j_0 += (-1)**i * (1 / 4 * expr**2)**i / factorial(i)**2

    g = Constant(0.57721566490153286)
    y_0 = (ln(expr / 2) + g) * j_0
    h_n = 0
    for i in range(n):
        h_n += 1 / (i + 1)
        y_0 += (-1)**(i) * h_n * (expr**2 / 4)**(i + 1) / (factorial(i + 1))**2
    y_0 *= Constant(2 / pi)

    imag_unit = Constant((np.zeros(1, dtype=np.complex128) + 1j)[0])
    h_0 = j_0 + imag_unit * y_0
    return h_0
예제 #9
0
def thetaInit(Ainit, Q, Q1, grounded, floating, inversionParams):
    """Compute intitial theta on the ice shelf (not grounded).
    Parameters
    ----------
    Ainit : firedrake function
        A Glens flow law A
    Q : firedrake function space
        scalar function space
    Q1 : firedrake function space
        1 deg scalar function space used with 'initWithDeg1'
    grounded : firedrake function
        Mask with 1s for grounded 0 for floating.
    floating : firedrake function
        Mask with 1s for floating 0 for grounded.
    Returns
    -------
    theta : firedrake function
        theta for floating ice
    """
    # Get initial file if there is one to init inversion
    checkFile = inversionParams['initFile']
    Quse = Q
    # Use degree 1 solution if prompted
    if inversionParams['initWithDeg1']:
        checkFile = f'{inversionParams["inversionResult"]}.deg1'
        Quse = Q1
    # Now check if there is a file specificed, and if so, init with that
    if checkFile is not None:
        Print(f'Init. with theta: {checkFile}')
        thetaTemp = mf.getCheckPointVars(checkFile,
                                         'thetaInv', Quse)['thetaInv']
        thetaInit = icepack.interpolate(thetaTemp, Q)
        return thetaInit
    # No initial theta, so use initial A to init inversion
    Atheta = mf.firedrakeSmooth(Ainit, alpha=1000)
    theta = firedrake.ln(Atheta)
    theta = firedrake.interpolate(theta, Q)
    return theta
예제 #10
0
    def __init__(self,
                 salinity,
                 temperature,
                 pressure_perturbation,
                 z,
                 GammaTfunc=None,
                 velocity=None,
                 ice_heat_flux=True,
                 HJ99Gamma=False,
                 f=None):
        super().__init__(salinity, temperature, pressure_perturbation, z)

        if velocity is None:
            # Use constant turbulent thermal and salinity exchange values given in Holland and Jenkins 1999.
            gammaT = self.gammaT
            gammaS = self.gammaS

        else:
            u = velocity

            if HJ99Gamma:
                # Holland and Jenkins 1999 turbulent heat/salt exchange velocity as a function
                # of friction velocity. This should be the same as in MITgcm.

                # Holland, D.M. and Jenkins, A., 1999. Modeling thermodynamic ice–ocean interactions at
                # the base of an ice shelf. Journal of Physical Oceanography, 29(8), pp.1787-1800.

                # Calculate friction velocity
                if isinstance(u, float):
                    print("Input velocity:", u)
                    u_bounded = max(u, 1e-3)
                    print("Bounded velocity:", u_bounded)
                else:
                    u_bounded = conditional(u > 1e-3, u, 1e-3)
                u_star = pow(self.C_d * pow(u_bounded, 2), 0.5)

                # Calculate turbulent component of thermal and salinity exchange velocity (Eq 15)
                # N.b MITgcm sets etastar = 1 so that the first part of Gamma_turb term below is constant.
                # eta_star = (1 + (zeta_N * u_star) / (f * L0 * Rc))^-1/2  (Eq 18)
                # In H&J99  eta_star is set to 1 when the Obukhov length is negative (i.e the buoyancy flux
                # is destabilising. This occurs during freezing. (Melting is stabilising)
                # So it does seem a bit odd because then eta_star is tuned to freezing conditions
                # need to work this out...?
                Gamma_Turb = 1.0 / (2.0 * self.zeta_N *
                                    self.eta_star) - 1.0 / self.k
                if f is not None:
                    # Add extra term if using coriolis term
                    # Calculate viscous sublayer thickness (Eq 17)
                    h_nu = 5.0 * self.nu / u_star
                    Gamma_Turb += ln(
                        u_star * self.zeta_N * pow(self.eta_star, 2) /
                        (abs(f) * h_nu)) / self.k

                # Calculate molecular components of thermal exchange velocity (Eq 16)
                GammaT_Mole = 12.5 * pow(self.Pr, 2.0 / 3.0) - 6.0

                # Calculate molecular component of salinity exchange velocity (Eq 16)
                GammaS_Mole = 12.5 * pow(self.Sc, 2.0 / 3.0) - 6.0

                # Calculate thermal and salinity exchange velocity. (Eq 14)
                # Do we need to catch -ve gamma? could have -ve Gamma_Turb?
                gammaT = u_star / (Gamma_Turb + GammaT_Mole)
                gammaS = u_star / (Gamma_Turb + GammaS_Mole)

                # print exchange velocities if testing when input velocity is a float.
                if isinstance(gammaT, float) or isinstance(gammaS, float):
                    print("gammaT = ", gammaT)
                    print("gammaS = ", gammaS)

            else:
                # ISOMIP+ based on Jenkins et al 2010. Measurement of basal rates beneath Ronne Ice Shelf
                u_tidal = 0.01
                u_star = pow(self.C_d * (pow(u, 2) + pow(u_tidal, 2)), 0.5)
                if GammaTfunc is None:
                    gammaT = self.GammaT * u_star
                    gammaS = self.GammaS * u_star
                else:
                    gammaT = GammaTfunc * u_star
                    gammaS = (GammaTfunc / 35.0) * u_star

                # print exchange velocities if testing when input velocity is a float.
                if isinstance(gammaT, float) or isinstance(gammaS, float):
                    print("gammaT = ", gammaT)
                    print("gammaS = ", gammaS)

        b_plus_cPb = (self.b + self.c * self.P_full
                      )  # save calculating this each time...

        # Calculate coefficients in quadratic equation for salinity at ice-ocean boundary.
        # Aa.Sb^2 + Bb.Sb + Cc = 0
        Aa = self.c_p_m * gammaT * self.a
        Bb = -gammaS * self.Lf
        Bb -= self.c_p_m * gammaT * self.T
        Bb += self.c_p_m * gammaT * b_plus_cPb
        Cc = gammaS * self.S * self.Lf

        if ice_heat_flux:
            Aa -= gammaS * self.c_p_i * self.a
            Bb += gammaS * self.S * self.c_p_i * self.a
            Bb -= gammaS * self.c_p_i * b_plus_cPb
            Bb += gammaS * self.c_p_i * self.T_ice
            Cc += gammaS * self.S * self.c_p_i * b_plus_cPb
            Cc -= gammaS * self.S * self.c_p_i * self.T_ice

        S1 = (-Bb + pow(Bb**2 - 4.0 * Aa * Cc, 0.5)) / (2.0 * Aa)
        S2 = (-Bb - pow(Bb**2 - 4.0 * Aa * Cc, 0.5)) / (2.0 * Aa)
        print(type(S1))
        print(S1)
        if isinstance(S1, (float, sympy.core.numbers.Float)):
            # Print statements for testing
            print("S1 = ", S1)
            print("S2 = ", S2)
            if S1 > 0:
                self.Sb = S1
                print("Choose S1")
            else:
                self.Sb = S2
                print("Choose S2")
        elif isinstance(S1, sympy.core.add.Add):
            self.Sb = S2
        else:
            self.Sb = conditional(S1 > 0.0, S1, S2)

        self.Tb = self.a * self.Sb + self.b + self.c * self.P_full
        self.wb = gammaS * (self.S - self.Sb) / self.Sb

        if ice_heat_flux:
            self.Q_ice = -self.rho0 * (self.T_ice -
                                       self.Tb) * self.c_p_i * self.wb
        else:
            if isinstance(S1, float):
                self.Q_ice = 0.0
            else:
                self.Q_ice = Constant(0.0)

        self.Q_mixed = -self.rho0 * self.c_p_m * gammaT * (self.Tb - self.T)
        self.Q_latent = self.Q_ice - self.Q_mixed

        self.QS_mixed = -self.rho0 * gammaS * (self.Sb - self.S)

        self.T_flux_bc = -(self.wb + gammaT) * (self.Tb - self.T)
        self.S_flux_bc = -(self.wb + gammaS) * (self.Sb - self.S)
예제 #11
0
m = fd.Mesh('meshes/circle.msh')
V = fd.FunctionSpace(m, 'DG', degree)
Vdim = fd.VectorFunctionSpace(m, 'DG', degree)

mesh_analog = fd2mm.MeshAnalog(m)
fspace_analog = fd2mm.FunctionSpaceAnalog(cl_ctx, mesh_analog, V)

xx = fd.SpatialCoordinate(m)
r"""
..math:

    \ln(\sqrt{(x+1)^2 + (y+1)^2})

i.e. a shift of the fundamental solution
"""
expr = fd.ln(fd.sqrt((xx[0] + 2)**2 + (xx[1] + 2)**2))
f = fd.Function(V).interpolate(expr)
gradf = fd.Function(Vdim).interpolate(fd.grad(expr))

# Let's create an operator which plugs in f, \partial_n f
# to Green's formula

sigma = sym.make_sym_vector("sigma", 2)
op = -(sym.D(LaplaceKernel(2),
          sym.var("u"),
          qbx_forced_limit=None)
    - sym.S(LaplaceKernel(2),
            sym.n_dot(sigma),
            qbx_forced_limit=None))

from meshmode.mesh import BTAG_ALL
예제 #12
0
def test_ice_shelf_inverse_with_noise(solver_type):
    import icepack

    Nx, Ny = 32, 32
    Lx, Ly = 20e3, 20e3

    u0 = 100
    h0, δh = 500, 100
    T0, δT = 254.15, 5.0
    A0 = icepack.rate_factor(T0)
    δA = icepack.rate_factor(T0 + δT) - A0

    def exact_u(x):
        ρ = ρ_I * (1 - ρ_I / ρ_W)
        Z = icepack.rate_factor(T0) * (ρ * g * h0 / 4)**n
        q = 1 - (1 - (δh / h0) * (x / Lx))**(n + 1)
        δu = Z * q * Lx * (h0 / δh) / (n + 1)
        return u0 + δu

    mesh = firedrake.RectangleMesh(Nx, Ny, Lx, Ly)
    degree = 2
    V = firedrake.VectorFunctionSpace(mesh, "CG", degree)
    Q = firedrake.FunctionSpace(mesh, "CG", degree)

    x, y = firedrake.SpatialCoordinate(mesh)
    u_initial = interpolate(as_vector((exact_u(x), 0)), V)
    q_initial = interpolate(firedrake.Constant(0), Q)
    h = interpolate(h0 - δh * x / Lx, Q)

    def viscosity(**kwargs):
        u = kwargs["velocity"]
        h = kwargs["thickness"]
        q = kwargs["log_fluidity"]

        A = A0 * firedrake.exp(-q / n)
        return icepack.models.viscosity.viscosity_depth_averaged(velocity=u,
                                                                 thickness=h,
                                                                 fluidity=A)

    model = icepack.models.IceShelf(viscosity=viscosity)
    dirichlet_ids = [1, 3, 4]
    flow_solver = icepack.solvers.FlowSolver(model,
                                             dirichlet_ids=dirichlet_ids)

    r = firedrake.sqrt((x / Lx - 1 / 2)**2 + (y / Ly - 1 / 2)**2)
    R = 1 / 4
    expr = firedrake.max_value(0, δA * (1 - (r / R)**2))
    q_true = firedrake.interpolate(-n * firedrake.ln(1 + expr / A0), Q)
    u_true = flow_solver.diagnostic_solve(velocity=u_initial,
                                          thickness=h,
                                          log_fluidity=q_true)

    # Make the noise equal to 1% of the signal
    area = firedrake.assemble(firedrake.Constant(1) * dx(mesh))
    σ = 0.001 * icepack.norm(u_true) / np.sqrt(area)
    print(σ)

    u_obs = u_true.copy(deepcopy=True)
    shape = u_obs.dat.data_ro.shape
    u_obs.dat.data[:] += σ * random.standard_normal(shape) / np.sqrt(2)

    def callback(inverse_solver):
        E, R = inverse_solver.objective, inverse_solver.regularization
        misfit = firedrake.assemble(E) / area
        regularization = firedrake.assemble(R) / area
        q = inverse_solver.parameter
        error = firedrake.norm(q - q_true) / np.sqrt(area)
        print(misfit, regularization, error, flush=True)

    L = firedrake.Constant(0.25 * Lx)
    problem = icepack.inverse.InverseProblem(
        model=model,
        objective=lambda u: 0.5 * ((u - u_obs) / σ)**2 * dx,
        regularization=lambda q: 0.5 * L**2 * inner(grad(q), grad(q)) * dx,
        state_name="velocity",
        state=u_initial,
        parameter_name="log_fluidity",
        parameter=q_initial,
        solver_kwargs={"dirichlet_ids": dirichlet_ids},
        diagnostic_solve_kwargs={"thickness": h},
    )

    solver = solver_type(problem, callback)

    max_iterations = 100
    iterations = solver.solve(rtol=1e-2, atol=0, max_iterations=max_iterations)
    print(f"Number of iterations: {iterations}")

    assert iterations < max_iterations
    q = solver.parameter
    assert firedrake.norm(q - q_true) / firedrake.norm(q_initial -
                                                       q_true) < 1 / 3
예제 #13
0
def test_ice_shelf_inverse_with_noise(solver_type):
    import icepack
    Nx, Ny = 32, 32
    Lx, Ly = 20e3, 20e3

    u0 = 100
    h0, δh = 500, 100
    T0, δT = 254.15, 5.0
    A0 = icepack.rate_factor(T0)
    δA = icepack.rate_factor(T0 + δT) - A0

    def exact_u(x):
        ρ = ρ_I * (1 - ρ_I / ρ_W)
        Z = icepack.rate_factor(T0) * (ρ * g * h0 / 4)**n
        q = 1 - (1 - (δh / h0) * (x / Lx))**(n + 1)
        δu = Z * q * Lx * (h0 / δh) / (n + 1)
        return u0 + δu

    mesh = firedrake.RectangleMesh(Nx, Ny, Lx, Ly)
    degree = 2
    V = firedrake.VectorFunctionSpace(mesh, 'CG', degree)
    Q = firedrake.FunctionSpace(mesh, 'CG', degree)

    x, y = firedrake.SpatialCoordinate(mesh)
    u_initial = interpolate(as_vector((exact_u(x), 0)), V)
    q_initial = interpolate(firedrake.Constant(0), Q)
    h = interpolate(h0 - δh * x / Lx, Q)

    def viscosity(u, h, q):
        A = A0 * firedrake.exp(-q / n)
        return icepack.models.viscosity.viscosity_depth_averaged(u, h, A)

    ice_shelf = icepack.models.IceShelf(viscosity=viscosity)
    dirichlet_ids = [1, 3, 4]
    tol = 1e-12

    r = firedrake.sqrt((x / Lx - 1 / 2)**2 + (y / Ly - 1 / 2)**2)
    R = 1 / 4
    expr = firedrake.max_value(0, δA * (1 - (r / R)**2))
    q_true = firedrake.interpolate(-n * firedrake.ln(1 + expr / A0), Q)
    u_true = ice_shelf.diagnostic_solve(h=h,
                                        q=q_true,
                                        u0=u_initial,
                                        dirichlet_ids=dirichlet_ids,
                                        tol=tol)

    # Make the noise equal to 1% of the signal
    area = firedrake.assemble(firedrake.Constant(1) * dx(mesh))
    σ = 0.001 * icepack.norm(u_true) / np.sqrt(area)
    print(σ)

    u_obs = u_true.copy(deepcopy=True)
    shape = u_obs.dat.data_ro.shape
    u_obs.dat.data[:] += σ * random.standard_normal(shape) / np.sqrt(2)

    def callback(inverse_solver):
        E, R = inverse_solver.objective, inverse_solver.regularization
        misfit = firedrake.assemble(E) / area
        regularization = firedrake.assemble(R) / area
        q = inverse_solver.parameter
        error = firedrake.norm(q - q_true) / np.sqrt(area)
        print(misfit, regularization, error, flush=True)

    L = 0.25 * Lx
    regularization = L**2 / 2 * inner(grad(q_initial), grad(q_initial)) * dx
    problem = icepack.inverse.InverseProblem(
        model=ice_shelf,
        method=icepack.models.IceShelf.diagnostic_solve,
        objective=lambda u: 0.5 * ((u - u_obs) / σ)**2 * dx,
        regularization=lambda q: 0.5 * L**2 * inner(grad(q), grad(q)) * dx,
        state_name='u',
        state=u_initial,
        parameter_name='q',
        parameter=q_initial,
        model_args={
            'h': h,
            'u0': u_initial,
            'tol': tol
        },
        dirichlet_ids=dirichlet_ids)

    solver = solver_type(problem, callback)

    max_iterations = 100
    iterations = solver.solve(rtol=1e-2, atol=0, max_iterations=max_iterations)
    print('Number of iterations: {}'.format(iterations))

    assert iterations < max_iterations
    q = solver.parameter
    assert firedrake.norm(q - q_true) / firedrake.norm(q_initial -
                                                       q_true) < 1 / 3
예제 #14
0
def test_ice_shelf_inverse(solver_type):
    import icepack
    Nx, Ny = 32, 32
    Lx, Ly = 20e3, 20e3

    u0 = 100
    h0, δh = 500, 100
    T0, δT = 254.15, 5.0
    A0 = icepack.rate_factor(T0)
    δA = icepack.rate_factor(T0 + δT) - A0

    def exact_u(x):
        ρ = ρ_I * (1 - ρ_I / ρ_W)
        Z = icepack.rate_factor(T0) * (ρ * g * h0 / 4)**n
        q = 1 - (1 - (δh / h0) * (x / Lx))**(n + 1)
        δu = Z * q * Lx * (h0 / δh) / (n + 1)
        return u0 + δu

    mesh = firedrake.RectangleMesh(Nx, Ny, Lx, Ly)
    degree = 2
    V = firedrake.VectorFunctionSpace(mesh, 'CG', degree)
    Q = firedrake.FunctionSpace(mesh, 'CG', degree)

    x, y = firedrake.SpatialCoordinate(mesh)
    u_initial = interpolate(as_vector((exact_u(x), 0)), V)
    q_initial = interpolate(firedrake.Constant(0), Q)
    h = interpolate(h0 - δh * x / Lx, Q)

    def viscosity(u, h, q):
        A = A0 * firedrake.exp(-q / n)
        return icepack.models.viscosity.viscosity_depth_averaged(u, h, A)

    ice_shelf = icepack.models.IceShelf(viscosity=viscosity)
    dirichlet_ids = [1, 3, 4]
    tol = 1e-12

    r = firedrake.sqrt((x / Lx - 1 / 2)**2 + (y / Ly - 1 / 2)**2)
    R = 1 / 4
    expr = firedrake.max_value(0, δA * (1 - (r / R)**2))
    q_true = firedrake.interpolate(-n * firedrake.ln(1 + expr / A0), Q)
    u_true = ice_shelf.diagnostic_solve(h=h,
                                        q=q_true,
                                        u0=u_initial,
                                        dirichlet_ids=dirichlet_ids,
                                        tol=tol)

    area = firedrake.assemble(firedrake.Constant(1) * dx(mesh))

    def callback(inverse_solver):
        E, R = inverse_solver.objective, inverse_solver.regularization
        misfit = firedrake.assemble(E) / area
        regularization = firedrake.assemble(R) / area
        q = inverse_solver.parameter
        error = firedrake.norm(q - q_true) / np.sqrt(area)
        print(misfit, regularization, error)

    L = 1e-4 * Lx
    problem = icepack.inverse.InverseProblem(
        model=ice_shelf,
        method=icepack.models.IceShelf.diagnostic_solve,
        objective=lambda u: 0.5 * (u - u_true)**2 * dx,
        regularization=lambda q: 0.5 * L**2 * inner(grad(q), grad(q)) * dx,
        state_name='u',
        state=u_initial,
        parameter_name='q',
        parameter=q_initial,
        model_args={
            'h': h,
            'u0': u_initial,
            'tol': tol
        },
        dirichlet_ids=dirichlet_ids)

    solver = solver_type(problem, callback)

    # Set an absolute tolerance so that we stop whenever the RMS velocity
    # errors are less than 0.1 m/yr
    area = firedrake.assemble(firedrake.Constant(1) * dx(mesh))
    atol = 0.5 * 0.01 * area
    max_iterations = 100
    iterations = solver.solve(rtol=0, atol=atol, max_iterations=max_iterations)
    print('Number of iterations: {}'.format(iterations))

    assert iterations < max_iterations
    q = solver.parameter
    assert firedrake.norm(q - q_true) / firedrake.norm(q_initial -
                                                       q_true) < 1 / 4
예제 #15
0
def test_greens_formula(degree, family, ambient_dim):

    fine_order = 4 * degree
    # Parameter to tune accuracy of pytential
    fmm_order = 5
    # This should be (order of convergence = qbx_order + 1)
    qbx_order = degree
    with_refinement = True

    qbx_kwargs = {
        'fine_order': fine_order,
        'fmm_order': fmm_order,
        'qbx_order': qbx_order
    }

    if ambient_dim == 2:
        mesh = mesh2d
        r"""
        ..math:

            \ln(\sqrt{(x+1)^2 + (y+1)^2})

        i.e. a shift of the fundamental solution
        """
        x, y = fd.SpatialCoordinate(mesh)
        expr = fd.ln(fd.sqrt((x + 2)**2 + (y + 2)**2))
    elif ambient_dim == 3:
        mesh = mesh3d
        x, y, z = fd.SpatialCoordinate(mesh)
        r"""
        ..math:

            \f{1}{4\pi \sqrt{(x-2)^2 + (y-2)^2 + (z-2)^2)}}

        i.e. a shift of the fundamental solution
        """
        expr = fd.Constant(1 / 4 / fd.pi) * 1 / fd.sqrt((x - 2)**2 +
                                                        (y - 2)**2 +
                                                        (z - 2)**2)
    else:
        raise ValueError("Ambient dimension must be 2 or 3, not %s" %
                         ambient_dim)

    # Let's compute some layer potentials!
    V = fd.FunctionSpace(mesh, family, degree)
    Vdim = fd.VectorFunctionSpace(mesh, family, degree)

    mesh_analog = fd2mm.MeshAnalog(mesh)
    fspace_analog = fd2mm.FunctionSpaceAnalog(cl_ctx, mesh_analog, V)

    true_sol = fd.Function(V).interpolate(expr)
    grad_true_sol = fd.Function(Vdim).interpolate(fd.grad(expr))

    # Let's create an operator which plugs in f, \partial_n f
    # to Green's formula

    sigma = sym.make_sym_vector("sigma", ambient_dim)
    op = -(sym.D(
        LaplaceKernel(ambient_dim), sym.var("u"), qbx_forced_limit=None) -
           sym.S(LaplaceKernel(ambient_dim),
                 sym.n_dot(sigma),
                 qbx_forced_limit=None))

    from meshmode.mesh import BTAG_ALL
    outer_bdy_id = BTAG_ALL

    # Think of this like :mod:`pytential`'s :function:`bind`
    pyt_op = fd2mm.fd_bind(cl_ctx,
                           fspace_analog,
                           op,
                           source=(V, outer_bdy_id),
                           target=V,
                           qbx_kwargs=qbx_kwargs,
                           with_refinement=with_refinement)

    # Compute the operation and store in result
    result = fd.Function(V)

    pyt_op(queue, u=true_sol, sigma=grad_true_sol, result_function=result)

    # Compare with f
    fnorm = fd.sqrt(fd.assemble(fd.inner(true_sol, true_sol) * fd.dx))
    l2_err = fd.sqrt(
        fd.assemble(fd.inner(true_sol - result, true_sol - result) * fd.dx))
    rel_l2_err = l2_err / fnorm

    # TODO: Make this more strict
    assert rel_l2_err < 0.09