<commit_before>"""
Notes
-----

Important attributes of continuous (order > 0) :class:`Field` and
:class:`SurfaceField` instances:

- `vertex_remap` : `econn[:, :n_vertex] = vertex_remap[conn]`
- `vertex_remap_i` : `conn = vertex_remap_i[econn[:, :n_vertex]]`

where `conn` is the mesh vertex connectivity, `econn` is the
region-local field connectivity.
"""
import numpy as nm

from sfepy.base.base import assert_
from sfepy.discrete.fem.utils import prepare_remap
from sfepy.discrete.common.dof_info import expand_nodes_to_dofs
from sfepy.discrete.fem.facets import get_facet_dof_permutations
from sfepy.discrete.fem.fields_base import (FEField, VolumeField, SurfaceField,
                                            H1Mixin)

class H1NodalMixin(H1Mixin):

    def _setup_facet_orientations(self):
        order = self.approx_order
        self.node_desc = self.poly_space.describe_nodes()

        edge_nodes = self.node_desc.edge_nodes
        if edge_nodes is not None:
            n_fp = self.gel.edges.shape[1]
            self.edge_dof_perms = get_facet_dof_permutations(n_fp, order)

        face_nodes = self.node_desc.face_nodes
        if face_nodes is not None:
            n_fp = self.gel.faces.shape[1]
            self.face_dof_perms = get_facet_dof_permutations(n_fp, order)

    def _setup_edge_dofs(self):
        """
        Setup edge DOF connectivity.
        """
        if self.node_desc.edge is None:
            return 0, None, None

        return self._setup_facet_dofs(1, self.node_desc.edge,
                                      self.edge_dof_perms,
                                      self.n_vertex_dof)

    def _setup_face_dofs(self):
        """
        Setup face DOF connectivity.
        """
        if self.node_desc.face is None:
            return 0, None, None

        return self._setup_facet_dofs(self.domain.shape.tdim - 1,
                                      self.node_desc.face,
                                      self.face_dof_perms,
                                      self.n_vertex_dof + self.n_edge_dof)

    def _setup_facet_dofs(self, dim, facet_desc, facet_perms, offset):
        """
        Helper function to setup facet DOF connectivity, works for both
        edges and faces.
        """
        facet_desc = nm.array(facet_desc)
        n_dof_per_facet = facet_desc.shape[1]

        cmesh = self.domain.cmesh

        facets = self.region.entities[dim]
        ii = nm.arange(facets.shape[0], dtype=nm.int32)
        all_dofs = offset + expand_nodes_to_dofs(ii, n_dof_per_facet)

        # Prepare global facet id remapping to field-local numbering.
        remap = prepare_remap(facets, cmesh.num[dim])

        cconn = self.region.domain.cmesh.get_conn(self.region.tdim, dim)
        offs = cconn.offsets

        n_f = self.gel.edges.shape[0] if dim == 1 else self.gel.faces.shape[0]

        oris = cmesh.get_orientations(dim)

        gcells = self.region.get_cells()
        n_el = gcells.shape[0]

        # Elements of facets.
        iel = nm.arange(n_el, dtype=nm.int32).repeat(n_f)
        ies = nm.tile(nm.arange(n_f, dtype=nm.int32), n_el)

        aux = offs[gcells][:, None] + ies.reshape((n_el, n_f))

        indices = cconn.indices[aux]
        facets_of_cells = remap[indices].ravel()

        ori = oris[aux].ravel()
        perms = facet_perms[ori]

        # Define global facet dof numbers.
        gdofs = offset + expand_nodes_to_dofs(facets_of_cells,
                                              n_dof_per_facet)

        # DOF columns in econn for each facet.
        iep = facet_desc[ies]

        iaux = nm.arange(gdofs.shape[0], dtype=nm.int32)
        self.econn[iel[:, None], iep] = gdofs[iaux[:, None], perms]

        n_dof = n_dof_per_facet * facets.shape[0]
        assert_(n_dof == nm.prod(all_dofs.shape))

        return n_dof, all_dofs, remap

    def _setup_bubble_dofs(self):
        """
        Setup bubble DOF connectivity.
        """
        if self.node_desc.bubble is None:
            return 0, None, None

        offset = self.n_vertex_dof + self.n_edge_dof + self.n_face_dof
        n_dof_per_cell = self.node_desc.bubble.shape[0]

        ii = self.region.get_cells()
        remap = prepare_remap(ii, self.domain.cmesh.n_el)

        n_cell = ii.shape[0]
        n_dof = n_dof_per_cell * n_cell

        all_dofs = nm.arange(offset, offset + n_dof, dtype=nm.int32)
        all_dofs.shape = (n_cell, n_dof_per_cell)
        iep = self.node_desc.bubble[0]
        self.econn[:,iep:] = all_dofs

        return n_dof, all_dofs, remap

    def _substitute_dofs(self, gsubs):
        """
        Perform facet DOF substitutions according to `gsubs`.

        Modifies `self.econn` in-place.
        """
        if self.gel.name == '2_4':
            ef = self.efaces

            oris = self.domain.cmesh.edge_oris.reshape((-1, 4))
            for ii, sub in enumerate(gsubs):
                # 2_4 edges always in opposite orientation.
                mori = oris[sub[0], sub[1]]
                assert_(oris[sub[2], sub[3]] == 1 - mori)
                assert_(oris[sub[4], sub[5]] == 1 - mori)

                ee = ef[sub[1]].copy()
                ee[0], ee[1] = ee[1], ee[0] # Swap vertex DOFs.
                ee[2:] = ee[-1:1:-1] # Swap edge DOFs.

                master = self.econn[sub[0], ee]
                self.econn[sub[2], ef[sub[3]]] = master
                self.econn[sub[4], ef[sub[5]]] = master

        elif self.gel.name == '3_8':
            pass

        else:
            raise ValueError('unsupported reference element type! (%s)'
                             % self.gel.name)

    def set_dofs(self, fun=0.0, region=None, dpn=None, warn=None):
        """
        Set the values of DOFs in a given region using a function of space
        coordinates or value `fun`.
        """
        if region is None:
            region = self.region

        if dpn is None:
            dpn = self.n_components

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

        if callable(fun):
            vals = fun(self.get_coor(nods))

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

        elif isinstance(fun, nm.ndarray):
            assert_(len(fun) == dpn)<commit_msg>update H1NodalMixin._substitute_dofs() for 3D, new _sort4()<commit_after>"""
Notes
-----

Important attributes of continuous (order > 0) :class:`Field` and
:class:`SurfaceField` instances:

- `vertex_remap` : `econn[:, :n_vertex] = vertex_remap[conn]`
- `vertex_remap_i` : `conn = vertex_remap_i[econn[:, :n_vertex]]`

where `conn` is the mesh vertex connectivity, `econn` is the
region-local field connectivity.
"""
import numpy as nm

