예제 #1
0
    def _coeff_initialise(self,mesh,coeff_pre):
        """Initialises self.coeff equal to coeff_pre, but sets up
        Firedrake Constant structure to allow for sampling.

        Parameters:

        mesh - a Firedrake mesh.

        coeff_pre - see init.
        """

        if self._coeff_dims == [2,2]\
                and coeff_pre != fd.as_matrix([[1.0,0.0],[0.0,1.0]]):

            warnings.warn("coeff_pre is not the identity. There is no\
            guarantee that the randomly-generated matrices are\
            positive-definite, or have the correct amount of noise.")

        d = mesh.geometric_dimension()
            
        # Bit of a hack, set up num_pieces
        num_pieces_list = []
        [num_pieces_list.append(self._num_pieces) for ii in range(d)]
            
        # Set up all the Firedrake Constants:
        self._constant_array = np.empty(num_pieces_list,dtype=object)

        with np.nditer(self._constant_array,flags=['refs_ok'],op_flags=['writeonly']) as array_it:
            
            for const in array_it:

                if self._coeff_dims == [2,2]:
                    const[...] = fd.Constant(np.array([[0.0,0.0],[0.0,0.0]]),domain=mesh)
                elif self._coeff_dims == [1]:
                    const[...] = fd.Constant(0.0,domain=mesh)
                
        # Form coeff by looping over all the subdomains
        x = fd.SpatialCoordinate(mesh)

        self.coeff = coeff_pre

        array_it = np.nditer(self._constant_array,flags=['refs_ok','multi_index'])

        while not array_it.finished:
        
            const =  array_it[0]
            
            loc_array = np.array((array_it.multi_index,1+np.array(array_it.multi_index))
                                 ,dtype='float').T/float(self._num_pieces)
            
            self.coeff += utils.nd_indicator(x,const,loc_array)

            array_it.iternext()
예제 #2
0
    def sharp_cutoff(self, centre, width, apply_to_preconditioner=False):
        """Applies a sharp cutoff function to A&n.

        Applying this function means A=I and n=1 on the boundary

        The cutoff function is 1 on a square/cube, and zero outside
        the square/cube.

        Inputs:

        centre - numpy array containing the coordinates of the centre
        of the cutoff zone.

        width - the width of the zone on which the original values of
        A & n hold.

        apply_to_preconditioner - boolean - if true, does this only to
        the preconditioner, rather than the problem itself. Used mainly
        when setting an already-existing problem as the preconditioner.
        """
        x = fd.SpatialCoordinate(self.V.mesh())

        dim = self.V.mesh().geometric_dimension()

        indicator_region = np.array(centre)\
                           + np.repeat(0.5*np.array([-width,width],ndmin=2),
                                       dim,axis=0)

        ind = nd_indicator(x, 1.0, indicator_region)

        identity = fd.as_matrix([[1.0, 0.0], [0.0, 1.0]])

        if apply_to_preconditioner:

            self.set_n_pre(1.0 + ind * (self._n_pre - 1.0))

            self.set_A_pre(identity + ind * (self._A_pre - identity))

        else:

            self.set_n(1.0 + ind * (self._n - 1.0))

            self.set_A(identity + ind * (self._A - identity))
k = 30.0

# Define a mesh that keeps pollution error bounded
num_cells = h_to_num_cells(k**-1.5, 2)

L = 1.0

mesh = SquareMesh(num_cells, num_cells, L)

# Use piecewise-linear finite elements
V = FunctionSpace(mesh, "CG", 1)

# n = 1 inside a square of size 1/3 x 1/3, and n=0.5 outside
x = SpatialCoordinate(mesh)
square_limits = np.array([[1.0 / 3.0, 2.0 / 3.0], [1.0 / 3.0, 2.0 / 3.0]])
n = 0.5 + nd_indicator(x, 0.5, square_limits)

# Define the problem
prob = hh.HelmholtzProblem(k, V, n=n)

# Use f and g corresponding to a plane wave (in homogeneous media)
prob.f_g_plane_wave()

# Use MUMPS as a direct solver
prob.use_mumps()

# Solve the problem
prob.solve()

