예제 #1
0
def flip_vectors(mesh, eigs, mesh_ref, eigs_ref, test_it=False):
    x_c = 1e-3
    for i in range(len(eigs)):
        s = FESolution(mesh, eigs[i])
        s_ref = FESolution(mesh_ref, eigs_ref[i])
        if s.value(x_c) < 0:
            #print "  Multiplying %d-th coarse eigenvector by (-1)" % i
            eigs[i] = -eigs[i]
        if s_ref.value(x_c) < 0:
            #print "  Multiplying %d-th ref. eigenvector by (-1)" % i
            eigs_ref[i] = -eigs_ref[i]

        if test_it:
            # Test it:
            s = FESolution(mesh, eigs[i]).to_discrete_function()
            s_ref = FESolution(mesh_ref, eigs_ref[i]).to_discrete_function()
            same_norm = (s - s_ref).l2_norm()
            flipped_norm = (s + s_ref).l2_norm()
            print same_norm, flipped_norm
            if same_norm > flipped_norm:
                c = min(same_norm, flipped_norm) / max(same_norm, flipped_norm)
                print "Warning: the flip is wrong, c=", c
                # If "c" is almost one, then the vectors can't really be
                # aligned anyway:
                assert c > 0.9
예제 #2
0
 def calculate_FE_coeffs(self):
     if self._fe_sol is None:
         from hermes1d.h1d_wrapper.h1d_wrapper import \
                 (assemble_projection_matrix_rhs, Mesh, FESolution)
         from hermes_common._hermes_common import CooMatrix
         pts, orders = self._mesh.get_mesh_data()
         m = Mesh(pts, orders)
         n_dof = m.assign_dofs()
         A = CooMatrix(n_dof)
         rhs = empty(n_dof)
         assemble_projection_matrix_rhs(m, A, rhs, self,
                 projection_type="L2")
         coeffs = solve(A.to_scipy_coo().todense(), rhs)
         self._fe_sol = FESolution(m, coeffs)
예제 #3
0
파일: fekete.py 프로젝트: tmatsuza/hermes
    def project_onto(self, mesh, proj_type="Fekete"):
        """
        Projects 'self' onto the 'mesh' using the 'proj_type' projection.

        proj_type == "Fekete"/"L2"/"H1"
        """
        if mesh == self._mesh:
            return self
        if proj_type == "Fekete":
            return Function(self, mesh)
        elif proj_type in ["L2", "H1"]:
            from hermes1d.h1d_wrapper.h1d_wrapper import \
                    (assemble_projection_matrix_rhs, Mesh, FESolution)
            from hermes1d.hermes_common.matrix import CSCMatrix, AVector
            pts, orders = mesh.get_mesh_data()
            m = Mesh(pts, orders)
            n_dof = m.assign_dofs()
            A = CSCMatrix(n_dof)
            rhs = AVector(n_dof)
            assemble_projection_matrix_rhs(m,
                                           A,
                                           rhs,
                                           self,
                                           projection_type=proj_type)
            coeffs = solve(A.to_scipy_csc().todense(), rhs.to_numpy())
            return FESolution(m, coeffs).to_discrete_function()
        else:
            raise ValueError("Unknown projection type")
예제 #4
0
def refine_mesh_romanowski(mesh, solutions):
    """
    Uses Romanowski refinement for all solutions in 'solutions'.

    Solutions are given as vectors coming from the matrix solver.
    """
    els2refine = []
    errors = []
    for sol in solutions:
        s = FESolution(mesh, sol)
        id, error = find_element_romanowski(s.get_element_coeffs())
        els2refine.append(id)
        errors.append(error)
    els2refine = list(set(els2refine))
    print "Will refine the elements:", els2refine
    mesh = refine_mesh(mesh, els2refine)
    return mesh
예제 #5
0
def refine_mesh_romanowski(mesh, solutions):
    """
    Uses Romanowski refinement for all solutions in 'solutions'.

    Solutions are given as vectors coming from the matrix solver.
    """
    els2refine = []
    errors = []
    for sol in solutions:
        s = FESolution(mesh, sol)
        id, error = find_element_romanowski(s.get_element_coeffs())
        els2refine.append(id)
        errors.append(error)
    els2refine = list(set(els2refine))
    print "Will refine the elements:", els2refine
    mesh = refine_mesh(mesh, els2refine)
    return mesh