from sfepy.base.base import assert_
from sfepy.discrete.fem.utils import prepare_remap
from sfepy.discrete.common.dof_info import expand_nodes_to_dofs
from sfepy.discrete.fem.facets import get_facet_dof_permutations
from sfepy.discrete.fem.fields_base import (FEField, VolumeField, SurfaceField,
                                            H1Mixin)

class H1NodalMixin(H1Mixin):

    def _setup_facet_orientations(self):
        order = self.approx_order
        self.node_desc = self.poly_space.describe_nodes()

        edge_nodes = self.node_desc.edge_nodes
        if edge_nodes is not None:
            n_fp = self.gel.edges.shape[1]
            self.edge_dof_perms = get_facet_dof_permutations(n_fp, order)

        face_nodes = self.node_desc.face_nodes
        if face_nodes is not None:
            n_fp = self.gel.faces.shape[1]
            self.face_dof_perms = get_facet_dof_permutations(n_fp, order)

    def _setup_edge_dofs(self):
        """
        Setup edge DOF connectivity.
        """
        if self.node_desc.edge is None:
            return 0, None, None

        return self._setup_facet_dofs(1, self.node_desc.edge,
                                      self.edge_dof_perms,
                                      self.n_vertex_dof)

    def _setup_face_dofs(self):
        """
        Setup face DOF connectivity.
        """
        if self.node_desc.face is None:
            return 0, None, None

        return self._setup_facet_dofs(self.domain.shape.tdim - 1,
                                      self.node_desc.face,
                                      self.face_dof_perms,
                                      self.n_vertex_dof + self.n_edge_dof)

    def _setup_facet_dofs(self, dim, facet_desc, facet_perms, offset):
        """
        Helper function to setup facet DOF connectivity, works for both
        edges and faces.
        """
        facet_desc = nm.array(facet_desc)
        n_dof_per_facet = facet_desc.shape[1]

        cmesh = self.domain.cmesh

        facets = self.region.entities[dim]
        ii = nm.arange(facets.shape[0], dtype=nm.int32)
        all_dofs = offset + expand_nodes_to_dofs(ii, n_dof_per_facet)

        # Prepare global facet id remapping to field-local numbering.
        remap = prepare_remap(facets, cmesh.num[dim])

        cconn = self.region.domain.cmesh.get_conn(self.region.tdim, dim)
        offs = cconn.offsets

        n_f = self.gel.edges.shape[0] if dim == 1 else self.gel.faces.shape[0]

        oris = cmesh.get_orientations(dim)

        gcells = self.region.get_cells()
        n_el = gcells.shape[0]

        # Elements of facets.
        iel = nm.arange(n_el, dtype=nm.int32).repeat(n_f)
        ies = nm.tile(nm.arange(n_f, dtype=nm.int32), n_el)

        aux = offs[gcells][:, None] + ies.reshape((n_el, n_f))

        indices = cconn.indices[aux]
        facets_of_cells = remap[indices].ravel()

        ori = oris[aux].ravel()
        perms = facet_perms[ori]

        # Define global facet dof numbers.
        gdofs = offset + expand_nodes_to_dofs(facets_of_cells,
                                              n_dof_per_facet)

        # DOF columns in econn for each facet.
        iep = facet_desc[ies]

        iaux = nm.arange(gdofs.shape[0], dtype=nm.int32)
        self.econn[iel[:, None], iep] = gdofs[iaux[:, None], perms]

        n_dof = n_dof_per_facet * facets.shape[0]
        assert_(n_dof == nm.prod(all_dofs.shape))

        return n_dof, all_dofs, remap

    def _setup_bubble_dofs(self):
        """
        Setup bubble DOF connectivity.
        """
        if self.node_desc.bubble is None:
            return 0, None, None

        offset = self.n_vertex_dof + self.n_edge_dof + self.n_face_dof
        n_dof_per_cell = self.node_desc.bubble.shape[0]

        ii = self.region.get_cells()
        remap = prepare_remap(ii, self.domain.cmesh.n_el)

        n_cell = ii.shape[0]
        n_dof = n_dof_per_cell * n_cell

        all_dofs = nm.arange(offset, offset + n_dof, dtype=nm.int32)
        all_dofs.shape = (n_cell, n_dof_per_cell)
        iep = self.node_desc.bubble[0]
        self.econn[:,iep:] = all_dofs

        return n_dof, all_dofs, remap

    def _substitute_dofs(self, gsubs):
        """
        Perform facet DOF substitutions according to `gsubs`.

        Modifies `self.econn` in-place.
        """
        if self.gel.name == '2_4':
            ef = self.efaces

            oris = self.domain.cmesh.edge_oris.reshape((-1, 4))
            for ii, sub in enumerate(gsubs):
                # 2_4 edges always in opposite orientation.
                mori = oris[sub[0], sub[1]]
                assert_(oris[sub[2], sub[3]] == 1 - mori)
                assert_(oris[sub[4], sub[5]] == 1 - mori)

                ee = ef[sub[1]].copy()
                ee[0], ee[1] = ee[1], ee[0] # Swap vertex DOFs.
                ee[2:] = ee[-1:1:-1] # Swap edge DOFs.

                master = self.econn[sub[0], ee]
                self.econn[sub[2], ef[sub[3]]] = master
                self.econn[sub[4], ef[sub[5]]] = master

        elif self.gel.name == '3_8':
            def _sort4(p):
                key = 0

                if (p[0] < p[1]): key += 1
                if (p[0] < p[2]): key += 2
                if (p[1] < p[2]): key += 4
                if (p[0] < p[3]): key += 8
                if (p[1] < p[3]): key += 16
                if (p[2] < p[3]): key += 32

                return key

            if gsubs[0] is not None:
                ef = self.efaces
                epf = self.gel.get_edges_per_face()
                nde = self.node_desc.edge
                ndf = self.node_desc.face
                gedges = self.gel.edges
                gfaces = self.gel.faces

                for ii, sub in enumerate(gsubs[0]):
                    master = self.econn[sub[0]]
                    fmaster = master[ef[sub[1]]]
                    lmaster = fmaster.tolist()

                    for ic in range(4):
                        ia, ib = 2 + 2 * ic, 2 + 2 * ic + 1
                        cell = self.econn[sub[ia]]

                        # Corner vertex is always the first for faces 0, 1, 2.
                        iv = cell[ef[sub[ib]][0]]
                        i0 = lmaster.index(iv)
                        for ik in range(4):
                            cell[ef[sub[ib]][ik]] = fmaster[:4][i0 - ik]

                        # Treat edge DOFs.
                        if nde is not None:
                            sedges = epf[sub[ib]]
                            medges = epf[sub[1]]
                            for ie, sedge in enumerate(sedges):
                                iim =  i0 - 1 - ie
                                ies = nde[sedge]
                                medge = medges[iim]
                                iem = nde[medge]

                                vm = master[gedges[medge]][0]
                                vs = cell[gedges[sedge]][0]
                                if vm == vs:
                                    cell[ies] = self.econn[sub[0], iem]

                                else:
                                    cell[ies] = self.econn[sub[0], iem[::-1]]

                        # Treat face DOFs.
                        if ndf is not None:
                            new_ori = _sort4(cell[gfaces[sub[ib]]])
                            smaster = nm.sort(master[ndf[sub[1]]])
                            aux = self.face_dof_perms[new_ori]
                            cell[ndf[sub[ib]]] = smaster[aux]

            if gsubs[1] is not None:
                ef = self.eedges
                for ii, sub in enumerate(gsubs[1]):
                    master = self.econn[sub[0]]

                    me = master[gedges[sub[1]]]
                    for ic in range(2):
                        ia, ib = 2 + 2 * ic, 2 + 2 * ic + 1
                        cell = self.econn[sub[ia]]
                        ce = cell[gedges[sub[ib]]]

                        if (me[0] == ce[0]) or (me[1] == ce[1]):
                            cell[ef[sub[ib]]] = master[ef[sub[1]]]

                        else:
                            ee = ef[sub[1]].copy()
                            ee[0], ee[1] = ee[1], ee[0] # Swap vertex DOFs.
                            ee[2:] = ee[-1:1:-1] # Swap edge DOFs.
                            cell[ef[sub[ib]]] = master[ee]

        else:
            raise ValueError('unsupported reference element type! (%s)'
                             % self.gel.name)

    def set_dofs(self, fun=0.0, region=None, dpn=None, warn=None):
        """
        Set the values of DOFs in a given region using a function of space
        coordinates or value `fun`.
        """
        if region is None:
            region = self.region

        if dpn is None:
            dpn = self.n_components

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

        if callable(fun):
            vals = fun(self.get_coor(nods))

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

        elif isinstance(fun, nm.ndarray):
            assert_(len(fun) == dpn)
{'fraction_non_alphanumeric': 0.11116709705863828, 'fraction_numerical': 0.013037727530389872, 'mean_word_length': 1.6063690085357847, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 27, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7201782', 'n_tokens_mistral': 5518, 'n_tokens_neox': 5146, 'n_words': 1085}