Source code for stride.physics.boundaries.devito


from ..common.devito import devito
import numpy as np

from .boundary import Boundary


class SpongeBoundary1(Boundary):

    def __init__(self, grid):
        """
        Sponge boundary for elastic codes
        """
        super().__init__(grid)

        self.damp = None

    def apply(self, field, velocity, direction='forward', **kwargs):
        space = self._grid.space
        time = self._grid.time

        reflection_coefficient = 10**(-(np.log10(max(*space.absorbing)) - 1)/np.log10(2) - 3)
        reflection_coefficient = kwargs.pop('reflection_coefficient', reflection_coefficient)

        if np.max(space.extra) > 0:
            damp = self._grid.function('damp')
            damp.data[:] = self.damping(velocity=velocity,
                                        reflection_coefficient=reflection_coefficient,
                                        mask=True, **kwargs) * time.step
        else:
            damp = 0

        self.damp = damp
        return None, [], []


[docs] class SpongeBoundary2(Boundary): """ Sponge boundary layer for a second-order equation as proposed in https://doi.org/10.1088/1742-2140/aaa4da. """ def __init__(self, grid): super().__init__(grid) self.damp = None
[docs] def apply(self, field, velocity, direction='forward', **kwargs): space = self._grid.space time = self._grid.time reflection_coefficient = 10 ** (-(np.log10(max(*space.absorbing)) - 1) / np.log10(2) - 3) reflection_coefficient = kwargs.pop('reflection_coefficient', reflection_coefficient) if np.max(space.extra) > 0: damp = self._grid.function('damp') damp.data[:] = 7 * self.damping(velocity=velocity, reflection_coefficient=reflection_coefficient, **kwargs) * time.step else: damp = 0 self.damp = damp u_dt = field.dtc if direction == 'forward' else field.dtc.T damping_term = 2*damp*u_dt + damp**2*field return damping_term, [], []
[docs] class ComplexFrequencyShiftPML2(Boundary): """ Complex frequency shift PML for a second-order equation as presented in https://doi.org/10.1121/1.4938270. """ def __init__(self, grid): super().__init__(grid)
[docs] def apply(self, field, velocity, direction='forward', **kwargs): space = self._grid.space reflection_coefficient = 10**(-(np.log10(max(*space.absorbing)) - 1)/np.log10(2) - 3) reflection_coefficient = kwargs.pop('reflection_coefficient', reflection_coefficient) f_centre = kwargs.pop('f_centre') subs = kwargs.pop('subs', None) abox = kwargs.pop('abox', None) dimensions = self._grid.devito_grid.dimensions shape = space.extended_shape eq_preparation = [] eq_before = [] eq_after = [] boundary_term = [] for dim_i in range(space.dim): dim = dimensions[dim_i] # Create damping functions sigma_i = self._grid.function('sigma_%d' % dim_i, space_order=2, dimensions=(dim,), shape=(shape[dim_i],)) alpha_i = self._grid.function('alpha_%d' % dim_i, space_order=2, dimensions=(dim,), shape=(shape[dim_i],)) sigma_di = self._grid.function('sigma_d%d' % dim_i, space_order=2, dimensions=(dim,), shape=(shape[dim_i],)) alpha_di = self._grid.function('alpha_d%d' % dim_i, space_order=2, dimensions=(dim,), shape=(shape[dim_i],)) # Fill functions sigma_i_data = self.damping(dimensions=(dim_i,), velocity=velocity, damping_type='power', power_degree=3, reflection_coefficient=reflection_coefficient, assign=True) alpha_i_data = self.damping(dimensions=(dim_i,), velocity=velocity, damping_type='power', power_degree=2, damping_coefficient=0.01*np.pi*f_centre, mask=True, assign=True) sigma_i.data_with_halo[:] = np.pad(sigma_i_data, ((2, 2),), mode='edge') alpha_i.data_with_halo[:] = np.pad(alpha_i_data, ((2, 2),), mode='edge') # Calculate their derivative eq_sigma_di = devito.Eq(sigma_di, devito.Derivative(sigma_i, (dim, 1))) eq_alpha_di = devito.Eq(alpha_di, devito.Derivative(alpha_i, (dim, 1))) # Create the auxiliary fields u_3 = self._grid.time_function('u_3_%d' % dim_i, time_order=1, space_order=2) u_2 = self._grid.time_function('u_2_%d' % dim_i, time_order=1, space_order=2) u_1 = self._grid.time_function('u_1_%d' % dim_i, time_order=1, space_order=2) # Prepare the various derivatives depending on whether we are going # forward or backward u_di = devito.Derivative(field, (dim, 1)) u_di2 = devito.Derivative(field, (dim, 2)) u_3_dt = u_3.dt if direction == 'forward' else u_3.dt.T u_2_dt = u_2.dt if direction == 'forward' else u_2.dt.T u_1_dt = u_1.dt if direction == 'forward' else u_1.dt.T u_3_next = u_3.forward if direction == 'forward' else u_3.backward u_2_next = u_2.forward if direction == 'forward' else u_2.backward u_1_next = u_1.forward if direction == 'forward' else u_1.backward u_di = u_di if direction == 'forward' else u_di.T # Calculate the auxiliary fields pde_3 = u_3_dt + (alpha_i + sigma_i) * u_3 - sigma_i ** 2 * (sigma_di + alpha_di) * u_di pde_2 = u_2_dt + (alpha_i + sigma_i) * u_2 - sigma_i * (2 * sigma_di * u_di + alpha_di * u_di + sigma_i * u_di2) + u_3_next # noqa: E501 pde_1 = u_1_dt + (alpha_i + sigma_i) * u_1 - (sigma_di * u_di + 2 * sigma_i * u_di2) + u_2_next # with the corresponding stencils pml_domain = (self._grid.pml_left[dim_i], self._grid.pml_right[dim_i]) pml_domain = [abox.intersection(dom) for dom in pml_domain] \ if devito.pro_available and isinstance(abox, devito.ABox) else pml_domain stencil_3 = [devito.Eq(u_3_next, devito.solve(pde_3, u_3_next, ), subdomain=dom, coefficients=subs) for dom in pml_domain] stencil_2 = [devito.Eq(u_2_next, devito.solve(pde_2, u_2_next, ), subdomain=dom, coefficients=subs) for dom in pml_domain] stencil_1 = [devito.Eq(u_1_next, devito.solve(pde_1, u_1_next, ), subdomain=dom, coefficients=subs) for dom in pml_domain] eq_preparation += [eq_sigma_di, eq_alpha_di] eq_before += stencil_3 + stencil_2 + stencil_1 boundary_term.append(u_1_next) return sum(boundary_term), eq_preparation + eq_before, eq_after
[docs] def clear(self): space = self._grid.space for dim_i in range(space.dim): self._grid.vars['u_3_%d' % dim_i].data_with_halo.fill(0.) self._grid.vars['u_2_%d' % dim_i].data_with_halo.fill(0.) self._grid.vars['u_1_%d' % dim_i].data_with_halo.fill(0.)
[docs] def deallocate(self): space = self._grid.space for dim_i in range(space.dim): self._grid.deallocate('u_3_%d' % dim_i) self._grid.deallocate('u_2_%d' % dim_i) self._grid.deallocate('u_1_%d' % dim_i)