@@ -567,186 +567,168 @@ def create_cell_closure(PETSc.DM dm,
567
567
568
568
@ cython.boundscheck (False )
569
569
@ cython.wraparound (False )
570
- def closure_ordering (mesh ,
571
- np.ndarray[PetscInt , ndim = 2 , mode = " c" ] closure_data,
572
- PETSc.Section vertex_numbering ,
573
- np.ndarray[PetscInt , ndim = 1 , mode = " c" ] entity_per_cell):
574
- """ Apply Fenics local numbering to a cell closure.
570
+ def closure_ordering (mesh , closure_data , closure_sizes ):
571
+ """ Apply FEniCS local numbering to a cell closure.
575
572
576
- :arg dm: The DM object encapsulating the mesh topology
577
- :arg vertex_numbering: Section describing the universal vertex numbering
578
- :arg cell_numbering: Section describing the global cell numbering
579
- :arg entity_per_cell: List of the number of entity points in each dimension
573
+ The reordering is achieved by ordering vertices according to their global
574
+ number and by ordering edges and facets according to a lexicographical
575
+ order of the non-incident vertices.
576
+
577
+ Parameters
578
+ ----------
579
+ mesh : MeshTopology
580
+ The mesh providing the closures.
581
+ closure_data : tuple
582
+ Tuple of arrays storing cell closure information per dimension.
583
+ closure_sizes : tuple
584
+ The number of points in the cell closure per dimension.
580
585
581
- Vertices := Ordered according to global/universal
582
- vertex numbering
583
- Edges/faces := Ordered according to lexicographical
584
- ordering of non-incident vertices
585
586
"""
586
587
cdef:
587
- PetscInt c, cStart, cEnd, v, vStart, vEnd
588
- PetscInt f, fStart, fEnd, e, eStart, eEnd
589
- PetscInt dim, vi, ci, fi, v_per_cell, f_per_cell, cell
590
- PetscInt offset, cell_offset, nfaces, nfacets
591
- PetscInt nclosure, nfacet_closure, nface_vertices
592
- PetscInt * vertices = NULL
593
- PetscInt * v_global = NULL
594
- # PetscInt *closure = NULL
595
- np.ndarray[PetscInt, ndim= 1 , mode= " c" ] closure
596
- PetscInt * facets = NULL
597
- PetscInt * faces = NULL
598
- PetscInt * face_indices = NULL
599
- const PetscInt * face_vertices = NULL
600
- PetscInt * facet_vertices = NULL
601
- np.ndarray[PetscInt, ndim= 2 , mode= " c" ] cell_closure
602
-
603
- PETSc.DM dm = mesh.topology_dm
604
-
605
- if vertex_numbering is not None :
606
- raise NotImplementedError (" TODO, see comments in mesh._closure_map" )
607
-
608
- dim = get_topological_dimension(dm)
609
- get_height_stratum(dm.dm, 0 , & cStart, & cEnd)
610
- get_height_stratum(dm.dm, 1 , & fStart, & fEnd)
611
- get_depth_stratum(dm.dm, 1 , & eStart, & eEnd)
612
- get_depth_stratum(dm.dm, 0 , & vStart, & vEnd)
613
-
614
- v_per_cell = entity_per_cell[0 ]
615
- if len (entity_per_cell) > 1 :
616
- f_per_cell = entity_per_cell[1 ]
617
- else :
618
- f_per_cell = 0
619
-
620
- cell_offset = sum (entity_per_cell) - 1
621
-
622
- CHKERR(PetscMalloc1(v_per_cell, & vertices))
623
- CHKERR(PetscMalloc1(v_per_cell, & v_global))
624
- CHKERR(PetscMalloc1(v_per_cell, & facets))
625
- if v_per_cell > 0 :
626
- CHKERR(PetscMalloc1(v_per_cell- 1 , & facet_vertices))
627
- if len (entity_per_cell) > 1 :
628
- CHKERR(PetscMalloc1(f_per_cell, & faces))
629
- CHKERR(PetscMalloc1(f_per_cell, & face_indices))
630
- cell_closure = np.empty((cEnd - cStart, sum (entity_per_cell)), dtype = IntType)
588
+ PETSc.DM dm
589
+ PetscInt tdim, cell
590
+ PetscInt nverts_per_cell, nedges_per_cell, nfacets_per_cell
591
+ PetscInt * verts= NULL , * edges= NULL , * facets= NULL , * global_verts= NULL
592
+ PetscInt * edge_cone= NULL , * edge_verts= NULL , * edge_incident_verts= NULL
593
+ PetscInt nfacet_closure, * facet_closure= NULL , * facet_verts= NULL
631
594
632
- for c in range (cStart, cEnd):
633
- # renumbering already complete
634
- # CHKERR(PetscSectionGetOffset(cell_numbering.sec, c, &cell))
635
- cell_dim, cell = mesh.points.axis_to_component_number(c)
636
- assert int (cell_dim.label) == dim
637
-
638
- # closure already packed
639
- # get_transitive_closure(dm.dm, c, PETSC_TRUE, &nclosure, &closure)
640
- # NOTE: This closure omits orientations, so the factor of 2 can be omitted
641
- closure = closure_data[cell, :]
642
-
643
- # Find vertices and translate universal numbers
644
- nverts = entity_per_cell[0 ]
645
- for i in range (nverts):
646
- vertices[i] = closure[i]
595
+ dm = mesh.topology_dm
596
+ tdim = mesh.dimension
597
+ assert tdim <= 3
598
+
599
+ nverts_per_cell = closure_sizes[0 ]
600
+ nedges_per_cell = closure_sizes[1 ] if tdim >= 1 else 0
601
+ nfacets_per_cell = closure_sizes[tdim- 1 ] if tdim >= 1 else 0
602
+
603
+ CHKERR(PetscMalloc1(nverts_per_cell, & verts))
604
+ CHKERR(PetscMalloc1(nedges_per_cell, & edges))
605
+ CHKERR(PetscMalloc1(nfacets_per_cell, & facets))
606
+ CHKERR(PetscMalloc1(nverts_per_cell, & global_verts))
607
+
608
+ CHKERR(PetscMalloc1(2 , & edge_verts))
609
+ CHKERR(PetscMalloc1(nedges_per_cell, & edge_incident_verts))
610
+
611
+ # upper bound
612
+ CHKERR(PetscMalloc1(nverts_per_cell, & facet_verts))
613
+
614
+ closure_data_reord = tuple (np.empty_like(d) for d in closure_data)
615
+ for cell in range (mesh.num_cells()):
616
+ # 1. Order vertices
617
+ for vi, vert in enumerate (closure_data[0 ][cell]):
618
+ verts[vi] = vert
619
+ global_verts[vi] = mesh._global_vertex_numbering[vert]
647
620
648
- if dm.comm.size > 1 :
649
- raise NotImplementedError
650
- # TODO for now assume that we are serial and that the local and
651
- # global numbers match
652
- for i in range (nverts):
653
- v_global[i] = vertices[i]
654
-
655
- # Sort vertices by universal number
656
- CHKERR(PetscSortIntWithArray(v_per_cell,v_global,vertices))
657
- for vi in range (v_per_cell):
658
- if dim == 1 :
659
- # Correct 1D edge numbering
660
- cell_closure[cell, vi] = vertices[v_per_cell- vi- 1 ]
661
- else :
662
- cell_closure[cell, vi] = vertices[vi]
663
- offset = v_per_cell
664
-
665
- # Find all edges (dim=1) (only relevant for `DMPlex`)
666
- if dim > 2 :
667
- raise NotImplementedError (" think about renumbered cones" )
668
- assert isinstance (dm, PETSc.DMPlex)
669
- nfaces = 0
670
- for ci in range (nclosure):
671
- if eStart <= closure[ci] < eEnd:
672
- faces[nfaces] = closure[ci]
673
-
674
- CHKERR(DMPlexGetConeSize(dm.dm, closure[ci],
675
- & nface_vertices))
676
- CHKERR(DMPlexGetCone(dm.dm, closure[ci],
677
- & face_vertices))
678
-
679
- # Edges in 3D are tricky because we need a
680
- # lexicographical sort with two keys (the local
681
- # numbers of the two non-incident vertices).
682
-
683
- # Find non-incident vertices
684
- fi = 0
685
- face_indices[nfaces] = 0
686
- for v in range (v_per_cell):
687
- incident = 0
688
- for vi in range (nface_vertices):
689
- if cell_closure[cell,v] == face_vertices[vi]:
690
- incident = 1
691
- break
692
- if incident == 0 :
693
- face_indices[nfaces] += v * 10 ** (1 - fi)
694
- fi += 1
695
- nfaces += 1
621
+ # Sort vertices by their global number
622
+ CHKERR(PetscSortIntWithArray(nverts_per_cell, global_verts, verts))
623
+
624
+ # Insert into the closure
625
+ for vi in range (nverts_per_cell):
626
+ # Correct 1D edge numbering
627
+ vert = verts[vi] if tdim != 1 else verts[nverts_per_cell- vi- 1 ]
628
+ closure_data_reord[0 ][cell, vi] = vert
629
+
630
+ # 2. Order edges (3D only, in 2D facets and edges are equivalent)
631
+ if tdim > 2 :
632
+ # Edges are tricky because we need a lexicographical sort with two
633
+ # keys (the local numbers of the two non-incident vertices)
634
+ for ei, edge in enumerate (closure_data[1 ][cell]):
635
+ edges[ei] = edge
636
+
637
+ # Convert the edge, which is in stratum-local, renumbered form
638
+ # back to what plex expects
639
+ edge_unrenum = mesh.points.applied_to_default_component_number(
640
+ mesh.edge_label, edge
641
+ )
642
+ edge_pt = mesh.points.component_to_axis_number(
643
+ mesh.edge_label, edge_unrenum
644
+ )
645
+
646
+ # Collect incident vertices
647
+ CHKERR(DMPlexGetCone(dm.dm, edge_pt, & edge_cone))
648
+ for i in range (2 ):
649
+ pt = edge_cone[i]
650
+ stratum, stratum_pt = mesh.points.axis_to_component_number(pt)
651
+ stratum_pt_renum = mesh.points.default_to_applied_component_number(
652
+ stratum, stratum_pt
653
+ )
654
+ edge_verts[i] = stratum_pt_renum
655
+
656
+ # Find non-incident vertices and store lexicographically
657
+ edge_incident_verts[ei] = 0
658
+ ptr = 0
659
+ for vi in range (nverts_per_cell):
660
+ incident = False
661
+ for vj in range (2 ):
662
+ if edge_verts[vj] == closure_data[0 ][cell, vi]:
663
+ incident = True
664
+ break
665
+ if not incident:
666
+ edge_incident_verts[ei] += vi * 10 ** (1 - ptr)
667
+ ptr += 1
696
668
697
669
# Sort by local numbers of non-incident vertices
698
- CHKERR(PetscSortIntWithArray(f_per_cell,
699
- face_indices, faces))
700
- for fi in range (nfaces):
701
- cell_closure[cell, offset+ fi] = faces[fi]
702
- offset += nfaces
703
-
704
- # Find all facets (co-dim=1)
705
- nfacets = entity_per_cell[dim- 1 ]
706
- for i in range (nfacets):
707
- # add nverts to skip those, bad for 3D
708
- facets[i] = closure[nverts+ i]
709
-
710
- # The cell itself is always the first entry in the Plex closure
711
- cell_closure[cell, cell_offset] = closure[0 ]
712
-
713
- # Now we can deal with facets (only relevant for `DMPlex`)
714
- if dim > 1 :
715
- for f in range (nfacets):
716
- # Derive facet vertices from facet_closure
717
- myverts = mesh._closures[dim- 1 ][1 ][0 ][facets[f]]
718
-
719
- if dim > 2 :
720
- # skip tets for now, assume facets are edges
721
- # and therefore that the closure has 3 entries
722
- raise NotImplementedError
723
-
724
- facet_vertices[0 ] = myverts[0 ]
725
- facet_vertices[1 ] = myverts[1 ]
726
-
727
- # Find non-incident vertices
728
- for v in range (v_per_cell):
729
- incident = 0
730
- for vi in range (v_per_cell- 1 ):
731
- if cell_closure[cell,v] == facet_vertices[vi]:
732
- incident = 1
670
+ CHKERR(PetscSortIntWithArray(nedges_per_cell, edge_incident_verts, edges))
671
+
672
+ # Insert into the closure
673
+ for ei in range (nedges_per_cell):
674
+ closure_data_reord[1 ][cell, ei] = edges[ei]
675
+
676
+ # 3. Order facets
677
+ if tdim > 1 :
678
+ for fi, facet in enumerate (closure_data[tdim- 1 ][cell]):
679
+ # Convert the facet, which is in stratum-local, renumbered form
680
+ # back to what plex expects
681
+ facet_unrenum = mesh.points.applied_to_default_component_number(
682
+ mesh.facet_label, facet
683
+ )
684
+ facet_pt = mesh.points.component_to_axis_number(
685
+ mesh.facet_label, facet_unrenum
686
+ )
687
+
688
+ # Collect vertices that are in the closure of the facet
689
+ get_transitive_closure(
690
+ dm.dm, facet_pt, PETSC_TRUE, & nfacet_closure, & facet_closure
691
+ )
692
+ ptr = 0
693
+ for i in range (nfacet_closure):
694
+ pt = facet_closure[2 * i]
695
+ stratum, stratum_pt = mesh.points.axis_to_component_number(pt)
696
+ stratum_pt_renum = mesh.points.default_to_applied_component_number(
697
+ stratum, stratum_pt
698
+ )
699
+ if stratum.label == mesh.vert_label:
700
+ facet_verts[ptr] = stratum_pt_renum
701
+ ptr += 1
702
+
703
+ # Find the non-incident vertex
704
+ for vi in range (nverts_per_cell):
705
+ incident = False
706
+ for vj in range (nverts_per_cell- 1 ):
707
+ if facet_verts[vj] == closure_data[0 ][cell, vi]:
708
+ incident = True
733
709
break
734
- # Only one non-incident vertex per facet, so
735
- # local facet no. = non-incident vertex no.
736
- if incident == 0 :
737
- cell_closure[ cell,offset + v ] = facets[f]
710
+ # Only one non-incident vertex per facet, so the local facet
711
+ # number is the same as the non-incident vertex number
712
+ if not incident :
713
+ closure_data_reord[tdim - 1 ][ cell, vi ] = facet
738
714
break
739
715
740
- offset += nfacets
716
+ # 4. And finally the cell
717
+ assert closure_sizes[tdim] == 1
718
+ closure_data_reord[tdim][cell] = closure_data[tdim][cell]
741
719
742
- CHKERR(PetscFree(vertices))
743
- CHKERR(PetscFree(v_global))
720
+ # Cleanup
721
+ CHKERR(PetscFree(verts))
722
+ CHKERR(PetscFree(edges))
744
723
CHKERR(PetscFree(facets))
745
- CHKERR(PetscFree(facet_vertices))
746
- CHKERR(PetscFree(faces))
747
- CHKERR(PetscFree(face_indices))
748
-
749
- return cell_closure
724
+ CHKERR(PetscFree(global_verts))
725
+ CHKERR(PetscFree(edge_verts))
726
+ CHKERR(PetscFree(edge_incident_verts))
727
+ CHKERR(PetscFree(facet_verts))
728
+ if facet_closure != NULL :
729
+ restore_transitive_closure(dm.dm, 0 , PETSC_TRUE, & nfacet_closure, & facet_closure)
730
+
731
+ return closure_data_reord
750
732
751
733
752
734
@ cython.boundscheck (False )
0 commit comments