Beispiel #1
0
    def interp_to_qp(self, dofs):
        """
        Interpolate DOFs into quadrature points.

        The quadrature order is given by the field approximation order.

        Parameters
        ----------
        dofs : array
            The array of DOF values of shape `(n_nod, n_component)`.

        Returns
        -------
        data_qp : array
            The values interpolated into the quadrature points.
        integral : Integral
            The corresponding integral defining the quadrature points.
        """
        integral = Integral('i', order=self.approx_order)

        data_qp = []
        for ig, ap in self.aps.iteritems():
            bf = ap.get_base('v', False, integral)
            bf = bf[:,0,:].copy()

            vals = nm.dot(bf, dofs[ap.econn])
            vals = nm.swapaxes(vals, 0, 1)
            vals.shape = vals.shape + (1,)

            data_qp.append(vals)

        data_qp = nm.concatenate(data_qp, axis=0)

        return data_qp, integral
Beispiel #2
0
    def interp_to_qp(self, dofs):
        """
        Interpolate DOFs into quadrature points.

        The quadrature order is given by the field approximation order.

        Parameters
        ----------
        dofs : array
            The array of DOF values of shape `(n_nod, n_component)`.

        Returns
        -------
        data_qp : array
            The values interpolated into the quadrature points.
        integral : Integral
            The corresponding integral defining the quadrature points.
        """
        integral = Integral('i', order=self.approx_order)

        bf = self.get_base('v', False, integral)
        bf = bf[:, 0, :].copy()

        data_qp = nm.dot(bf, dofs[self.econn])
        data_qp = nm.swapaxes(data_qp, 0, 1)
        data_qp.shape = data_qp.shape + (1, )

        return data_qp, integral
Beispiel #3
0
    def get_surface_basis(self, region):
        from sfepy.discrete.integrals import Integral
        import sfepy.discrete.iga as iga
        from sfepy.discrete.iga.extmods.igac import eval_mapping_data_in_qp

        nurbs = self.nurbs
        facets = self._get_facets(region.kind_tdim)

        # Cell and face(cell) ids for each facet.
        fis = region.get_facet_indices()

        # Integral given by max. NURBS surface degree.
        fdegrees = iga.get_surface_degrees(nurbs.degrees)
        order = fdegrees.max()
        integral = Integral('i', order=2 * order)
        vals, weights = integral.get_qp(self.domain.gel.surface_facet_name)

        # Boundary QP - use tensor product structure.
        bvals = iga.create_boundary_qp(vals, region.tdim)

        # Compute facet basis, jacobians and physical BQP.
        all_qp = []
        all_fbfs = []
        all_dets = []
        for ii, (ie, ifa) in enumerate(fis):
            qp_coors = bvals[ifa]

            bfs, _, dets = eval_mapping_data_in_qp(qp_coors, nurbs.cps,
                                                   nurbs.weights,
                                                   nurbs.degrees, nurbs.cs,
                                                   nurbs.conn, nm.array([ie]))
            # Facet basis.
            fbfs = bfs[..., facets[ifa]][0, :, 0, :]

            # Weight Jacobians by quadrature point weights.
            dets = nm.abs(dets) * weights[None, :, None, None]
            dets = dets[0, :, 0, :]

            # Physical BQP.
            fcps = nurbs.cps[nurbs.conn[ie, facets[ifa]]]
            qp = nm.dot(fbfs, fcps)

            all_qp.append(qp)
            all_fbfs.append(fbfs)
            all_dets.append(dets)

        return all_qp, all_fbfs, all_dets
