def run_advection_diffusion(tmpdir):

    # Mesh, state and equation
    L = 10
    mesh = PeriodicIntervalMesh(20, L)
    dt = 0.02
    tmax = 1.0

    diffusion_params = DiffusionParameters(kappa=0.75, mu=5)
    output = OutputParameters(dirname=str(tmpdir), dumpfreq=25)
    state = State(mesh, dt=dt, output=output)
    V = state.spaces("DG", "DG", 1)
    Vu = VectorFunctionSpace(mesh, "CG", 1)

    equation = AdvectionDiffusionEquation(
        state, V, "f", Vu=Vu, diffusion_parameters=diffusion_params)

    problem = [(equation, ((SSPRK3(state), transport), (BackwardEuler(state),
                                                        diffusion)))]

    # Initial conditions
    x = SpatialCoordinate(mesh)
    xc_init = 0.25 * L
    xc_end = 0.75 * L
    umax = 0.5 * L / tmax

    # Get minimum distance on periodic interval to xc
    x_init = conditional(
        sqrt((x[0] - xc_init)**2) < 0.5 * L, x[0] - xc_init,
        L + x[0] - xc_init)

    x_end = conditional(
        sqrt((x[0] - xc_end)**2) < 0.5 * L, x[0] - xc_end, L + x[0] - xc_end)

    f_init = 5.0
    f_end = f_init / 2.0
    f_width_init = L / 10.0
    f_width_end = f_width_init * 2.0
    f_init_expr = f_init * exp(-(x_init / f_width_init)**2)
    f_end_expr = f_end * exp(-(x_end / f_width_end)**2)

    state.fields('f').interpolate(f_init_expr)
    state.fields('u').interpolate(as_vector([Constant(umax)]))
    f_end = state.fields('f_end', V).interpolate(f_end_expr)

    # Time stepper
    timestepper = PrescribedTransport(state, problem)
    timestepper.run(0, tmax=tmax)

    error = norm(state.fields('f') - f_end) / norm(f_end)

    return error
Esempio n. 2
0
    def n_min(self, n_min, apply_to_preconditioner=False):
        """Ensure n \geq n_min everywhere.

        If apply_to_preconditioner is True,then this is only done to the
        preconditioner."""

        if apply_to_preconditioner:
            self.set_n_pre(
                fd.conditional(fd.lt(fd.real(self._n_pre), n_min), n_min,
                               self._n_pre))

        else:
            self.set_n(
                fd.conditional(fd.lt(fd.real(self._n), n_min), n_min, self._n))
Esempio n. 3
0
    def __init__(self, state, accretion=True, accumulation=True):
        super().__init__(state)

        # obtain our fields
        self.water_c = state.fields('water_c')
        self.rain = state.fields('rain')

        # declare function space
        Vt = self.water_c.function_space()

        # define some parameters as attributes
        dt = state.timestepping.dt
        k_1 = Constant(0.001)  # accretion rate in 1/s
        k_2 = Constant(2.2)  # accumulation rate in 1/s
        a = Constant(0.001)  # min cloud conc in kg/kg
        b = Constant(0.875)  # power for rain in accumulation

        # make default rates to be zero
        accr_rate = Constant(0.0)
        accu_rate = Constant(0.0)

        if accretion:
            accr_rate = k_1 * (self.water_c - a)
        if accumulation:
            accu_rate = k_2 * self.water_c * self.rain**b

        # make coalescence rate function, that needs to be the same for all updates in one time step
        coalesce_rate = Function(Vt)

        # adjust coalesce rate using min_value so negative cloud concentration doesn't occur
        self.lim_coalesce_rate = Interpolator(
            conditional(
                self.rain < 0.0,  # if rain is negative do only accretion
                conditional(accr_rate < 0.0, 0.0,
                            min_value(accr_rate, self.water_c / dt)),
                # don't turn rain back into cloud
                conditional(
                    accr_rate + accu_rate < 0.0,
                    0.0,
                    # if accretion rate is negative do only accumulation
                    conditional(
                        accr_rate < 0.0, min_value(accu_rate,
                                                   self.water_c / dt),
                        min_value(accr_rate + accu_rate, self.water_c / dt)))),
            coalesce_rate)

        # tell the prognostic fields what to update to
        self.water_c_new = Interpolator(self.water_c - dt * coalesce_rate, Vt)
        self.rain_new = Interpolator(self.rain + dt * coalesce_rate, Vt)
 def setup_constants(self):
     x, y = fd.SpatialCoordinate(self.mesh)
     self.constants = {
         'deltat':
         fd.Constant(self.prm['dt']),
         'Kd':
         fd.Constant(0.01),
         'k1':
         fd.Constant(0.005),
         'k2':
         fd.Constant(0.00005),
         'lamd1':
         fd.Constant(0.000005),
         'lamd2':
         fd.Constant(0.0),
         'rho_s':
         fd.Constant(1.),
         'L':
         fd.Constant(1.),
         'phi':
         fd.Constant(0.3),
         'n':
         fd.FacetNormal(self.mesh),
         'f':
         fd.Constant((0.0, 0.0)),
         'nu':
         fd.Constant(0.001),
         'frac':
         fd.Constant(1.),
         'source1':
         fd.conditional(
             pow(x - 1, 2) + pow(y - 1.5, 2) < 0.25 * 0.25, 10.0, 0)
     }