예제 #6
0
def flip_vectors(mesh, eigs, mesh_ref, eigs_ref, test_it=False):
    x_c = 1e-3
    for i in range(len(eigs)):
        s = FESolution(mesh, eigs[i])
        s_ref = FESolution(mesh_ref, eigs_ref[i])
        if s.value(x_c) < 0:
            #print "  Multiplying %d-th coarse eigenvector by (-1)" % i
            eigs[i] = -eigs[i]
        if s_ref.value(x_c) < 0:
            #print "  Multiplying %d-th ref. eigenvector by (-1)" % i
            eigs_ref[i] = -eigs_ref[i]

        if test_it:
            # Test it:
            s = FESolution(mesh, eigs[i]).to_discrete_function()
            s_ref = FESolution(mesh_ref, eigs_ref[i]).to_discrete_function()
            same_norm = (s-s_ref).l2_norm()
            flipped_norm = (s+s_ref).l2_norm()
            print same_norm, flipped_norm
            if same_norm > flipped_norm:
                c = min(same_norm, flipped_norm) / max(same_norm, flipped_norm)
                print "Warning: the flip is wrong, c=", c
                # If "c" is almost one, then the vectors can't really be
                # aligned anyway:
                assert c > 0.9
예제 #7
0
def test_l2_h1_proj3():
    """
    Tests conversion to FE basis.
    """
    pts = arange(0, 2 * pi, 0.1)
    orders = [2] * (len(pts) - 1)
    m = Mesh(pts, orders)

    f = Function(lambda x: sin(x), Mesh1D(pts, orders))

    n_dof = m.assign_dofs()
    A = CSCMatrix(n_dof)
    rhs = AVector(n_dof)
    assemble_projection_matrix_rhs(m, A, rhs, f, projection_type="L2")
    x = solve(A.to_scipy_csc().todense(), rhs.to_numpy())
    sol_l2 = FESolution(m, x).to_discrete_function()
    A = CSCMatrix(n_dof)
    assemble_projection_matrix_rhs(m, A, rhs, f, projection_type="H1")
    x = solve(A.to_scipy_csc().todense(), rhs.to_numpy())
    sol_h1 = FESolution(m, x).to_discrete_function()
    assert sol_l2 == f
    assert sol_h1 == f
예제 #8
0
 def calculate_FE_coeffs(self):
     if self._fe_sol is None:
         from hermes1d.h1d_wrapper.h1d_wrapper import \
                 (assemble_projection_matrix_rhs, Mesh, FESolution)
         from hermes1d.hermes_common.matrix import CSCMatrix, AVector
         pts, orders = self._mesh.get_mesh_data()
         m = Mesh(pts, orders)
         n_dof = m.assign_dofs()
         A = CSCMatrix(n_dof)
         rhs = AVector(n_dof)
         assemble_projection_matrix_rhs(m, A, rhs, self,
                 projection_type="L2")
         coeffs = solve(A.to_scipy_csc().todense(), rhs.to_numpy())
         self._fe_sol = FESolution(m, coeffs)
예제 #9
0
def test_l2_h1_proj2():
    """
    Tests the correctness of the projections.
    """
    pts = arange(0, 2 * pi, 3)
    orders = [4] * (len(pts) - 1)
    m = Mesh(pts, orders)

    pts = array(list(arange(0, pts[-1], 0.1)) + [pts[-1]])
    orders = [6] * (len(pts) - 1)
    f_exact = Function(lambda x: sin(x), Mesh1D(pts, orders))

    n_dof = m.assign_dofs()
    A = CSCMatrix(n_dof)
    rhs = AVector(n_dof)
    assemble_projection_matrix_rhs(m, A, rhs, f_sin, projection_type="L2")
    x = solve(A.to_scipy_csc().todense(), rhs.to_numpy())
    sol_l2 = FESolution(m, x).to_discrete_function()
    A = CSCMatrix(n_dof)
    assemble_projection_matrix_rhs(m, A, rhs, f_sin, projection_type="H1")
    x = solve(A.to_scipy_csc().todense(), rhs.to_numpy())
    sol_h1 = FESolution(m, x).to_discrete_function()
    assert (sol_l2 - f_exact).l2_norm() < 0.002
    assert (sol_h1 - f_exact).l2_norm() < 0.002
예제 #10
0
def test_l2_h1_proj_run():
    """
    Test that the projections run.

    It doesn't test if it's correct.
    """
    pts = arange(0, 2 * pi, 1)
    orders = [3] * (len(pts) - 1)
    m = Mesh(pts, orders)
    n_dof = m.assign_dofs()
    A = CSCMatrix(n_dof)
    rhs = AVector(n_dof)
    assemble_projection_matrix_rhs(m, A, rhs, f_sin, projection_type="L2")
    x = solve(A.to_scipy_csc().todense(), rhs.to_numpy())
    sol_l2 = FESolution(m, x).to_discrete_function()
    A = CSCMatrix(n_dof)
    assemble_projection_matrix_rhs(m, A, rhs, f_sin, projection_type="H1")
    x = solve(A.to_scipy_csc().todense(), rhs.to_numpy())
    sol_h1 = FESolution(m, x).to_discrete_function()
    sol_l2.plot(False)
    sol_h1.plot(False)