Beispiel #4
0
def compute_nodal_normals(nodes, region, field, return_imap=False):
    """
    Nodal normals are computed by simple averaging of element normals of
    elements every node is contained in.
    """
    dim = region.dim

    field.domain.create_surface_group(region)
    field._setup_surface_data(region)

    # Custom integral with quadrature points very close to facet vertices.
    coors = field.gel.surface_facet.coors
    centre = coors.sum(axis=0) / coors.shape[0]
    qp_coors = coors + 1e-8 * (centre - coors)
    # Unit normals -> weights = ones.
    qp_weights = nm.ones(qp_coors.shape[0], dtype=nm.float64)

    integral = Integral('aux', coors=qp_coors, weights=qp_weights)

    normals = nm.zeros((nodes.shape[0], dim), dtype=nm.float64)
    mask = nm.zeros((nodes.max() + 1, ), dtype=nm.int32)
    imap = nm.empty_like(mask)
    imap.fill(nodes.shape[0])  # out-of-range index for normals.
    imap[nodes] = nm.arange(nodes.shape[0], dtype=nm.int32)

    for ig in region.igs:
        cmap, _ = field.get_mapping(ig, region, integral, 'surface')
        e_normals = cmap.normal[..., 0]

        sd = field.domain.surface_groups[ig][region.name]
        econn = sd.get_connectivity()
        mask[econn] += 1

        # normals[imap[econn]] += e_normals
        im = imap[econn]
        for ii, en in enumerate(e_normals):
            normals[im[ii]] += en

    # All nodes must have a normal.
    if not nm.all(mask[nodes] > 0):
        raise ValueError('region %s has not complete faces!' % region.name)

    norm = la.norm_l2_along_axis(normals)[:, nm.newaxis]
    if (norm < 1e-15).any():
        raise ValueError('zero nodal normal! (a node in volume?)')
    normals /= norm

    if return_imap:
        return normals, imap

    else:
        return normals
    def test_quadratures(self):
        """
        Test if the quadratures have orders they claim to have, using
        symbolic integration by sympy.
        """
        from sfepy.discrete.quadratures import quadrature_tables, tp_geometries
        from sfepy.discrete.integrals import Integral

        if sm is None:
            self.report('cannot import sympy, skipping')
            return True

        quad = Integral('test_integral')

        ok = True
        failed = []
        for geometry, qps in ordered_iteritems(quadrature_tables):
            self.report('geometry:', geometry)

            if geometry == '0_1':
                continue

            elif geometry in tp_geometries:
                iter_qp = range(1, 11)

            elif geometry == '2_3':
                iter_qp = range(1, 25)

            elif geometry == '3_4':
                iter_qp = range(1, 12)

            else:
                iter_qp = sorted(qps.keys())

            for order in iter_qp:
                self.report('order:', order)

                aux = self._test_quadratures(quad, geometry, order)
                _ok, integral, val = aux

                if not _ok:
                    failed.append((geometry, order, float(integral), val))

                ok = ok and _ok

        if not ok:
            self.report('failed:')
            for aux in failed:
                self.report(aux, '%.1e' % abs(aux[2] - aux[3]))

        return ok
Beispiel #6
0
    def get_surface_basis(self, region):
        """
        Get basis for projections to region's facets.

        Notes
        -----
        Cannot be uses for all fields because IGA does not support surface
        mappings.
        """
        order = self.approx_order

        integral = Integral('i', order=2 * order)
        geo, mapping = self.get_mapping(region, integral, 'surface')
        pqps = get_physical_qps(region, integral)
        qps = pqps.values.reshape(pqps.shape)

        bfs = nm.broadcast_to(
            geo.bf[..., 0, :],
            (qps.shape[0], qps.shape[1], geo.bf.shape[3]),
        )

        return qps, bfs, geo.det[..., 0]