Esempio n. 5
0
def terminus(u, h, s):
    r"""Return the terminal stress part of the ice stream action functional

    The power exerted due to stress at the ice calving terminus :math:`\Gamma`
    is

    .. math::
       E(u) = \frac{1}{2}\int_\Gamma\left(\rho_Igh^2 - \rho_Wgd^2\right)
       u\cdot \nu\, ds

    where :math:`d` is the water depth at the terminus. We assume that sea
    level is at :math:`z = 0` for purposes of calculating the water depth.

    Parameters
    ----------
    u : firedrake.Function
        ice velocity
    h : firedrake.Function
        ice thickness
    s : firedrake.Function
        ice surface elevation
    ice_front_ids : list of int
        numeric IDs of the parts of the boundary corresponding to the
        calving front
    """
    from firedrake import conditional, lt
    d = conditional(lt(s - h, 0), s - h, 0)

    τ_I = ρ_I * g * h**2 / 2
    τ_W = ρ_W * g * d**2 / 2

    ν = firedrake.FacetNormal(u.ufl_domain())
    return (τ_I - τ_W) * inner(u, ν)
Esempio n. 6
0
    def residual(self, test, trial, trial_lagged, fields, bcs):
        u_adv = trial_lagged
        phi = test
        n = self.n
        u = trial

        F = -dot(u, div(outer(phi, u_adv)))*self.dx

        for id, bc in bcs.items():
            if 'u' in bc:
                u_in = bc['u']
            elif 'un' in bc:
                u_in = bc['un'] * n  # this implies u_t=0 on the inflow
            else:
                u_in = zero(self.dim)
            F += conditional(dot(u_adv, n) < 0,
                             dot(phi, u_in)*dot(u_adv, n),
                             dot(phi, u)*dot(u_adv, n)) * self.ds(id)

        if not (is_continuous(self.trial_space) and normal_is_continuous(u_adv)):
            # s=0: u.n(-)<0  =>  flow goes from '+' to '-' => '+' is upwind
            # s=1: u.n(-)>0  =>  flow goes from '-' to '+' => '-' is upwind
            s = 0.5*(sign(dot(avg(u), n('-'))) + 1.0)
            u_up = u('-')*s + u('+')*(1-s)
            F += dot(u_up, (dot(u_adv('+'), n('+'))*phi('+') + dot(u_adv('-'), n('-'))*phi('-'))) * self.dS

        return -F
    def build(self):
        """
        Build the conditionally valued firedrake function.

        Raises:
            AttributeError: If required properties are not defined.
            AttributeError: If operator not in allows list.

        Returns:
            Function:
                firedrake function set to 1 where the condition is met and 0
                where it is not.
        """
        for k in self.properties:
            if self._props[k] is None:
                raise AttributeError('"{}" has not been defined.'.format(k))

        op = self._props['operator']
        lhs = self._props['lhs']
        rhs = self._props['rhs']

        if op not in self._dispatch_table:
            raise AttributeError('Unknown condition: {}'.format(op))

        val = conditional(self._dispatch_table[op](lhs, rhs), 1, 0)
        return Function(self.V).interpolate(val)
Esempio n. 8
0
def rate_factor(T):
    r"""Compute the rate factor in Glen's flow law for a given temperature

    The strain rate :math:`\dot\varepsilon` of ice resulting from a stress
    :math:`\tau` is

    .. math::
       \dot\varepsilon = A(T)\tau^3

    where :math:`A(T)` is the temperature-dependent rate factor:

    .. math::
       A(T) = A_0\exp(-Q/RT)

    where :math:`R` is the ideal gas constant, :math:`Q` has units of
    energy per mole, and :math:`A_0` is a prefactor with units of
    pressure :math:`\text{MPa}^{-3}\times\text{yr}^{-1}`.

    Parameters
    ----------
    T : float, np.ndarray, or UFL expression
        The ice temperature

    Returns
    -------
    A : same type as T
        The ice fluidity
    """
    import ufl

    if isinstance(T, ufl.core.expr.Expr):
        cold = firedrake.lt(T, transition_temperature)
        A0 = firedrake.conditional(cold, A0_cold, A0_warm)
        Q = firedrake.conditional(cold, Q_cold, Q_warm)
        A = A0 * firedrake.exp(-Q / (R * T))
        if isinstance(T, firedrake.Constant):
            return firedrake.Constant(A)

        return A

    cold = T < transition_temperature
    warm = ~cold if isinstance(T, np.ndarray) else (not cold)
    A0 = A0_cold * cold + A0_warm * warm
    Q = Q_cold * cold + Q_warm * warm

    return A0 * np.exp(-Q / (R * T))