# Plot the solution
prob.plot()
예제 #4
0
def nearby_preconditioning_piecewise_experiment_set(
        A_pre_type,n_pre_type,dim,num_pieces,seed,num_repeats,
        k_list,h_list,p_list,noise_master_level_list,noise_modifier_list,
        save_location):
    """Test nearby preconditioning for a range of parameter values.

    Performs nearby preconditioning tests for a range of values of k,
    the mesh size h, and the size of the random noise (which can be
    specified in terms of k and h). The random noise is piecewise
    constant on a grid unrelated to the finite-element mesh.

    Parameters:

    A_pre_type - string - options are 'constant', giving A_pre =
    [[1.0,0.0],[0.0,1.0]].

    n_pre_type - string - options are 'constant', giving n_pre = 1.0;
    'jump_down' giving n_pre = 2/3 on a central square of side length
    1/3, and 1 otherwise; and 'jump_up' giving n_pre = 1.5 on a central
    square of side length 1/3, and 1 otherwise.

    dim - 2 or 3, the dimension of the problem.

    num_pieces - see
        helmholtz.coefficients.PieceWiseConstantCoeffGenerator.

    seed - see StochasticHelmholtzProblem.

    num_repeats - see nearby_preconditioning_test.

    k_list - list of positive floats - the values of k for which we will
    run experiments.

    h_list - list of 2-tuples; in each tuple (call it t) t[0] should be
    a positive float and t[1] should be a float. These specify the
    values of the mesh size h for which we will run experiments. h =
    t[0] * k**t[1].

    p_list - list of positive ints, the polynomial degrees to run
    experiments for. Degree >= 5 will be very slow because of the
    implementation in Firedrake.

    noise_master_level_list - list of 2-tuples, where each entry of the
    tuple is a positive float.  This defines the values of base_noise_A
    and base_noise_n to be used in the experiments. Call a given tuple
    t. Then base_noise_A = t[0] and base_noise_n = t[1].

    noise_modifier_list - list of 4-tuples; the entries of each tuple
    should be floats. Call a given tuple t. This modifies the base noise
    so that the L^\infty norms of A and n are less than or equal to
    (respectively) base_noise_A * h**t[0] * k**t[1] and base_noise_n *
    h**t[2] * k**t[3].

    save_location - see utils.write_repeats_to_csv.

    """

    if not(isinstance(A_pre_type,str)):
        raise TypeError("Input A_pre_type should be a string")
    elif A_pre_type is not "constant":
        raise HelmholtzNotImplementedError(
            "Currently only implemented A_pre_type = 'constant'.")

    if not(isinstance(n_pre_type,str)):
        raise TypeError("Input n_pre_type should be a string")

    if not(isinstance(k_list,list)):
        raise TypeError("Input k_list should be a list.")
    elif any(not(isinstance(k,float)) for k in k_list):
        raise TypeError("Input k_list should be a list of floats.")
    elif any(k <= 0 for k in k_list):
        raise TypeError(
            "Input k_list should be a list of positive floats.")

    if not(isinstance(h_list,list)):
        raise TypeError("Input h_list should be a list.")
    elif any(not(isinstance(h_tuple,tuple)) for h_tuple in h_list):
        raise TypeError("Input h_list should be a list of tuples.")
    elif any(len(h_tuple) is not 2 for h_tuple in h_list):
        raise TypeError("Input h_list should be a list of 2-tuples.")
    elif any(not(isinstance(h_tuple[0],float)) for h_tuple in h_list)\
             or any(h_tuple[0] <= 0 for h_tuple in h_list):
        raise TypeError(
            "The first item of every tuple in h_list\
            should be a positive float.")
    elif any(not(isinstance(h_tuple[1],float)) for h_tuple in h_list):
        raise TypeError(
            "The second item of every tuple in h_list should be a float.")

    if not(isinstance(noise_master_level_list,list)):
        raise TypeError(
            "Input noise_master_level_list should be a list.")
    elif any(not(isinstance(noise_tuple,tuple))
             for noise_tuple in noise_master_level_list):
        raise TypeError(
            "Input noise_master_level_list should be a list of tuples.")
    elif any(len(noise_tuple) is not 2
             for noise_tuple in noise_master_level_list):
        raise TypeError(
            "Input noise_master_level_list should be a list of 2-tuples.")
    elif any(any(not(isinstance(noise_tuple[i],float))
                 for i in range(len(noise_tuple)))
             for noise_tuple in noise_master_level_list):
        raise TypeError(
            "Input noise_master_level_list\
            should be a list of 2-tuples of floats.")

    if not(isinstance(noise_modifier_list,list)):
        raise TypeError("Input noise_modifier_list should be a list.")
    elif any(not(isinstance(mod_tuple,tuple))
             for mod_tuple in noise_modifier_list):
        raise TypeError(
            "Input noise_modifier_list should be a list of tuples.")
    elif any(len(mod_tuple) is not 4 for mod_tuple in noise_modifier_list):
        raise TypeError(
            "Input noise_modifier_list should be a list of 4-tuples.")
    elif any(any(not(isinstance(mod_tuple[i],float))
                 for i in range(len(mod_tuple)))
             for mod_tuple in noise_modifier_list):
        raise TypeError(
            "Input noise_modifier_list\
            should be a list of 4-tuples of floats.")


    
    for k in k_list:
        for h_tuple in h_list:
            for p in p_list:
                h = h_tuple[0] * k**h_tuple[1]
                mesh_points = hh_utils.h_to_num_cells(h,dim)
                mesh = fd.UnitSquareMesh(mesh_points,mesh_points)
                V = fd.FunctionSpace(mesh, "CG", p)
                f = 0.0
                d = fd.as_vector([1.0/fd.sqrt(2.0),1.0/fd.sqrt(2.0)])
                x = fd.SpatialCoordinate(mesh)
                nu = fd.FacetNormal(mesh)
                g=1j*k*fd.exp(1j*k*fd.dot(x,d))*(fd.dot(d,nu)-1)

                if A_pre_type is "constant":
                    A_pre = fd.as_matrix([[1.0,0.0],[0.0,1.0]])

                if n_pre_type is "constant":
                    n_pre = 1.0

                elif n_pre_type is "jump_down":
                    n_pre = (2.0/3.0)\
                            + hh_utils.nd_indicator(
                                x,1.0/3.0,
                                np.array([[1.0/3.0,2.0/3.0],
                                          [1.0/3.0,2.0/3.0],
                                          [1.0/3.0,2.0/3.0]]
                                )
                            )

                elif n_pre_type is "jump_up":
                    n_pre = 1.5\
                            + hh_utils.nd_indicator(
                                x,-1.0/2.0,
                                np.array([[1.0/3.0,2.0/3.0],
                                          [1.0/3.0,2.0/3.0],
                                          [1.0/3.0,2.0/3.0]]
                                )
                            )


                for noise_master in noise_master_level_list:
                    A_noise_master = noise_master[0]
                    n_noise_master = noise_master[1]

                    for modifier in noise_modifier_list:
                        if fd.COMM_WORLD.rank == 0:
                            print(k,h_tuple,noise_master,modifier)

                        A_modifier = h ** modifier[0] * k**modifier[1]
                        n_modifier = h ** modifier[2] * k**modifier[3]
                        A_noise_level = A_noise_master * A_modifier
                        n_noise_level = n_noise_master * n_modifier

                        A_stoch = coeff.PiecewiseConstantCoeffGenerator(
                            mesh,num_pieces,A_noise_level,A_pre,[2,2])
                        n_stoch = coeff.PiecewiseConstantCoeffGenerator(
                            mesh,num_pieces,n_noise_level,n_pre,[1])
                        np.random.seed(seed)

                        GMRES_its = nearby_preconditioning_experiment(
                            V,k,A_pre,A_stoch,n_pre,n_stoch,f,g,num_repeats)

                        if fd.COMM_WORLD.rank == 0:
                            hh_utils.write_GMRES_its(
                                GMRES_its,save_location,
                                {'k' : k,
                                 'h_tuple' : h_tuple,
                                 'p' : p,
                                 'num_pieces' : num_pieces,
                                 'A_pre_type' : A_pre_type,
                                 'n_pre_type' : n_pre_type,
                                 'noise_master' : noise_master,
                                 'modifier' : modifier,
                                 'num_repeats' : num_repeats
                                 }
                                )