예제 #11
0
def test_l2_h1_proj_run():
    """
    Test that the projections run.

    It doesn't test if it's correct.
    """
    pts = arange(0, 2*pi, 1)
    orders = [3]*(len(pts)-1)
    m = Mesh(pts, orders)
    n_dof = m.assign_dofs()
    A = CSCMatrix(n_dof)
    rhs = AVector(n_dof)
    assemble_projection_matrix_rhs(m, A, rhs, f_sin, projection_type="L2")
    x = solve(A.to_scipy_csc().todense(), rhs.to_numpy())
    sol_l2 = FESolution(m, x).to_discrete_function()
    A = CSCMatrix(n_dof)
    assemble_projection_matrix_rhs(m, A, rhs, f_sin, projection_type="H1")
    x = solve(A.to_scipy_csc().todense(), rhs.to_numpy())
    sol_h1 = FESolution(m, x).to_discrete_function()
    sol_l2.plot(False)
    sol_h1.plot(False)
예제 #12
0
class Function(h1d_wrapper.Function):
    """
    Represents a function on a mesh.

    The values are given in the Fekete points.
    """

    def __init__(self, obj, mesh=None):
        if not isinstance(mesh, Mesh1D):
            raise Exception("You need to specify a mesh.")
        self._mesh = mesh
        if isinstance(obj, (tuple, list, ndarray)):
            self._values = obj
        else:
            self._values = []
            for a, b, order in mesh.iter_elems():
                fekete_points = _fekete.get_fekete_points_phys(order, a, b)
                # Note: this is not a projection (it only evaluates obj in
                # fekete points), so the result is not the best
                # approximation possible:
                elem_values = [obj(p) for p in fekete_points]
                self._values.append(array(elem_values))

        self._poly_coeffs = {}
        self._fe_sol = None

        self.logger = _logger_Function

    def get_polynomial(self, x, values, a, b):
        """
        Returns the interpolating polynomial's coeffs.

        The len(values) specifies the order and we work in the element <a, b>
        """
        # Note: the version in _fekete is 2.6x faster
        n = len(values)
        A = empty((n, n), dtype="double")
        y = empty((n,), dtype="double")
        assert len(x) == n
        for i in range(n):
            for j in range(n):
                A[i, j] = _fekete.get_x_phys(x[i], a, b)**(n-j-1)
            y[i] = values[i]
        a = solve(A, y)
        return a

    def restrict_to_interval(self, A, B):
        """
        Returns the same function, with the mesh (domain) restricted to the
        interval (A, B).
        """
        m = self._mesh.restrict_to_interval(A, B)
        return Function(self, m)


    def eval_polynomial(self, coeffs, x):
        # This is about 15x faster
        return _fekete.eval_polynomial(coeffs, x)
        # than this:
        r = 0
        n = len(coeffs)
        for i, a in enumerate(coeffs):
            r += a*x**(n-i-1)
        return r

    def eval_polynomial_array(self, coeffs, x):
        # This is about 6x faster
        return _fekete.eval_polynomial_array(coeffs, x)
        # than this:
        r = zeros(len(x))
        n = len(coeffs)
        for i, a in enumerate(coeffs):
            r += a*x**(n-i-1)
        return r

    def __call__(self, x):
        for n, (a, b, order) in enumerate(self._mesh.iter_elems()):
            if b < x:
                continue
            y = _fekete.eval_poly(array([float(x)]), self._values[n],
                    a, b)[0]
            return y

    def eval_f(self, x):
        return self(x)

    def eval_dfdx(self, x):
        self.calculate_FE_coeffs()
        return self._fe_sol.deriv(x)

    def calculate_FE_coeffs(self):
        if self._fe_sol is None:
            from hermes1d.h1d_wrapper.h1d_wrapper import \
                    (assemble_projection_matrix_rhs, Mesh, FESolution)
            from hermes1d.hermes_common.matrix import CSCMatrix, AVector
            pts, orders = self._mesh.get_mesh_data()
            m = Mesh(pts, orders)
            n_dof = m.assign_dofs()
            A = CSCMatrix(n_dof)
            rhs = AVector(n_dof)
            assemble_projection_matrix_rhs(m, A, rhs, self,
                    projection_type="L2")
            coeffs = solve(A.to_scipy_csc().todense(), rhs.to_numpy())
            self._fe_sol = FESolution(m, coeffs)

    def get_values_in_element(self, n, x):
        """
        Return the values in points 'x' in the element 'n'.

        'x' is a numpy array of points
        'n' is an element id

        It returns a numpy array of values of the function in points 'x'.
        All points 'x' must be in the element 'n'.
        """
        a, b, order = self._mesh.get_element_by_id(n)
        assert (a<=x).all()
        assert (x<=b).all()
        return _fekete.eval_poly(x, self._values[n], a, b)

    def get_polynomial_coeffs(self, n, values, a, b):
        if n not in self._poly_coeffs:
            vals = array(values)
            x = array(points[len(vals)-1])
            self._poly_coeffs[n] = _fekete.get_polynomial(x, vals, a, b)
        return self._poly_coeffs[n]

    def project_onto(self, mesh, proj_type="Fekete"):
        """
        Projects 'self' onto the 'mesh' using the 'proj_type' projection.

        proj_type == "Fekete"/"L2"/"H1"
        """
        if mesh == self._mesh:
            return self
        if proj_type == "Fekete":
            return Function(self, mesh)
        elif proj_type in ["L2", "H1"]:
            from hermes1d.h1d_wrapper.h1d_wrapper import \
                    (assemble_projection_matrix_rhs, Mesh, FESolution)
            from hermes1d.hermes_common.matrix import CSCMatrix, AVector
            pts, orders = mesh.get_mesh_data()
            m = Mesh(pts, orders)
            n_dof = m.assign_dofs()
            A = CSCMatrix(n_dof)
            rhs = AVector(n_dof)
            assemble_projection_matrix_rhs(m, A, rhs, self,
                    projection_type=proj_type)
            coeffs = solve(A.to_scipy_csc().todense(), rhs.to_numpy())
            return FESolution(m, coeffs).to_discrete_function()
        else:
            raise ValueError("Unknown projection type")

    def project_onto_union(self, mesh):
        """
        The same as project_onto, only "mesh" is a subset of self._mesh.
        """
        if mesh == self._mesh:
            return self
        values = []
        n = 0
        for a, b, order in mesh.iter_elems():
            if a >= self._mesh._points[n+1]:
                n += 1
            fekete_points = _fekete.get_fekete_points_phys(order, a, b)
            elem_values = []
            # Note: this is not a projection (it only evaluates obj in
            # fekete points), so the result is not the best
            # approximation possible:
            elem_values = self.get_values_in_element(n, fekete_points)
            values.append(elem_values)
        return Function(values, mesh)

    def plot(self, call_show=True):
        try:
            from jsplot import plot, show
        except ImportError:
            from pylab import plot, show
        odd = False
        for n, (a, b, order) in enumerate(self._mesh.iter_elems()):
            fekete_points = _fekete.get_fekete_points_phys(order, a, b)
            vals = self._values[n]
            assert len(vals) == len(fekete_points)
            x = arange(a, b, 0.1)
            y = [self(_x) for _x in x]
            if odd:
                format = "g-"
            else:
                format = "r-"
            odd = not odd
            plot(x, y, format)
            plot(fekete_points, vals, "ko")
        if call_show:
            show()

    def __eq__(self, o):
        if isinstance(o, Function):
            for a, b, order in self._mesh.iter_elems():
                fekete_points = _fekete.get_fekete_points_phys(order, a, b)
                for p in fekete_points:
                    if not feq(self(p), o(p)):
                        return False
            for a, b, order in o._mesh.iter_elems():
                fekete_points = _fekete.get_fekete_points_phys(order, a, b)
                for p in fekete_points:
                    if not feq(self(p), o(p)):
                        return False
            return True
        else:
            return False

    def __ne__(self, o):
        return not self.__eq__(o)

    def __add__(self, o):
        if self._mesh == o._mesh:
            values = [array(x)+array(y) for x, y in zip(self._values,
                o._values)]
            return Function(values, self._mesh)
        else:
            union_mesh = self._mesh.union(o._mesh)
            return self.project_onto_union(union_mesh) + o.project_onto_union(union_mesh)

    def __sub__(self, o):
        return self + (-o)

    def __neg__(self):
        values = [-x for x in self._values]
        return Function(values, self._mesh)

    def __pow__(self, o):
        if isinstance(o, (int, long)):
            pts = self._mesh._points
            orders = empty(len(self._mesh._orders), dtype="int")
            values = []
            for n, (a, b, order) in enumerate(self._mesh.iter_elems()):
                order = o*order
                x = _fekete.get_fekete_points_phys(order, a, b)
                vals = _fekete.eval_poly(x, self._values[n], a, b)**o
                values.append(vals)
                orders[n] = order
            mesh = Mesh1D(pts, orders)
            return Function(values, mesh)
        else:
            return NotImplemented

    def get_mesh_adapt(self, max_order=12):
        return self._mesh

    def l2_norm(self, method="Fekete"):
        """
        Calculates the L2 norm of the function.

        method == "Fekete" or "FE": Use Legendre interpolation, or first
            project to a FE basis and then calculate the L2 norm
        """
        if method=="Fekete":
            r = 0
            for n, (a, b, order) in enumerate(self._mesh.iter_elems()):
                x, w = _fekete.get_gauss_points_phys(a, b, order+1)
                vals = _fekete.eval_poly(x, self._values[n], a, b)
                r += _fekete.int_f2(w, vals)
            return sqrt(r)
        elif method=="FE":
            self.calculate_FE_coeffs()
            return self._fe_sol.l2_norm()

    def h1_norm(self):
        """
        Calculates the H1 norm of the function.
        """
        self.calculate_FE_coeffs()
        return self._fe_sol.h1_norm()

    def get_candidates_with_errors(self, f, elems=None):
        """
        Returns a sorted list of all candidates and their errors.

        The best candidate is first, the worst candidate is last.

        The "f" is the reference function which we want to approximate using
        "self".
        """
        cand_with_errors = []
        orig = f.project_onto(self._mesh)
        dof_orig = orig.dofs()
        err_orig = (f - orig).l2_norm()
        for a, b, order in self._mesh.iter_elems(elems):
            self.logger.info("Considering element: %s %s %s", a, b, order)
            cands = generate_candidates(a, b, order)
            #self.logger.debug("Candidates %s", cands)
            #print "-"*40
            #print a, b, order
            best_crit = 1e10
            for m in cands:
                #self.logger.debug("Candidate: %s", m)
                #self.logger.debug("  create_mesh...")
                cand_mesh = self._mesh.use_candidate(m)
                #self.logger.debug("  project...")
                cand = f.project_onto(cand_mesh)
                dof_cand = cand.dofs()
                #self.logger.debug("  l2_norm...")
                # This is slow, because we are calculating the l2_norm over the
                # whole mesh and we are doing the union mesh as well. All we
                # need to do is integrate over the element we are interested
                # and cache the rest of the elements.
                diff = f - cand
                err_cand = diff.l2_norm()
                #self.logger.debug("  Choose...")
                if dof_cand == dof_orig:
                    if err_cand < err_orig:
                        # if this happens, it means that we can get better
                        # approximation with the same DOFs, so we definitely take
                        # this candidate:
                        print "DOF_cand == DOF_orig:", dof_cand, dof_orig, err_cand, err_orig
                        crit = -1e10
                    else:
                        crit = 1e10 # forget this candidate
                elif dof_cand > dof_orig:
                    # if DOF rises, we take the candidate that goes the steepest in
                    # the log/sqrt error/DOFs convergence graph
                    # we want 'crit' as negative as possible:
                    crit = (log(err_cand) - log(err_orig)) / \
                            sqrt(dof_cand - dof_orig)
                    #print crit, err_cand, err_orig, dof_cand, dof_orig
                else:
                    if err_cand < err_orig:
                        # if this happens, it means that we can get better
                        # approximation with less DOFs, so we definitely take
                        # this candidate:
                        print "Nice!", dof_cand, dof_orig, err_cand, err_orig
                        crit = -1e10
                    else:
                        crit = 1e10 # forget this candidate
                if crit < best_crit:
                    best_m = m
                    best_crit = crit
            cand_with_errors.append((best_m, best_crit))
                #if crit < -1e9:
                #    cand_with_errors.sort(key=lambda x: x[1])
                #    return cand_with_errors

        cand_with_errors.sort(key=lambda x: x[1])
        return cand_with_errors

    def dofs(self):
        return self._mesh.dofs()