Esempio n. 9
0
def new_max(a, b):
    """Helper function for f.

    a and b can be dimensions of a UFL SpatialCoordinate.
    """

    return fd.conditional(fd.eq(a, b), a,
                          heaviside(b - a) * b + heaviside(a - b) * a)
Esempio n. 10
0
 def _psi(self, a, dt, u, c):
     '''The top-surface boundary value for c.  Where ice is present this
     is built using the surface mass balance value.'''
     # FIXME only set up for b=0
     # FIXME criteria for significant ice is lame: "h > 1.1 Href"
     # FIXME assumes h^{n-1} = lambda (where there is significant ice)
     x = fd.SpatialCoordinate(self.mesh)
     h = x[self.k] + c
     dhdt = a - self._tangentu(u, x[self.k]) + u[self.k]
     return fd.conditional(h > 1.1 * self.Href, dt * dhdt, 0.0 - x[self.k])
Esempio n. 11
0
    def __init__(self, dq1_space):
        v = TestFunction(dq1_space)
        # nodes on squeezed facets are not included in dS_v or ds_v
        # and all other nodes are (for DQ1), so this step gives nonzero for these other nodes
        self.marker = assemble(avg(v) * dS_v + v * ds_v)
        # flip this: 1 for squeezed nodes, and 0 for all others
        self.marker.assign(conditional(self.marker > 1e-12, 0, 1))

        self.P0 = FunctionSpace(dq1_space.mesh(), "DG", 0)
        self.u0 = Function(self.P0, name='averaged squeezed values')
        self.u1 = Function(dq1_space, name='aux. squeezed values')
Esempio n. 12
0
 def surface_force(self):
     A = 1.
     d = 0.9 * self.Lz
     l = 0.1 * self.Lz
     T = fd.Function(self.V)
     T.interpolate(
         fd.conditional(
             self.X[2] > d,
             fd.as_vector(
                 [A * fd.sin((self.X[2] - d) / l * fd.pi / 2.)**2, 0., 0.]),
             fd.as_vector([0., 0., 0.])))  # surface force / area
     return T
Esempio n. 13
0
def test_read_and_write_segy():
    vp_name = "velocity_models/test"
    segy_file = vp_name + ".segy"
    hdf5_file = vp_name + ".hdf5"
    mesh = fire.UnitSquareMesh(10, 10)
    mesh.coordinates.dat.data[:, 0] *= -1

    V = fire.FunctionSpace(mesh, 'CG', 3)
    x, y = fire.SpatialCoordinate(mesh)
    r = 0.2
    xc = -0.5
    yc = 0.5

    vp = fire.Function(V)

    c = fire.conditional((x - xc)**2 + (y - yc)**2 < r**2, 3.0, 1.5)

    vp.interpolate(c)

    xi, yi, zi = spyro.io.write_function_to_grid(vp, V, 10.0 / 1000.0)
    spyro.io.create_segy(zi, segy_file)
    write_velocity_model(segy_file, vp_name)

    model = {}

    model["opts"] = {
        "method": "CG",  # either CG or KMV
        "quadrature": "CG",  # Equi or KMV
        "degree": 3,  # p order
        "dimension": 2,  # dimension
    }
    model["mesh"] = {
        "Lz": 1.0,  # depth in km - always positive
        "Lx": 1.0,  # width in km - always positive
        "Ly": 0.0,  # thickness in km - always positive
        "meshfile": None,
        "initmodel": None,
        "truemodel": hdf5_file,
    }
    model["BCs"] = {
        "status": False,
    }

    vp_read = spyro.io.interpolate(model, mesh, V, guess=False)

    fire.File("velocity_models/test.pvd").write(vp_read)

    value_at_center = vp_read.at(xc, yc)
    test1 = math.isclose(value_at_center, 3.0)
    value_outside_circle = vp_read.at(xc + r + 0.1, yc)
    test2 = math.isclose(value_outside_circle, 1.5)
    assert all([test1, test2])
 def setup_constants(self):
     x, y = fd.SpatialCoordinate(self.mesh)
     self.constants = {
         'deltat':
         fd.Constant(self.prm['dt']),
         'n':
         fd.FacetNormal(self.mesh),
         'f':
         fd.Constant((0.0, 0.0)),
         'nu':
         fd.Constant(0.001),
         'eps':
         fd.Constant(0.01),
         'K':
         fd.Constant(10.0),
         'f_1':
         fd.conditional(
             pow(x - 0.1, 2) + pow(y - 0.1, 2) < 0.05 * 0.05, 0.1, 0),
         'f_2':
         fd.conditional(
             pow(x - 0.1, 2) + pow(y - 0.3, 2) < 0.05 * 0.05, 0.1, 0),
         'f_3':
         fd.Constant(0.0)
     }