Beispiel #7
0
    def set_dofs(self, fun=0.0, region=None, dpn=None, warn=None):
        """
        Set the values of DOFs given by the `region` using a function of space
        coordinates or value `fun`.

        If `fun` is a function, the l2 projection that is global for all region
        facets is used to set the DOFs.

        If `dpn > 1`, and `fun` is a function, it has to return the values
        DOF-by-DOF, i.e. a single one-dimensional vector with all values of the
        first component, then of the second one etc. concatenated
        together.

        Parameters
        ----------
        fun : float or array of length dpn or callable
            The DOF values.
        region : Region
            The region containing the DOFs.
        dpn : int, optional
            The DOF-per-node count. If not given, the number of field
            components is used.
        warn : str, optional
            The warning message printed when the region selects no DOFs.

        Returns
        -------
        nods : array, shape (n_dof,)
            The field DOFs (or node indices) given by the region.
        vals : array, shape (dpn, n_dof)
            The values of the DOFs, DOF-by-DOF when raveled in C (row-major)
            order.
        """
        if region is None:
            region = self.region

        if dpn is None:
            dpn = self.n_components

        nods = []
        vals = []

        aux = self.get_dofs_in_region(region)
        nods = nm.unique(nm.hstack(aux))

        if nm.isscalar(fun):
            vals = nm.repeat([fun], nods.shape[0] * dpn)

        elif isinstance(fun, nm.ndarray):
            assert_(len(fun) == dpn)
            vals = nm.repeat(fun, nods.shape[0])

        elif callable(fun):
            import scipy.sparse as sps
            from sfepy.solvers.ls import solve
            from sfepy.discrete.integrals import Integral
            from sfepy.discrete.fem.utils import prepare_remap
            import sfepy.discrete.iga as iga
            from sfepy.discrete.iga.extmods.igac import eval_mapping_data_in_qp

            nurbs = self.nurbs
            facets = self._get_facets(region.kind_tdim)

            # Region facet connectivity.
            rconn = self.get_econn('surface', region)

            # Local connectivity.
            remap = prepare_remap(nods, nods.max() + 1)
            lconn = [remap[ii] for ii in rconn]

            # Cell and face(cell) ids for each facet.
            fis = region.get_facet_indices()

            # Integral given by max. NURBS surface degree.
            fdegrees = iga.get_surface_degrees(nurbs.degrees)
            order = fdegrees.max()
            integral = Integral('i', order=2 * order)
            vals, weights = integral.get_qp(self.domain.gel.surface_facet_name)

            # Boundary QP - use tensor product structure.
            bvals = iga.create_boundary_qp(vals, region.tdim)

            # Compute facet basis, jacobians and physical BQP.
            n_dof = len(nods)
            rhs = nm.zeros((dpn, n_dof), dtype=nm.float64)
            rows, cols, mvals = [], [], []
            all_qp = []
            all_fbfs = []
            all_dets = []
            for ii, (ie, ifa) in enumerate(fis):
                qp_coors = bvals[ifa]

                bfs, _, dets = eval_mapping_data_in_qp(qp_coors, nurbs.cps,
                                                       nurbs.weights,
                                                       nurbs.degrees, nurbs.cs,
                                                       nurbs.conn,
                                                       nm.array([ie]))
                # Facet basis.
                fbfs = bfs[..., facets[ifa]][0, :, 0, :]

                # Weight Jacobians by quadrature point weights.
                dets = nm.abs(dets) * weights[None, :, None, None]
                dets = dets[0, :, 0, :]

                # Physical BQP.
                fcps = nurbs.cps[nurbs.conn[ie, facets[ifa]]]
                qp = nm.dot(fbfs, fcps)

                all_qp.append(qp)
                all_fbfs.append(fbfs)
                all_dets.append(dets)

            # DOF values in the physical BQP.
            qps = nm.concatenate(all_qp)
            vals = nm.asarray(fun(qps))
            vals.shape = (dpn, qps.shape[0])

            n_qp_face = len(bvals[0])

            # Assemble l2 projection system.
            for ii, (ie, ifa) in enumerate(fis):
                # Assembling indices.
                elc = lconn[ii]

                fvals = vals[:, n_qp_face * ii:n_qp_face * (ii + 1)]

                fbfs = all_fbfs[ii]
                dets = all_dets[ii]

                # Local projection system.
                for idof in range(dpn):
                    lrhs = (fbfs * (fvals[idof, :, None] * dets)).sum(0)
                    rhs[idof, elc] += lrhs

                lmtx = ((fbfs[..., None] * fbfs[:, None, :]) *
                        dets[..., None]).sum(0)

                er, ec = nm.meshgrid(elc, elc)
                rows.append(er.ravel())
                cols.append(ec.ravel())
                mvals.append(lmtx.ravel())

            rows = nm.concatenate(rows)
            cols = nm.concatenate(cols)
            mvals = nm.concatenate(mvals)
            mtx = sps.coo_matrix((mvals, (rows, cols)), shape=(n_dof, n_dof))

            vals = nm.zeros((dpn, n_dof), dtype=nm.float64)

            # Solve l2 projection system.
            for idof in range(dpn):
                dofs = solve(mtx, rhs[idof, :])
                vals[idof, remap[nods]] = dofs

        else:
            raise ValueError('unknown function/value type! (%s)' % type(fun))

        return nods, vals