예제 #5
0
        print(k, flush=True)

        eps = eps_const / k**eps_power

        shift = np.array([[eps, 0.0], [0.0, 0.0]])

        num_cells = h_to_num_cells(k**(-1.5), 2)

        mesh = fd.UnitSquareMesh(num_cells, num_cells)

        V = fd.FunctionSpace(mesh, "CG", 1)

        x = fd.SpatialCoordinate(mesh)

        n = 0.5 + nd_indicator(x, 1.0, discon + eps)

        n_pre = 0.5 + nd_indicator(x, 1.0, discon)

        A = fd.as_matrix([[1.0, 0.0], [0.0, 1.0]])

        prob = HelmholtzProblem(k, V, A=A, n=n, A_pre=A, n_pre=n_pre)

        prob.f_g_plane_wave([np.cos(angle), np.sin(angle)])

        prob.solve()

        storage = np.append(storage,
                            np.array((k, prob.GMRES_its), ndmin=2),
                            axis=0)
예제 #6
0
    varying_coeff = fd.as_matrix([[1.0, 0.0], [0.0, 1.0]])
else:
    constant_to_multiply = 1.0
    varying_coeff = 1.0

for ii in range(num_pieces):
    for jj in range(num_pieces):
        if np.mod(ii + jj, 2) == 1:
            value = +alpha * k_multipler
        else:
            value = -alpha * k_multipler
        fl_ii = float(ii)
        fl_jj = float(jj)
        print(ii, jj, value)
        varying_coeff += hh_utils.nd_indicator(
            x, value * constant_to_multiply,
            np.array([[fl_ii, fl_ii + 1.0], [fl_jj, fl_jj + 1.0]]) /
            float(num_pieces))

if A_vs_n:
    A = varying_coeff
    n = 1.0
else:
    A = fd.as_matrix([[1.0, 0.0], [0.0, 1.0]])
    n = varying_coeff

A_pre = fd.as_matrix([[1.0, 0.0], [0.0, 1.0]])

n_pre = 1.0

prob = hh.HelmholtzProblem(k=k, V=V, A=A, n=n, A_pre=A_pre, n_pre=n_pre)