Esempio n. 15
0
    def sources(self, **kwargs):
        keys = ("damage", "velocity", "strain_rate", "membrane_stress")
        D, u, ε, M = itemgetter(*keys)(kwargs)

        # Increase/decrease damage depending on stress and strain rates
        ε_1 = eigenvalues(ε)[0]
        σ_e = sqrt(inner(M, M) - det(M))

        ε_h = firedrake.Constant(self.healing_strain_rate)
        σ_d = firedrake.Constant(self.damage_stress)
        γ_h = firedrake.Constant(self.healing_rate)
        γ_d = firedrake.Constant(self.damage_rate)

        healing = γ_h * min_value(ε_1 - ε_h, 0)
        fracture = γ_d * conditional(σ_e - σ_d > 0, ε_1, 0.0) * (1 - D)

        return healing + fracture
Esempio n. 16
0
def setup_fallout(dirname):

    # declare grid shape, with length L and height H
    L = 10.
    H = 10.
    nlayers = 10
    ncolumns = 10

    # make mesh
    m = PeriodicIntervalMesh(ncolumns, L)
    mesh = ExtrudedMesh(m, layers=nlayers, layer_height=(H / nlayers))
    x = SpatialCoordinate(mesh)

    dt = 0.1
    output = OutputParameters(dirname=dirname + "/fallout",
                              dumpfreq=10,
                              dumplist=['rain_mixing_ratio'])
    parameters = CompressibleParameters()
    diagnostic_fields = [Precipitation()]
    state = State(mesh,
                  dt=dt,
                  output=output,
                  parameters=parameters,
                  diagnostic_fields=diagnostic_fields)

    Vrho = state.spaces("DG1_equispaced")
    problem = [(AdvectionEquation(state, Vrho, "rho", ufamily="CG",
                                  udegree=1), ForwardEuler(state))]
    state.fields("rho").assign(1.)

    physics_list = [Fallout(state)]
    rain0 = state.fields("rain_mixing_ratio")

    # set up rain
    xc = L / 2
    zc = H / 2
    rc = H / 4
    r = sqrt((x[0] - xc)**2 + (x[1] - zc)**2)
    rain_expr = conditional(r > rc, 0., 1e-3 * (cos(pi * r / (rc * 2)))**2)

    rain0.interpolate(rain_expr)

    # build time stepper
    stepper = PrescribedTransport(state, problem, physics_list=physics_list)

    return stepper, 10.0
Esempio n. 17
0
    def sources(self, **kwargs):
        keys = ('damage', 'velocity', 'strain_rate', 'membrane_stress')
        keys_alt = ('D', 'u', 'ε', 'M')
        D, u, ε, M = get_kwargs_alt(kwargs, keys, keys_alt)

        # Increase/decrease damage depending on stress and strain rates
        ε_1 = eigenvalues(ε)[0]
        σ_e = sqrt(inner(M, M) - det(M))

        ε_h = firedrake.Constant(self.healing_strain_rate)
        σ_d = firedrake.Constant(self.damage_stress)
        γ_h = firedrake.Constant(self.healing_rate)
        γ_d = firedrake.Constant(self.damage_rate)

        healing = γ_h * min_value(ε_1 - ε_h, 0)
        fracture = γ_d * conditional(σ_e - σ_d > 0, ε_1, 0.) * (1 - D)

        return healing + fracture
Esempio n. 18
0
def writesolutiongeometry(filename, refmesh, mzfine, upc):
    # get fields on reference mesh
    u, p, c = upc.split()

    # compute h on base mesh as updated surface elevation
    #   h(x,y) = lambda(x,y) + c(x,y,lambda(x,y))
    lambase = surfaceelevation(refmesh)  # bounded below by Href; space Q1base
    cbase, Q1base = _surfacevalue(refmesh, c)
    hbase0 = fd.Function(Q1base).interpolate(lambase + cbase)
    hbase = fd.Function(Q1base)
    hbase.interpolate(fd.conditional(hbase0 > 0.0, hbase0, 0.0))

    # duplicate fine mesh and extend h onto it
    mesh = extrudedmesh(refmesh._base_mesh,
                        mzfine,
                        refine=-1,
                        temporary_height=1.0)
    h = extend(mesh, hbase)

    # change mesh coordinate to linear times h
    Vcoord = mesh.coordinates.function_space()
    if mesh._base_mesh.cell_dimension() == 1:
        x, z = fd.SpatialCoordinate(mesh)
        Xnew = fd.Function(Vcoord).interpolate(fd.as_vector([x, h * z]))
    elif mesh._base_mesh.cell_dimension() == 2:
        x, y, z = fd.SpatialCoordinate(mesh)
        Xnew = fd.Function(Vcoord).interpolate(fd.as_vector([x, y, h * z]))
    else:
        raise ValueError('applies only to 2D and 3D extruded meshes')
    mesh.coordinates.assign(Xnew)

    # interpolate velocity u and pressure p from refmesh onto mesh and write
    Vu, Vp, _ = vectorspaces(mesh)
    unew = fd.Function(Vu)
    pnew = fd.Function(Vp)
    unew.rename('velocity')
    pnew.rename('pressure')
    # note f.at() searches for element to evaluate (thanks L Mitchell)
    print(Xnew.dat.data_ro)  # FIXME shows inadmissible z: too high
    unew.dat.data[:] = u.at(Xnew.dat.data_ro)
    pnew.dat.data[:] = p.at(Xnew.dat.data_ro)
    fd.File(filename).write(unew, pnew)
    return 0