Beispiel #8
0
    def set_dofs(self, fun=0.0, region=None, dpn=None, warn=None):
        """
        Set the values of DOFs given by the `region` using a function of space
        coordinates or value `fun`.

        If `fun` is a function, the l2 projection that is global for all region
        facets is used to set the DOFs.

        If `dpn > 1`, and `fun` is a function, it has to return the values
        DOF-by-DOF, i.e. a single one-dimensional vector with all values of the
        first component, then of the second one etc. concatenated
        together.

        Parameters
        ----------
        fun : float or array of length dpn or callable
            The DOF values.
        region : Region
            The region containing the DOFs.
        dpn : int, optional
            The DOF-per-node count. If not given, the number of field
            components is used.
        warn : str, optional
            The warning message printed when the region selects no DOFs.

        Returns
        -------
        nods : array, shape (n_dof,)
            The field DOFs (or node indices) given by the region.
        vals : array, shape (dpn, n_dof)
            The values of the DOFs, DOF-by-DOF when raveled in C (row-major)
            order.
        """
        if region is None:
            region = self.region

        if dpn is None:
            dpn = self.n_components

        nods = []
        vals = []

        aux = self.get_dofs_in_region(region)
        nods = nm.unique(nm.hstack(aux))

        if nm.isscalar(fun):
            vals = nm.repeat([fun], nods.shape[0] * dpn)

        elif isinstance(fun, nm.ndarray):
            assert_(len(fun) == dpn)
            vals = nm.repeat(fun, nods.shape[0])

        elif callable(fun):
            import scipy.sparse as sps
            from sfepy.solvers.ls import solve
            from sfepy.discrete.integrals import Integral
            from sfepy.discrete.fem.utils import prepare_remap
            import sfepy.discrete.iga as iga
            from sfepy.discrete.iga.extmods.igac import eval_mapping_data_in_qp

            nurbs = self.nurbs
            facets = self._get_facets(region.kind_tdim)

            # Region facet connectivity.
            rconn = self.get_econn('surface', region)

            # Local connectivity.
            remap = prepare_remap(nods, nods.max() + 1)
            lconn = [remap[ii] for ii in rconn]

            # Cell and face(cell) ids for each facet.
            fis = region.get_facet_indices()

            # Integral given by max. NURBS surface degree.
            fdegrees = iga.get_surface_degrees(nurbs.degrees)
            order = fdegrees.max()
            integral = Integral('i', order=2*order)
            vals, weights = integral.get_qp(self.domain.gel.surface_facet_name)

            # Boundary QP - use tensor product structure.
            bvals = iga.create_boundary_qp(vals, region.tdim)

            # Compute facet basis, jacobians and physical BQP.
            n_dof = len(nods)
            rhs = nm.zeros((dpn, n_dof), dtype=nm.float64)
            rows, cols, mvals = [], [], []
            all_qp = []
            all_fbfs = []
            all_dets = []
            for ii, (ie, ifa) in enumerate(fis):
                qp_coors = bvals[ifa]

                bfs, _, dets = eval_mapping_data_in_qp(qp_coors, nurbs.cps,
                                                       nurbs.weights,
                                                       nurbs.degrees,
                                                       nurbs.cs,
                                                       nurbs.conn,
                                                       nm.array([ie]))
                # Facet basis.
                fbfs = bfs[..., facets[ifa]][0, :, 0, :]

                # Weight Jacobians by quadrature point weights.
                dets = nm.abs(dets) * weights[None, :, None, None]
                dets = dets[0, :, 0, :]

                # Physical BQP.
                fcps = nurbs.cps[nurbs.conn[ie, facets[ifa]]]
                qp = nm.dot(fbfs, fcps)

                all_qp.append(qp)
                all_fbfs.append(fbfs)
                all_dets.append(dets)

            # DOF values in the physical BQP.
            qps = nm.concatenate(all_qp)
            vals = nm.asarray(fun(qps))
            vals.shape = (dpn, qps.shape[0])

            n_qp_face = len(bvals[0])

            # Assemble l2 projection system.
            for ii, (ie, ifa) in enumerate(fis):
                # Assembling indices.
                elc = lconn[ii]

                fvals = vals[:, n_qp_face * ii : n_qp_face * (ii + 1)]

                fbfs = all_fbfs[ii]
                dets = all_dets[ii]

                # Local projection system.
                for idof in xrange(dpn):
                    lrhs = (fbfs * (fvals[idof, :, None] * dets)).sum(0)
                    rhs[idof, elc] += lrhs

                lmtx = ((fbfs[..., None] * fbfs[:, None, :])
                        * dets[..., None]).sum(0)

                er, ec = nm.meshgrid(elc, elc)
                rows.append(er.ravel())
                cols.append(ec.ravel())
                mvals.append(lmtx.ravel())

            rows = nm.concatenate(rows)
            cols = nm.concatenate(cols)
            mvals = nm.concatenate(mvals)
            mtx = sps.coo_matrix((mvals, (rows, cols)), shape=(n_dof, n_dof))

            vals = nm.zeros((dpn, n_dof), dtype=nm.float64)

            # Solve l2 projection system.
            for idof in xrange(dpn):
                dofs = solve(mtx, rhs[idof, :])
                vals[idof, remap[nods]] = dofs

        else:
            raise ValueError('unknown function/value type! (%s)' % type(fun))

        return nods, vals