예제 #13
0
def adapt_mesh(mesh, eigs, l=0, Z=1, adapt_type="hp", eqn_type="R"):
    """
    Adapts the mesh using the adaptivity type 'adapt_type'.

    Returns a new instance of the H1D mesh.

    adapt_type .... one of: h, hp, p, uniform-p, romanowski
    """
    if adapt_type == "romanowski":
        m = refine_mesh_romanowski(mesh, eigs)
        pts, orders = m.get_mesh_data()
        return Mesh(pts, orders)
    elif adapt_type == "uniform-p":
        pts, orders = mesh.get_mesh_data()
        orders = array(orders) + 1
        return Mesh(pts, orders)
    elif adapt_type in ["h", "p", "hp"]:
        NORM = 1  # 1 ... H1; 0 ... L2;
        THRESHOLD = 0.7
        mesh_ref = mesh.reference_refinement()
        print "Fine mesh created (%d DOF)." % mesh_ref.get_n_dof()
        N_dof, energies, eigs_ref = solve_schroedinger(mesh_ref,
                                                       l=l,
                                                       Z=Z,
                                                       eqn_type=eqn_type,
                                                       eig_num=len(eigs))
        flip_vectors(mesh, eigs, mesh_ref, eigs_ref)
        print "    Done."
        sols = []
        sols_ref = []
        print "Normalizing solutions..."
        for i in range(len(eigs)):
            e = (eigs[i]).copy()
            coarse_h1_norm = FESolution(mesh, e).h1_norm()
            e /= coarse_h1_norm
            sols.append(e)
            e = (eigs_ref[i]).copy()
            reference_h1_norm = FESolution(mesh_ref, e).h1_norm()
            e /= reference_h1_norm
            sols_ref.append(e)
            #print "H1 norms:"
            #print "coarse    (%d):" % i, coarse_h1_norm
            #print "reference (%d):" % i, reference_h1_norm
        print "    Done."
        meshes = []
        mesh_orig = mesh.copy()
        mesh_orig.assign_dofs()
        errors = []
        for sol, sol_ref in zip(sols, sols_ref):
            mesh = mesh_orig.copy()
            mesh.assign_dofs()
            mesh_ref = mesh.reference_refinement()
            mesh_ref.assign_dofs()
            mesh.copy_vector_to_mesh(sol, 0)
            mesh_ref.copy_vector_to_mesh(sol_ref, 0)
            err_est_total, err_est_array = calc_error_estimate(
                NORM, mesh, mesh_ref)
            ref_sol_norm = calc_solution_norm(NORM, mesh_ref)
            err_est_rel = err_est_total / ref_sol_norm
            print "Relative error (est) = %g %%\n" % (100. * err_est_rel)
            errors.append(err_est_rel)
            # TODO: adapt using all the vectors:
            # 0 ... hp, 1 ... h, 2 ... p
            if adapt_type == "hp":
                ADAPT_TYPE = 0
            elif adapt_type == "h":
                ADAPT_TYPE = 1
            elif adapt_type == "p":
                ADAPT_TYPE = 2
            else:
                raise ValueError("Unkown adapt_type")
            adapt(NORM, ADAPT_TYPE, THRESHOLD, err_est_array, mesh, mesh_ref)
            meshes.append(mesh)
        pts, orders = mesh_orig.get_mesh_data()
        mesh = Mesh1D(pts, orders)
        for m in meshes:
            pts, orders = m.get_mesh_data()
            m = Mesh1D(pts, orders)
            mesh = mesh.union(m)
        pts, orders = mesh.get_mesh_data()
        mesh = Mesh(pts, orders)
        return mesh
    else:
        raise ValueError("Unknown adapt_type")