Esempio n. 19
0
def test_inflow_boundary(scheme):
    start = 16
    finish = 3 * start
    incr = 4
    num_points = np.array(list(range(start, finish + incr, incr)))
    errors = np.zeros_like(num_points, dtype=np.float64)

    for k, nx in enumerate(num_points):
        mesh = firedrake.UnitSquareMesh(nx, nx, diagonal='crossed')
        degree = 1
        Q = firedrake.FunctionSpace(mesh, 'DG', 1)

        x = firedrake.SpatialCoordinate(mesh)
        U = Constant(1.)
        u = as_vector((U, 0.))

        q_in = Constant(1.)
        s = Constant(0.)

        final_time = 0.5
        min_diameter = mesh.cell_sizes.dat.data_ro[:].min()
        max_speed = 1.
        multiplier = multipliers[scheme] / 2
        timestep = multiplier * min_diameter / max_speed / (2 * degree + 1)
        num_steps = int(final_time / timestep)
        dt = final_time / num_steps

        q_0 = firedrake.project(q_in - x[0], Q)
        equation = plumes.models.advection.make_equation(u, s, q_in)
        integrator = scheme(equation, q_0)

        for step in range(num_steps):
            integrator.step(dt)

        q = integrator.state
        T = Constant(final_time)
        expr = q_in - firedrake.conditional(x[0] > U * T, x[0] - U * T, 0)
        errors[k] = assemble(abs(q - expr) * dx) / assemble(abs(expr) * dx)

    slope, intercept = np.polyfit(np.log2(1 / num_points), np.log2(errors), 1)
    print(f'log(error) ~= {slope:5.3f} * log(dx) {intercept:+5.3f}')
    assert slope > degree - 0.1
Esempio n. 20
0
    def __init__(self,
                 salinity,
                 temperature,
                 pressure_perturbation,
                 z,
                 C,
                 r=7.5e-4):
        super().__init__(salinity, temperature, pressure_perturbation, z)

        epsilon = 0.0625  # aspect ratio of frazil ice disks = 1/16
        Nusselt = 1.0  # ratio of convective /conductive heat transfer.
        gammaT_frazil = Nusselt * self.kappa_T / (epsilon * r)
        gammaS_frazil = Nusselt * self.kappa_S / (epsilon * r)

        Aa = self.a
        Bb = -self.T + self.b + self.c * self.P_full
        Bb -= gammaS_frazil * self.Lf / (gammaT_frazil * self.c_p_m)
        Cc = self.S * gammaS_frazil * self.Lf / (gammaT_frazil * self.c_p_m)

        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.Sc = S1
                print("Choose S1")
            else:
                self.Sc = S2
                print("Choose S2")
        elif isinstance(S1, sympy.core.add.Add):
            self.Sc = S2
        else:
            self.Sc = conditional(S1 > 0.0, S1, S2)

        self.Tc = self.a * self.Sc + self.b + self.c * self.P_full
        self.wc = ((1 - C) * gammaS_frazil *
                   (self.S - self.Sc) * 2 * C / r) / self.Sc
Esempio n. 21
0
    def sources(self, **kwargs):
        keys = ('damage', 'velocity', 'fluidity')
        keys_alt = ('D', 'u', 'A')
        D, u, A = get_kwargs_alt(kwargs, keys, keys_alt)

        # Increase/decrease damage depending on stress and strain rates
        ε = sym(grad(u))
        ε_1 = eigenvalues(ε)[0]

        σ = M(ε, A)
        σ_e = sqrt(inner(σ, σ) - det(σ))

        ε_h = firedrake.Constant(self.healing_strain_rate)
        σ_d = firedrake.Constant(self.damage_stress)
        γ_h = firedrake.Constant(self.healing_rate)
        γ_d = firedrake.Constant(self.damage_rate)

        healing = γ_h * min_value(ε_1 - ε_h, 0)
        fracture = γ_d * conditional(σ_e - σ_d > 0, ε_1, 0.) * (1 - D)

        return healing + fracture