Beispiel #9
0
    def _eval_basis_transform(self, subs):
        """
        """
        from sfepy.discrete import Integral
        from sfepy.discrete.fem import Mesh, FEDomain, Field

        transform = nm.tile(nm.eye(self.econn.shape[1]),
                            (self.econn.shape[0], 1, 1))
        if subs is None:
            return transform

        gel = self.gel
        ao = self.approx_order

        conn = [gel.conn]
        mesh = Mesh.from_data('a', gel.coors, None, [conn], [nm.array([0])],
                              [gel.name])
        cdomain = FEDomain('d', mesh)
        comega = cdomain.create_region('Omega', 'all')
        rcfield = Field.from_args('rc', self.dtype, 1, comega, approx_order=ao)

        fdomain = cdomain.refine()
        fomega = fdomain.create_region('Omega', 'all')
        rffield = Field.from_args('rf', self.dtype, 1, fomega, approx_order=ao)

        def assign_transform(transform, bf, subs, ef):
            if not len(subs): return

            n_sub = (subs.shape[1] - 2) // 2

            for ii, sub in enumerate(subs):
                for ij in range(n_sub):
                    ik = 2 * (ij + 1)

                    fface = ef[sub[ik + 1]]

                    mtx = transform[sub[ik]]
                    ix, iy = nm.meshgrid(fface, fface)

                    cbf = bf[iy, 0, ix]

                    mtx[ix, iy] = cbf

        fcoors = rffield.get_coor()

        coors = fcoors[rffield.econn[0]]
        integral = Integral('i',
                            coors=coors,
                            weights=nm.ones_like(coors[:, 0]))

        rcfield.clear_qp_base()
        bf = rcfield.get_base('v', False, integral)

        if gel.name == '2_4':
            fsubs = subs
            esubs = None

            assign_transform(transform, bf, fsubs, rffield.efaces)

        else:
            fsubs = subs[0]
            esubs = subs[1]

            assign_transform(transform, bf, fsubs, rffield.efaces)
            if esubs is not None:
                assign_transform(transform, bf, esubs, rffield.eedges)

        assert_((nm.abs(transform.sum(1) - 1.0) < 1e-15).all())

        return transform
Beispiel #10
0
def load_and_plot_fun(folder, filename, exact=None):
    """
    Parameters
    ----------
    folder : str
        folder where to look for files
    filename : str
        used in {name}.i.vtk, i = 0,1, ... tns - 1
        number of time steps
    exact : callable
        exact solution at the last frame
    """
    in_file = head(glob(pjoin(folder, "*.vtk")))

    coors, data = load_state_1D_vtk(in_file)

    approx_order = data.shape[0] - 1

    dmesh = Mesh.from_file(in_file)
    domain = FEDomain("", dmesh)
    omega = domain.create_region('Omega', 'all')

    field = DGField('f',
                    nm.float64,
                    'scalar',
                    omega,
                    approx_order=approx_order)
    # Sufficient quadrature order for the analytical expression.
    idiff = Integral('idiff', 20)

    u = FieldVariable("u", "unknown", field)

    eqs = Equations(
        [Equation('balance', SurfaceTerm("s()", "u", idiff, omega, u=u))])
    pb = Problem("err_est", equations=eqs)

    u.set_data(field.ravel_sol(data.swapaxes(0, 1)))

    num_qp = pb.evaluate('ev_volume_integrate.idiff.Omega(u)',
                         u=u,
                         integrals=Integrals([idiff]),
                         mode='qp')

    aux = Material('aux', function=sol_fun)
    ana_qp = pb.evaluate('ev_volume_integrate_mat.idiff.Omega(aux.u, u)',
                         aux=aux,
                         u=u,
                         integrals=Integrals([idiff]),
                         mode='qp')
    qps = pb.fields["f"].mapping.get_physical_qps(idiff.get_qp("1_2")[0])
    fqps = qps.flatten()

    plt.figure("Reconstructed solution")
    plt.gca().set_ylim(-.5, 3.)

    ww_approx, xx = reconstruct_legendre_dofs(coors, None, data)
    ww_exact = exact(xx)

    XN = xx[-1]
    X1 = xx[0]
    plt.plot([X1, XN], [2, 2], 'grey', alpha=.6)
    plt.plot([X1, XN], [0, 0], 'grey', alpha=.6)
    plt.plot(fqps, ana_qp.flatten(), label="$p_{exact}(1, x)$")
    plt.plot(fqps, num_qp.flatten(), label="$p_h(1, x)$")
    plt.legend()
    plt.show()