예제 #14
0
파일: fekete.py 프로젝트: tmatsuza/hermes
class Function(h1d_wrapper.Function):
    """
    Represents a function on a mesh.

    The values are given in the Fekete points.
    """
    def __init__(self, obj, mesh=None):
        if not isinstance(mesh, Mesh1D):
            raise Exception("You need to specify a mesh.")
        self._mesh = mesh
        if isinstance(obj, (tuple, list, ndarray)):
            self._values = obj
        else:
            self._values = []
            for a, b, order in mesh.iter_elems():
                fekete_points = _fekete.get_fekete_points_phys(order, a, b)
                # Note: this is not a projection (it only evaluates obj in
                # fekete points), so the result is not the best
                # approximation possible:
                elem_values = [obj(p) for p in fekete_points]
                self._values.append(array(elem_values))

        self._poly_coeffs = {}
        self._fe_sol = None

        self.logger = _logger_Function

    def get_polynomial(self, x, values, a, b):
        """
        Returns the interpolating polynomial's coeffs.

        The len(values) specifies the order and we work in the element <a, b>
        """
        # Note: the version in _fekete is 2.6x faster
        n = len(values)
        A = empty((n, n), dtype="double")
        y = empty((n, ), dtype="double")
        assert len(x) == n
        for i in range(n):
            for j in range(n):
                A[i, j] = _fekete.get_x_phys(x[i], a, b)**(n - j - 1)
            y[i] = values[i]
        a = solve(A, y)
        return a

    def restrict_to_interval(self, A, B):
        """
        Returns the same function, with the mesh (domain) restricted to the
        interval (A, B).
        """
        m = self._mesh.restrict_to_interval(A, B)
        return Function(self, m)

    def eval_polynomial(self, coeffs, x):
        # This is about 15x faster
        return _fekete.eval_polynomial(coeffs, x)
        # than this:
        r = 0
        n = len(coeffs)
        for i, a in enumerate(coeffs):
            r += a * x**(n - i - 1)
        return r

    def eval_polynomial_array(self, coeffs, x):
        # This is about 6x faster
        return _fekete.eval_polynomial_array(coeffs, x)
        # than this:
        r = zeros(len(x))
        n = len(coeffs)
        for i, a in enumerate(coeffs):
            r += a * x**(n - i - 1)
        return r

    def __call__(self, x):
        for n, (a, b, order) in enumerate(self._mesh.iter_elems()):
            if b < x:
                continue
            y = _fekete.eval_poly(array([float(x)]), self._values[n], a, b)[0]
            return y

    def eval_f(self, x):
        return self(x)

    def eval_dfdx(self, x):
        self.calculate_FE_coeffs()
        return self._fe_sol.deriv(x)

    def calculate_FE_coeffs(self):
        if self._fe_sol is None:
            from hermes1d.h1d_wrapper.h1d_wrapper import \
                    (assemble_projection_matrix_rhs, Mesh, FESolution)
            from hermes1d.hermes_common.matrix import CSCMatrix, AVector
            pts, orders = self._mesh.get_mesh_data()
            m = Mesh(pts, orders)
            n_dof = m.assign_dofs()
            A = CSCMatrix(n_dof)
            rhs = AVector(n_dof)
            assemble_projection_matrix_rhs(m,
                                           A,
                                           rhs,
                                           self,
                                           projection_type="L2")
            coeffs = solve(A.to_scipy_csc().todense(), rhs.to_numpy())
            self._fe_sol = FESolution(m, coeffs)

    def get_values_in_element(self, n, x):
        """
        Return the values in points 'x' in the element 'n'.

        'x' is a numpy array of points
        'n' is an element id

        It returns a numpy array of values of the function in points 'x'.
        All points 'x' must be in the element 'n'.
        """
        a, b, order = self._mesh.get_element_by_id(n)
        assert (a <= x).all()
        assert (x <= b).all()
        return _fekete.eval_poly(x, self._values[n], a, b)

    def get_polynomial_coeffs(self, n, values, a, b):
        if n not in self._poly_coeffs:
            vals = array(values)
            x = array(points[len(vals) - 1])
            self._poly_coeffs[n] = _fekete.get_polynomial(x, vals, a, b)
        return self._poly_coeffs[n]

    def project_onto(self, mesh, proj_type="Fekete"):
        """
        Projects 'self' onto the 'mesh' using the 'proj_type' projection.

        proj_type == "Fekete"/"L2"/"H1"
        """
        if mesh == self._mesh:
            return self
        if proj_type == "Fekete":
            return Function(self, mesh)
        elif proj_type in ["L2", "H1"]:
            from hermes1d.h1d_wrapper.h1d_wrapper import \
                    (assemble_projection_matrix_rhs, Mesh, FESolution)
            from hermes1d.hermes_common.matrix import CSCMatrix, AVector
            pts, orders = mesh.get_mesh_data()
            m = Mesh(pts, orders)
            n_dof = m.assign_dofs()
            A = CSCMatrix(n_dof)
            rhs = AVector(n_dof)
            assemble_projection_matrix_rhs(m,
                                           A,
                                           rhs,
                                           self,
                                           projection_type=proj_type)
            coeffs = solve(A.to_scipy_csc().todense(), rhs.to_numpy())
            return FESolution(m, coeffs).to_discrete_function()
        else:
            raise ValueError("Unknown projection type")

    def project_onto_union(self, mesh):
        """
        The same as project_onto, only "mesh" is a subset of self._mesh.
        """
        if mesh == self._mesh:
            return self
        values = []
        n = 0
        for a, b, order in mesh.iter_elems():
            if a >= self._mesh._points[n + 1]:
                n += 1
            fekete_points = _fekete.get_fekete_points_phys(order, a, b)
            elem_values = []
            # Note: this is not a projection (it only evaluates obj in
            # fekete points), so the result is not the best
            # approximation possible:
            elem_values = self.get_values_in_element(n, fekete_points)
            values.append(elem_values)
        return Function(values, mesh)

    def plot(self, call_show=True):
        try:
            from jsplot import plot, show
        except ImportError:
            from pylab import plot, show
        odd = False
        for n, (a, b, order) in enumerate(self._mesh.iter_elems()):
            fekete_points = _fekete.get_fekete_points_phys(order, a, b)
            vals = self._values[n]
            assert len(vals) == len(fekete_points)
            x = arange(a, b, 0.1)
            y = [self(_x) for _x in x]
            if odd:
                format = "g-"
            else:
                format = "r-"
            odd = not odd
            plot(x, y, format)
            plot(fekete_points, vals, "ko")
        if call_show:
            show()

    def __eq__(self, o):
        if isinstance(o, Function):
            for a, b, order in self._mesh.iter_elems():
                fekete_points = _fekete.get_fekete_points_phys(order, a, b)
                for p in fekete_points:
                    if not feq(self(p), o(p)):
                        return False
            for a, b, order in o._mesh.iter_elems():
                fekete_points = _fekete.get_fekete_points_phys(order, a, b)
                for p in fekete_points:
                    if not feq(self(p), o(p)):
                        return False
            return True
        else:
            return False

    def __ne__(self, o):
        return not self.__eq__(o)

    def __add__(self, o):
        if self._mesh == o._mesh:
            values = [
                array(x) + array(y) for x, y in zip(self._values, o._values)
            ]
            return Function(values, self._mesh)
        else:
            union_mesh = self._mesh.union(o._mesh)
            return self.project_onto_union(union_mesh) + o.project_onto_union(
                union_mesh)

    def __sub__(self, o):
        return self + (-o)

    def __neg__(self):
        values = [-x for x in self._values]
        return Function(values, self._mesh)

    def __pow__(self, o):
        if isinstance(o, (int, long)):
            pts = self._mesh._points
            orders = empty(len(self._mesh._orders), dtype="int")
            values = []
            for n, (a, b, order) in enumerate(self._mesh.iter_elems()):
                order = o * order
                x = _fekete.get_fekete_points_phys(order, a, b)
                vals = _fekete.eval_poly(x, self._values[n], a, b)**o
                values.append(vals)
                orders[n] = order
            mesh = Mesh1D(pts, orders)
            return Function(values, mesh)
        else:
            return NotImplemented

    def get_mesh_adapt(self, max_order=12):
        return self._mesh

    def l2_norm(self, method="Fekete"):
        """
        Calculates the L2 norm of the function.

        method == "Fekete" or "FE": Use Legendre interpolation, or first
            project to a FE basis and then calculate the L2 norm
        """
        if method == "Fekete":
            r = 0
            for n, (a, b, order) in enumerate(self._mesh.iter_elems()):
                x, w = _fekete.get_gauss_points_phys(a, b, order + 1)
                vals = _fekete.eval_poly(x, self._values[n], a, b)
                r += _fekete.int_f2(w, vals)
            return sqrt(r)
        elif method == "FE":
            self.calculate_FE_coeffs()
            return self._fe_sol.l2_norm()

    def h1_norm(self):
        """
        Calculates the H1 norm of the function.
        """
        self.calculate_FE_coeffs()
        return self._fe_sol.h1_norm()

    def get_candidates_with_errors(self, f, elems=None):
        """
        Returns a sorted list of all candidates and their errors.

        The best candidate is first, the worst candidate is last.

        The "f" is the reference function which we want to approximate using
        "self".
        """
        cand_with_errors = []
        orig = f.project_onto(self._mesh)
        dof_orig = orig.dofs()
        err_orig = (f - orig).l2_norm()
        for a, b, order in self._mesh.iter_elems(elems):
            self.logger.info("Considering element: %s %s %s", a, b, order)
            cands = generate_candidates(a, b, order)
            #self.logger.debug("Candidates %s", cands)
            #print "-"*40
            #print a, b, order
            best_crit = 1e10
            for m in cands:
                #self.logger.debug("Candidate: %s", m)
                #self.logger.debug("  create_mesh...")
                cand_mesh = self._mesh.use_candidate(m)
                #self.logger.debug("  project...")
                cand = f.project_onto(cand_mesh)
                dof_cand = cand.dofs()
                #self.logger.debug("  l2_norm...")
                # This is slow, because we are calculating the l2_norm over the
                # whole mesh and we are doing the union mesh as well. All we
                # need to do is integrate over the element we are interested
                # and cache the rest of the elements.
                diff = f - cand
                err_cand = diff.l2_norm()
                #self.logger.debug("  Choose...")
                if dof_cand == dof_orig:
                    if err_cand < err_orig:
                        # if this happens, it means that we can get better
                        # approximation with the same DOFs, so we definitely take
                        # this candidate:
                        print "DOF_cand == DOF_orig:", dof_cand, dof_orig, err_cand, err_orig
                        crit = -1e10
                    else:
                        crit = 1e10  # forget this candidate
                elif dof_cand > dof_orig:
                    # if DOF rises, we take the candidate that goes the steepest in
                    # the log/sqrt error/DOFs convergence graph
                    # we want 'crit' as negative as possible:
                    crit = (log(err_cand) - log(err_orig)) / \
                            sqrt(dof_cand - dof_orig)
                    #print crit, err_cand, err_orig, dof_cand, dof_orig
                else:
                    if err_cand < err_orig:
                        # if this happens, it means that we can get better
                        # approximation with less DOFs, so we definitely take
                        # this candidate:
                        print "Nice!", dof_cand, dof_orig, err_cand, err_orig
                        crit = -1e10
                    else:
                        crit = 1e10  # forget this candidate
                if crit < best_crit:
                    best_m = m
                    best_crit = crit
            cand_with_errors.append((best_m, best_crit))
            #if crit < -1e9:
            #    cand_with_errors.sort(key=lambda x: x[1])
            #    return cand_with_errors

        cand_with_errors.sort(key=lambda x: x[1])
        return cand_with_errors

    def dofs(self):
        return self._mesh.dofs()