Esempio n. 22
0
    def residual(self, trial, trial_lagged, fields, bcs):
        u = fields['velocity']
        phi = self.test
        n = self.n
        q = trial

        F = q * div(phi * u) * self.dx

        for id, bc in bcs.items():
            if 'q' in bc:
                F -= conditional(
                    dot(u, n) < 0,
                    phi * dot(u, n) * bc['q'],
                    phi * dot(u, n) * q) * self.ds(id)

        if not (is_continuous(trial) and is_continuous(u)):
            # this is the same trick as in the DG_advection firedrake demo
            un = 0.5 * (dot(u, n) + abs(dot(u, n)))
            F -= (phi('+') - phi('-')) * (un('+') * q('+') -
                                          un('-') * q('-')) * self.dS

        return F
Esempio n. 23
0
ext_mesh = ExtrudedMesh(m, layers=nlayers, layer_height=H/nlayers)
Vc = VectorFunctionSpace(ext_mesh, "DG", 2)
coord = SpatialCoordinate(ext_mesh)
x = Function(Vc).interpolate(as_vector([coord[0], coord[1]]))
a = 1000.
xc = L/2.
x, z = SpatialCoordinate(ext_mesh)
hm = 1.
zs = hm*a**2/((x-xc)**2 + a**2)

smooth_z = True
dirname = 'nh_mountain'
if smooth_z:
    dirname += '_smootherz'
    zh = 5000.
    xexpr = as_vector([x, conditional(z < zh, z + cos(0.5*pi*z/zh)**6*zs, z)])
else:
    xexpr = as_vector([x, z + ((H-z)/H)*zs])

new_coords = Function(Vc).interpolate(xexpr)
mesh = Mesh(new_coords)

# sponge function
W_DG = FunctionSpace(mesh, "DG", 2)
x, z = SpatialCoordinate(mesh)
zc = H-10000.
mubar = 0.15/dt
mu_top = conditional(z <= zc, 0.0, mubar*sin((pi/2.)*(z-zc)/(H-zc))**2)
mu = Function(W_DG).interpolate(mu_top)
fieldlist = ['u', 'rho', 'theta']
timestepping = TimesteppingParameters(dt=dt)
Esempio n. 24
0
 def d2(s):
     return conditional(le(s, fd.Constant(1.0)), s - fd.Constant(1.0),
                        d1(s))
Esempio n. 25
0
    theta_b = Function(Vt).interpolate(Tsurf)
    rho_b = Function(Vr)

    # Calculate hydrostatic Pi
    compressible_hydrostatic_balance(state, theta_b, rho_b, solve_for_rho=True)

    x = SpatialCoordinate(mesh)
    a = 5.0e3
    deltaTheta = 1.0e-2
    xc = 0.5 * L
    xr = 4000.
    zc = 3000.
    zr = 2000.
    r = sqrt(((x[0] - xc) / xr)**2 + ((x[1] - zc) / zr)**2)
    theta_pert = conditional(r > 1., 0., -7.5 * (1. + cos(pi * r)))
    theta0.interpolate(theta_b + theta_pert)
    water0.interpolate(theta_pert)
    rho0.assign(rho_b)

    state.initialise([('u', u0), ('rho', rho0), ('theta', theta0),
                      ('water', water0)])
    state.set_reference_profiles([('rho', rho_b), ('theta', theta_b)])

    # Set up advection schemes
    ueqn = EulerPoincare(state, Vu)
    rhoeqn = AdvectionEquation(state, Vr, equation_form="continuity")
    supg = True
    if supg:
        thetaeqn = SUPGAdvection(state, Vt, equation_form="advective")
        watereqn = SUPGAdvection(state, Vt, equation_form="advective")
Esempio n. 26
0
theta_b = Function(Vt).interpolate(Constant(Tsurf))

# Calculate hydrostatic fields
compressible_hydrostatic_balance(state, theta_b, rho0, solve_for_rho=True)

# make mean fields
rho_b = Function(Vr).assign(rho0)

# define perturbation
xc = L / 2
zc = 2000.
rc = 2000.
Tdash = 2.0
r = sqrt((x - xc)**2 + (z - zc)**2)
theta_pert = Function(Vt).interpolate(
    conditional(r > rc, 0.0,
                Tdash * (cos(pi * r / (2.0 * rc)))**2))

# define initial theta
theta0.assign(theta_b * (theta_pert / 300.0 + 1.0))

# find perturbed rho
gamma = TestFunction(Vr)
rho_trial = TrialFunction(Vr)
lhs = gamma * rho_trial * dx
rhs = gamma * (rho_b * theta_b / theta0) * dx
rho_problem = LinearVariationalProblem(lhs, rhs, rho0)
rho_solver = LinearVariationalSolver(rho_problem)
rho_solver.solve()

state.set_reference_profiles([('rho', rho_b), ('theta', theta_b)])
Esempio n. 27
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)
Esempio n. 28
0
def domainify(vector, x):
    dim = len(x)
    return conditional(
        x[0] > 0.0, vector, as_vector(tuple(0.0 for _ in range(dim)))
    )
Esempio n. 29
0
def setup_condens(dirname):

    # declare grid shape, with length L and height H
    L = 1000.
    H = 1000.
    nlayers = int(H / 100.)
    ncolumns = int(L / 100.)

    # make mesh
    m = PeriodicIntervalMesh(ncolumns, L)
    mesh = ExtrudedMesh(m, layers=nlayers, layer_height=(H / nlayers))
    x = SpatialCoordinate(mesh)

    fieldlist = ['u', 'rho', 'theta']
    timestepping = TimesteppingParameters(dt=1.0, maxk=4, maxi=1)
    output = OutputParameters(dirname=dirname + "/condens",
                              dumpfreq=1,
                              dumplist=['u'],
                              perturbation_fields=['theta', 'rho'])
    parameters = CompressibleParameters()

    state = State(mesh,
                  vertical_degree=1,
                  horizontal_degree=1,
                  family="CG",
                  timestepping=timestepping,
                  output=output,
                  parameters=parameters,
                  fieldlist=fieldlist,
                  diagnostic_fields=[Sum('water_v', 'water_c')])

    # declare initial fields
    u0 = state.fields("u")
    rho0 = state.fields("rho")
    theta0 = state.fields("theta")

    # spaces
    Vpsi = FunctionSpace(mesh, "CG", 2)
    Vt = theta0.function_space()
    Vr = rho0.function_space()

    # make a gradperp
    gradperp = lambda u: as_vector([-u.dx(1), u.dx(0)])

    # declare tracer field and a background field
    water_v0 = state.fields("water_v", Vt)
    water_c0 = state.fields("water_c", Vt)

    # Isentropic background state
    Tsurf = Constant(300.)

    theta_b = Function(Vt).interpolate(Tsurf)
    rho_b = Function(Vr)

    # Calculate initial rho
    compressible_hydrostatic_balance(state, theta_b, rho_b, solve_for_rho=True)

    # set up water_v
    xc = 500.
    zc = 350.
    rc = 250.
    r = sqrt((x[0] - xc)**2 + (x[1] - zc)**2)
    w_expr = conditional(r > rc, 0., 0.25 * (1. + cos((pi / rc) * r)))

    # set up velocity field
    u_max = 10.0

    psi_expr = ((-u_max * L / pi) * sin(2 * pi * x[0] / L) *
                sin(pi * x[1] / L))

    psi0 = Function(Vpsi).interpolate(psi_expr)
    u0.project(gradperp(psi0))
    theta0.interpolate(theta_b)
    rho0.interpolate(rho_b)
    water_v0.interpolate(w_expr)

    state.initialise([('u', u0), ('rho', rho0), ('theta', theta0),
                      ('water_v', water_v0), ('water_c', water_c0)])
    state.set_reference_profiles([('rho', rho_b), ('theta', theta_b)])

    # set up advection schemes
    rhoeqn = AdvectionEquation(state, Vr, equation_form="continuity")
    thetaeqn = SUPGAdvection(state,
                             Vt,
                             supg_params={"dg_direction": "horizontal"},
                             equation_form="advective")

    # build advection dictionary
    advected_fields = []
    advected_fields.append(("u", NoAdvection(state, u0, None)))
    advected_fields.append(("rho", SSPRK3(state, rho0, rhoeqn)))
    advected_fields.append(("theta", SSPRK3(state, theta0, thetaeqn)))
    advected_fields.append(("water_v", SSPRK3(state, water_v0, thetaeqn)))
    advected_fields.append(("water_c", SSPRK3(state, water_c0, thetaeqn)))

    physics_list = [Condensation(state)]

    # build time stepper
    stepper = AdvectionDiffusion(state,
                                 advected_fields,
                                 physics_list=physics_list)

    return stepper, 5.0
Esempio n. 30
0
Kz = fd.Function(V)
phi = fd.Constat(0.2)

coords2ijk = np.vectorize(coords2ijk, excluded=['data_array', 'Delta'])

Kx.dat.data[...] = coords2ijk(coords[:, 0], coords[:, 1],
                                    coords[:, 2], Delta=Delta, data_array=kx_array)
Ky.dat.data[...] = coords2ijk(coords[:, 0], coords[:, 1],
                                    coords[:, 2], Delta=Delta, data_array=ky_array)
Kz.dat.data[...] = coords2ijk(coords[:, 0], coords[:, 1],
                                    coords[:, 2], Delta=Delta, data_array=kz_array)

print("END: Read in reservoir fields")

# Permeability field harmonic interpolation to facets
Kx_facet = fd.conditional(fd.gt(fd.avg(Kx), 0.0), Kx('+')*Kx('-') / fd.avg(Kx), 0.0)
Ky_facet = fd.conditional(fd.gt(fd.avg(Ky), 0.0), Ky('+')*Ky('-') / fd.avg(Ky), 0.0)
Kz_facet = fd.conditional(fd.gt(fd.avg(Kz), 0.0), Kz('+')*Kz('-') / fd.avg(Kz), 0.0)

# We can now define the bilinear and linear forms for the left and right
dx = fd.dx
KdivU = fd.as_vector((Kx_facet*u.dx(0), Ky_facet*u.dx(1), Kz_facet*u.dx(2)))
a = (fd.dot(KdivU, fd.grad(v))) * dx
m = u * v * phi * dx

# Defining the eigenvalue problem

petsc_a = fd.assemble(a).M.handle
petsc_m = fd.assemble(m).M.handle

num_eigenvalues = 3
Esempio n. 31
0
def pml(mesh,
        scatterer_bdy_id,
        outer_bdy_id,
        wave_number,
        options_prefix=None,
        solver_parameters=None,
        inner_region=None,
        fspace=None,
        tfspace=None,
        true_sol_grad=None,
        pml_type=None,
        delta=None,
        quad_const=None,
        speed=None,
        pml_min=None,
        pml_max=None):
    """
        For unlisted arg descriptions, see run_method

        :arg inner_region: boundary id of non-pml region
        :arg pml_type: Type of pml function, either 'quadratic' or 'bdy_integral'
        :arg delta: For :arg:`pml_type` of 'bdy_integral', added to denominator
                    to prevent 1 / 0 at edge of boundary
        :arg quad_const: For :arg:`pml_type` of 'quadratic', a scaling constant
        :arg speed: Speed of sound
        :arg pml_min: A list, *pml_min[i]* is where to begin pml layer in direction
                      *i*
        :arg pml_max: A list, *pml_max[i]* is where to end pml layer in direction *i*
    """
    # Handle defauls
    if pml_type is None:
        pml_type = 'bdy_integral'
    if delta is None:
        delta = 1e-3
    if quad_const is None:
        quad_const = 1.0
    if speed is None:
        speed = 340.0

    pml_types = ['bdy_integral', 'quadratic']
    if pml_type not in pml_types:
        raise ValueError("PML type of %s is not one of %s" %
                         (pml_type, pml_types))

    xx = SpatialCoordinate(mesh)
    # {{{ create sigma functions for PML
    sigma = None
    if pml_type == 'bdy_integral':
        sigma = [
            Constant(speed) / (Constant(delta + extent) - abs(coord))
            for extent, coord in zip(pml_max, xx)
        ]
    elif pml_type == 'quadratic':
        sigma = [
            Constant(quad_const) * (abs(coord) - Constant(min_))**2
            for min_, coord in zip(pml_min, xx)
        ]
    r"""
        Here \kappa is the wave number and c is the speed

        ..math::

        \kappa = \frac{ \omega } { c }
    """
    omega = wave_number * speed

    # {{{ Set up PML functions
    gamma = [
        Constant(1.0) + conditional(
            abs(real(coord)) >= real(min_),
            Constant(1j / omega) * sigma_i, Constant(0.0))
        for min_, coord, sigma_i in zip(pml_min, xx, sigma)
    ]

    kappa = [None] * len(gamma)
    gamma_prod = 1.0
    for i in range(len(gamma)):
        gamma_prod *= gamma[i]
        tensor_i = [Constant(0.0) for _ in range(len(gamma))]
        tensor_i[i] = 1.0
        r"""
            *i*th entry is

            .. math::

            \frac{\prod_{j\neq i} \gamma_j}{ \gamma_i }
        """
        for j in range(len(gamma)):
            if j != i:
                tensor_i[i] *= gamma[j]
            else:
                tensor_i[i] /= gamma[j]
        kappa[i] = tensor_i

    kappa = as_tensor(kappa)

    # }}}

    p = TrialFunction(fspace)
    q = TestFunction(fspace)

    k = wave_number  # Just easier to look at
    a = (inner(dot(grad(p), kappa), grad(q)) -
         Constant(k**2) * gamma_prod * inner(p, q)) * dx

    n = FacetNormal(mesh)
    L = inner(dot(true_sol_grad, n), q) * ds(scatterer_bdy_id)

    bc = DirichletBC(fspace, Constant(0), outer_bdy_id)

    solution = Function(fspace)

    #solve(a == L, solution, bcs=[bc], options_prefix=options_prefix)
    # Create a solver and return the KSP object with the solution so that can get
    # PETSc information
    # Create problem
    problem = vs.LinearVariationalProblem(a, L, solution, [bc], None)
    # Create solver and call solve
    solver = vs.LinearVariationalSolver(problem,
                                        solver_parameters=solver_parameters,
                                        options_prefix=options_prefix)
    solver.solve()

    return solver.snes, solution