xref: /petsc/src/binding/petsc4py/test/test_dmplex.py (revision 62ed42821f84f33353546905c9271ed730d39ff0)
1728cfed7Sksagiyamimport petsc4py
25808f684SSatish Balayfrom petsc4py import PETSc
35808f684SSatish Balayimport unittest
4728cfed7Sksagiyamimport os
5728cfed7Sksagiyamimport filecmp
65808f684SSatish Balayimport numpy as np
76f336411SStefano Zampiniimport importlib
85808f684SSatish Balay
95808f684SSatish Balay# --------------------------------------------------------------------
105808f684SSatish Balay
11e77db20cSJoe WallworkERR_ARG_OUTOFRANGE = 63
125808f684SSatish Balay
135808f684SSatish Balay
146f336411SStefano Zampiniclass BaseTestPlex:
155808f684SSatish Balay    COMM = PETSc.COMM_WORLD
165808f684SSatish Balay    DIM = 1
175808f684SSatish Balay    CELLS = [[0, 1], [1, 2]]
186f336411SStefano Zampini    COORDS = [[0.0], [0.5], [1.0]]
195808f684SSatish Balay    COMP = 1
205808f684SSatish Balay    DOFS = [1, 0]
215808f684SSatish Balay
225808f684SSatish Balay    def setUp(self):
236f336411SStefano Zampini        self.plex = PETSc.DMPlex().createFromCellList(
246f336411SStefano Zampini            self.DIM, self.CELLS, self.COORDS, comm=self.COMM
256f336411SStefano Zampini        )
265808f684SSatish Balay
275808f684SSatish Balay    def tearDown(self):
285808f684SSatish Balay        self.plex.destroy()
295808f684SSatish Balay        self.plex = None
3062e5d2d2SJDBetteridge        PETSc.garbage_cleanup()
315808f684SSatish Balay
325808f684SSatish Balay    def testTopology(self):
333df08285SMatthew G. Knepley        rank = self.COMM.rank
345808f684SSatish Balay        dim = self.plex.getDimension()
355808f684SSatish Balay        pStart, pEnd = self.plex.getChart()
365808f684SSatish Balay        cStart, cEnd = self.plex.getHeightStratum(0)
375808f684SSatish Balay        vStart, vEnd = self.plex.getDepthStratum(0)
386f336411SStefano Zampini        numDepths = self.plex.getLabelSize('depth')
395808f684SSatish Balay        coords_raw = self.plex.getCoordinates().getArray()
405808f684SSatish Balay        coords = np.reshape(coords_raw, (vEnd - vStart, dim))
415808f684SSatish Balay        self.assertEqual(dim, self.DIM)
425808f684SSatish Balay        self.assertEqual(numDepths, self.DIM + 1)
433df08285SMatthew G. Knepley        if rank == 0 and self.CELLS is not None:
445808f684SSatish Balay            self.assertEqual(cEnd - cStart, len(self.CELLS))
453df08285SMatthew G. Knepley        if rank == 0 and self.COORDS is not None:
465808f684SSatish Balay            self.assertEqual(vEnd - vStart, len(self.COORDS))
475808f684SSatish Balay            self.assertTrue((coords == self.COORDS).all())
485808f684SSatish Balay
495808f684SSatish Balay    def testClosure(self):
505808f684SSatish Balay        pStart, pEnd = self.plex.getChart()
515808f684SSatish Balay        for p in range(pStart, pEnd):
525808f684SSatish Balay            closure = self.plex.getTransitiveClosure(p)[0]
535808f684SSatish Balay            for c in closure:
545808f684SSatish Balay                cone = self.plex.getCone(c)
555808f684SSatish Balay                self.assertEqual(self.plex.getConeSize(c), len(cone))
565808f684SSatish Balay                for i in cone:
575808f684SSatish Balay                    self.assertIn(i, closure)
585808f684SSatish Balay            star = self.plex.getTransitiveClosure(p, useCone=False)[0]
595808f684SSatish Balay            for s in star:
605808f684SSatish Balay                support = self.plex.getSupport(s)
615808f684SSatish Balay                self.assertEqual(self.plex.getSupportSize(s), len(support))
625808f684SSatish Balay                for i in support:
635808f684SSatish Balay                    self.assertIn(i, star)
645808f684SSatish Balay
655808f684SSatish Balay    def testAdjacency(self):
665808f684SSatish Balay        PETSc.DMPlex.setAdjacencyUseAnchors(self.plex, False)
675808f684SSatish Balay        flag = PETSc.DMPlex.getAdjacencyUseAnchors(self.plex)
685808f684SSatish Balay        self.assertFalse(flag)
695808f684SSatish Balay        PETSc.DMPlex.setAdjacencyUseAnchors(self.plex, True)
705808f684SSatish Balay        flag = PETSc.DMPlex.getAdjacencyUseAnchors(self.plex)
715808f684SSatish Balay        self.assertTrue(flag)
725808f684SSatish Balay        PETSc.DMPlex.setBasicAdjacency(self.plex, False, False)
735808f684SSatish Balay        flagA, flagB = PETSc.DMPlex.getBasicAdjacency(self.plex)
745808f684SSatish Balay        self.assertFalse(flagA)
755808f684SSatish Balay        self.assertFalse(flagB)
765808f684SSatish Balay        PETSc.DMPlex.setBasicAdjacency(self.plex, True, True)
775808f684SSatish Balay        flagA, flagB = PETSc.DMPlex.getBasicAdjacency(self.plex)
785808f684SSatish Balay        self.assertTrue(flagA)
795808f684SSatish Balay        self.assertTrue(flagB)
805808f684SSatish Balay        pStart, pEnd = self.plex.getChart()
815808f684SSatish Balay        for p in range(pStart, pEnd):
825808f684SSatish Balay            adjacency = self.plex.getAdjacency(p)
835808f684SSatish Balay            self.assertTrue(p in adjacency)
845808f684SSatish Balay            self.assertTrue(len(adjacency) > 1)
855808f684SSatish Balay
865808f684SSatish Balay    def testSectionDofs(self):
875808f684SSatish Balay        self.plex.setNumFields(1)
885808f684SSatish Balay        section = self.plex.createSection([self.COMP], [self.DOFS])
895808f684SSatish Balay        size = section.getStorageSize()
906f336411SStefano Zampini        entity_dofs = [
916f336411SStefano Zampini            self.plex.getStratumSize('depth', d) * self.DOFS[d]
926f336411SStefano Zampini            for d in range(self.DIM + 1)
936f336411SStefano Zampini        ]
945808f684SSatish Balay        self.assertEqual(sum(entity_dofs), size)
955808f684SSatish Balay
965808f684SSatish Balay    def testSectionClosure(self):
975808f684SSatish Balay        section = self.plex.createSection([self.COMP], [self.DOFS])
985808f684SSatish Balay        self.plex.setSection(section)
995808f684SSatish Balay        vec = self.plex.createLocalVec()
1005808f684SSatish Balay        pStart, pEnd = self.plex.getChart()
1015808f684SSatish Balay        for p in range(pStart, pEnd):
1025808f684SSatish Balay            for i in range(section.getDof(p)):
1035808f684SSatish Balay                off = section.getOffset(p)
1045808f684SSatish Balay                vec.setValue(off + i, p)
1055808f684SSatish Balay
1065808f684SSatish Balay        for p in range(pStart, pEnd):
1075808f684SSatish Balay            point_closure = self.plex.getTransitiveClosure(p)[0]
1085808f684SSatish Balay            dof_closure = self.plex.vecGetClosure(section, vec, p)
1095808f684SSatish Balay            for p in dof_closure:
1105808f684SSatish Balay                self.assertIn(p, point_closure)
1115808f684SSatish Balay
1125808f684SSatish Balay    def testBoundaryLabel(self):
113439f958dSVaclav Hapla        pStart, pEnd = self.plex.getChart()
1146f336411SStefano Zampini        if pEnd - pStart == 0:
1156f336411SStefano Zampini            return
116439f958dSVaclav Hapla
1176f336411SStefano Zampini        self.assertFalse(self.plex.hasLabel('boundary'))
1186f336411SStefano Zampini        self.plex.markBoundaryFaces('boundary')
1196f336411SStefano Zampini        self.assertTrue(self.plex.hasLabel('boundary'))
1205808f684SSatish Balay
1216f336411SStefano Zampini        faces = self.plex.getStratumIS('boundary', 1)
1225808f684SSatish Balay        for f in faces.getIndices():
1235808f684SSatish Balay            points, orient = self.plex.getTransitiveClosure(f, useCone=True)
1245808f684SSatish Balay            for p in points:
1256f336411SStefano Zampini                self.plex.setLabelValue('boundary', p, 1)
1265808f684SSatish Balay
1275808f684SSatish Balay        for p in range(pStart, pEnd):
1286f336411SStefano Zampini            if self.plex.getLabelValue('boundary', p) != 1:
1296f336411SStefano Zampini                self.plex.setLabelValue('boundary', p, 2)
1305808f684SSatish Balay
1316f336411SStefano Zampini        numBoundary = self.plex.getStratumSize('boundary', 1)
1326f336411SStefano Zampini        numInterior = self.plex.getStratumSize('boundary', 2)
1335808f684SSatish Balay        self.assertNotEqual(numBoundary, pEnd - pStart)
1345808f684SSatish Balay        self.assertNotEqual(numInterior, pEnd - pStart)
1355808f684SSatish Balay        self.assertEqual(numBoundary + numInterior, pEnd - pStart)
1365808f684SSatish Balay
137*71f1c950SStefano Zampini    def testLocalSubmesh(self):
138*71f1c950SStefano Zampini        for ovl in [0, 1, 2]:
139*71f1c950SStefano Zampini            plex = self.plex.refine()
140*71f1c950SStefano Zampini            sf = plex.distribute(overlap=ovl)
141*71f1c950SStefano Zampini            if sf:
142*71f1c950SStefano Zampini                sf.destroy()
143*71f1c950SStefano Zampini            gis = plex.getCellNumbering()
144*71f1c950SStefano Zampini
145*71f1c950SStefano Zampini            for ignore in [True, False]:
146*71f1c950SStefano Zampini                locplex, _ = plex.filter(comm=PETSc.COMM_SELF, ignoreHalo=ignore)
147*71f1c950SStefano Zampini                lis = locplex.getCellNumbering()
148*71f1c950SStefano Zampini                if ignore:
149*71f1c950SStefano Zampini                    self.assertEqual(
150*71f1c950SStefano Zampini                        lis.getLocalSize(), len(np.where(gis.getIndices() > -1)[0])
151*71f1c950SStefano Zampini                    )
152*71f1c950SStefano Zampini                else:
153*71f1c950SStefano Zampini                    self.assertEqual(lis.getLocalSize(), gis.getLocalSize())
154*71f1c950SStefano Zampini                lis.destroy()
155*71f1c950SStefano Zampini                locplex.destroy()
156*71f1c950SStefano Zampini            gis.destroy()
157*71f1c950SStefano Zampini            plex.destroy()
158*71f1c950SStefano Zampini
159d6a8d7c6SJoe Wallwork    def testMetric(self):
1606f336411SStefano Zampini        if self.DIM == 1:
1616f336411SStefano Zampini            return
162d6a8d7c6SJoe Wallwork        self.plex.distribute()
1636f336411SStefano Zampini        if self.CELLS is None and not self.plex.isSimplex():
1646f336411SStefano Zampini            return
165b59e092eSJoe Wallwork        self.plex.orient()
166d6a8d7c6SJoe Wallwork
167d6a8d7c6SJoe Wallwork        h_min = 1.0e-30
1686f336411SStefano Zampini        h_max = 1.0e30
1696f336411SStefano Zampini        a_max = 1.0e10
1705d6e921eSJoe Wallwork        target = 8.0
171d6a8d7c6SJoe Wallwork        p = 1.0
172358f35a7SJoe Wallwork        beta = 1.3
173a5745b59SJoe Wallwork        hausd = 0.01
1740e99b0e2SJoe Wallwork        self.plex.metricSetUniform(False)
175d6a8d7c6SJoe Wallwork        self.plex.metricSetIsotropic(False)
176d6a8d7c6SJoe Wallwork        self.plex.metricSetRestrictAnisotropyFirst(False)
177358f35a7SJoe Wallwork        self.plex.metricSetNoInsertion(False)
178358f35a7SJoe Wallwork        self.plex.metricSetNoSwapping(False)
179358f35a7SJoe Wallwork        self.plex.metricSetNoMovement(False)
1808d4b236aSJoe Wallwork        self.plex.metricSetNoSurf(False)
181358f35a7SJoe Wallwork        self.plex.metricSetVerbosity(-1)
182358f35a7SJoe Wallwork        self.plex.metricSetNumIterations(3)
183d6a8d7c6SJoe Wallwork        self.plex.metricSetMinimumMagnitude(h_min)
184d6a8d7c6SJoe Wallwork        self.plex.metricSetMaximumMagnitude(h_max)
185d6a8d7c6SJoe Wallwork        self.plex.metricSetMaximumAnisotropy(a_max)
186d6a8d7c6SJoe Wallwork        self.plex.metricSetTargetComplexity(target)
187d6a8d7c6SJoe Wallwork        self.plex.metricSetNormalizationOrder(p)
188358f35a7SJoe Wallwork        self.plex.metricSetGradationFactor(beta)
189a5745b59SJoe Wallwork        self.plex.metricSetHausdorffNumber(hausd)
190d6a8d7c6SJoe Wallwork
1910e99b0e2SJoe Wallwork        self.assertFalse(self.plex.metricIsUniform())
192d6a8d7c6SJoe Wallwork        self.assertFalse(self.plex.metricIsIsotropic())
193d6a8d7c6SJoe Wallwork        self.assertFalse(self.plex.metricRestrictAnisotropyFirst())
194358f35a7SJoe Wallwork        self.assertFalse(self.plex.metricNoInsertion())
195358f35a7SJoe Wallwork        self.assertFalse(self.plex.metricNoSwapping())
196358f35a7SJoe Wallwork        self.assertFalse(self.plex.metricNoMovement())
1978d4b236aSJoe Wallwork        self.assertFalse(self.plex.metricNoSurf())
1986f336411SStefano Zampini        self.assertTrue(self.plex.metricGetVerbosity() == -1)
1996f336411SStefano Zampini        self.assertTrue(self.plex.metricGetNumIterations() == 3)
2006f336411SStefano Zampini        self.assertTrue(np.isclose(self.plex.metricGetMinimumMagnitude(), h_min))
2016f336411SStefano Zampini        self.assertTrue(np.isclose(self.plex.metricGetMaximumMagnitude(), h_max))
2026f336411SStefano Zampini        self.assertTrue(np.isclose(self.plex.metricGetMaximumAnisotropy(), a_max))
2036f336411SStefano Zampini        self.assertTrue(np.isclose(self.plex.metricGetTargetComplexity(), target))
2046f336411SStefano Zampini        self.assertTrue(np.isclose(self.plex.metricGetNormalizationOrder(), p))
2056f336411SStefano Zampini        self.assertTrue(np.isclose(self.plex.metricGetGradationFactor(), beta))
2066f336411SStefano Zampini        self.assertTrue(np.isclose(self.plex.metricGetHausdorffNumber(), hausd))
207d6a8d7c6SJoe Wallwork
2085d6e921eSJoe Wallwork        metric1 = self.plex.metricCreateUniform(0.5)
2095d6e921eSJoe Wallwork        metric2 = self.plex.metricCreateUniform(1.0)
2105d6e921eSJoe Wallwork        metric = self.plex.metricCreate()
2115d6e921eSJoe Wallwork        det = self.plex.metricDeterminantCreate()
2125d6e921eSJoe Wallwork        self.plex.metricAverage2(metric1, metric2, metric)
2135d6e921eSJoe Wallwork        metric1.array[:] *= 1.5
2146f336411SStefano Zampini        self.assertTrue(np.allclose(metric.array, metric1.array))
2155d6e921eSJoe Wallwork        self.plex.metricIntersection2(metric1, metric2, metric)
2166f336411SStefano Zampini        self.assertTrue(np.allclose(metric.array, metric2.array))
21755a74a43SLisandro Dalcin        self.plex.metricEnforceSPD(metric, metric1, det[0])
2186f336411SStefano Zampini        self.assertTrue(np.allclose(metric.array, metric1.array))
2196f336411SStefano Zampini
2206f336411SStefano Zampini        if self.DIM == 2 and PETSc.COMM_WORLD.getSize() > 6:
2216f336411SStefano Zampini            # Error with 7 processes in 2D: normalization factor is -1
2226f336411SStefano Zampini            return
2236f336411SStefano Zampini
2246f336411SStefano Zampini        self.plex.metricNormalize(
2256f336411SStefano Zampini            metric, metric1, det[0], restrictSizes=False, restrictAnisotropy=False
2266f336411SStefano Zampini        )
2275d6e921eSJoe Wallwork        metric2.scale(pow(target, 2.0 / self.DIM))
2286f336411SStefano Zampini        self.assertTrue(np.allclose(metric1.array, metric2.array))
2295808f684SSatish Balay
2305808f684SSatish Balay    def testAdapt(self):
2316f336411SStefano Zampini        if self.DIM == 1:
2326f336411SStefano Zampini            return
2336f336411SStefano Zampini        if self.DIM == 3 and PETSc.COMM_WORLD.getSize() > 4:
2346f336411SStefano Zampini            # Error with 5 processes in 3D
2356f336411SStefano Zampini            # ----------------------------
2366f336411SStefano Zampini            # Warning: MMG5_mmgIntextmet: Unable to diagonalize at least 1 metric.
2376f336411SStefano Zampini            # Error: MMG3D_defsiz_ani: unable to intersect metrics at point 8.
2386f336411SStefano Zampini            # Metric undefined. Exit program.
2396f336411SStefano Zampini            # MMG remeshing problem. Exit program.
2406f336411SStefano Zampini            return
241d03c5e66SJoe Wallwork        self.plex.orient()
242d03c5e66SJoe Wallwork        plex = self.plex.refine()
243d03c5e66SJoe Wallwork        plex.distribute()
2446f336411SStefano Zampini        if self.CELLS is None and not plex.isSimplex():
2456f336411SStefano Zampini            return
2466f336411SStefano Zampini        if sum(self.DOFS) > 1:
2476f336411SStefano Zampini            return
248d03c5e66SJoe Wallwork        metric = plex.metricCreateUniform(9.0)
2495808f684SSatish Balay        try:
2506f336411SStefano Zampini            newplex = plex.adaptMetric(metric, '')
251afa732d8SStefano Zampini            plex.destroy()
2526f336411SStefano Zampini            newplex.destroy()
2535808f684SSatish Balay        except PETSc.Error as exc:
254afa732d8SStefano Zampini            plex.destroy()
2556f336411SStefano Zampini            if exc.ierr != ERR_ARG_OUTOFRANGE:
2566f336411SStefano Zampini                raise
2575808f684SSatish Balay
258c039638dSMatthew G. Knepley    def testNatural(self):
259c039638dSMatthew G. Knepley        dim = self.plex.getDimension()
260c039638dSMatthew G. Knepley        ct = self.plex.getCellType(0)
261c039638dSMatthew G. Knepley        fe = PETSc.FE().createByCell(dim, 1, ct)
262c039638dSMatthew G. Knepley        self.plex.setField(0, fe)
263c039638dSMatthew G. Knepley        self.plex.createDS()
264c039638dSMatthew G. Knepley        self.plex.setUseNatural(True)
265c039638dSMatthew G. Knepley        self.plex.distribute()
266c039638dSMatthew G. Knepley        self.plex.view()
267c039638dSMatthew G. Knepley        gv = self.plex.createGlobalVec()
268c039638dSMatthew G. Knepley        nv = self.plex.createNaturalVec()
269c039638dSMatthew G. Knepley        self.plex.globalToNaturalBegin(gv, nv)
270c039638dSMatthew G. Knepley        self.plex.globalToNaturalEnd(gv, nv)
271c039638dSMatthew G. Knepley        self.plex.naturalToGlobalBegin(nv, gv)
272c039638dSMatthew G. Knepley        self.plex.naturalToGlobalEnd(nv, gv)
2735808f684SSatish Balay
2745808f684SSatish Balay# --------------------------------------------------------------------
2755808f684SSatish Balay
2766f336411SStefano Zampini
2775808f684SSatish Balayclass BaseTestPlex_2D(BaseTestPlex):
2785808f684SSatish Balay    DIM = 2
2796f336411SStefano Zampini    CELLS = [
2806f336411SStefano Zampini        [0, 1, 3],
2816f336411SStefano Zampini        [1, 3, 4],
2826f336411SStefano Zampini        [1, 2, 4],
2836f336411SStefano Zampini        [2, 4, 5],
2846f336411SStefano Zampini        [3, 4, 6],
2856f336411SStefano Zampini        [4, 6, 7],
2866f336411SStefano Zampini        [4, 5, 7],
2876f336411SStefano Zampini        [5, 7, 8],
2886f336411SStefano Zampini    ]
2896f336411SStefano Zampini    COORDS = [
2906f336411SStefano Zampini        [0.0, 0.0],
2916f336411SStefano Zampini        [0.5, 0.0],
2926f336411SStefano Zampini        [1.0, 0.0],
2936f336411SStefano Zampini        [0.0, 0.5],
2946f336411SStefano Zampini        [0.5, 0.5],
2956f336411SStefano Zampini        [1.0, 0.5],
2966f336411SStefano Zampini        [0.0, 1.0],
2976f336411SStefano Zampini        [0.5, 1.0],
2986f336411SStefano Zampini        [1.0, 1.0],
2996f336411SStefano Zampini    ]
3005808f684SSatish Balay    DOFS = [1, 0, 0]
3015808f684SSatish Balay
3026f336411SStefano Zampini
3035808f684SSatish Balayclass BaseTestPlex_3D(BaseTestPlex):
3045808f684SSatish Balay    DIM = 3
3056f336411SStefano Zampini    CELLS = [
3066f336411SStefano Zampini        [0, 2, 3, 7],
3076f336411SStefano Zampini        [0, 2, 6, 7],
3086f336411SStefano Zampini        [0, 4, 6, 7],
3096f336411SStefano Zampini        [0, 1, 3, 7],
3106f336411SStefano Zampini        [0, 1, 5, 7],
3116f336411SStefano Zampini        [0, 4, 5, 7],
3126f336411SStefano Zampini    ]
3136f336411SStefano Zampini    COORDS = [
3146f336411SStefano Zampini        [0.0, 0.0, 0.0],
3156f336411SStefano Zampini        [1.0, 0.0, 0.0],
3166f336411SStefano Zampini        [0.0, 1.0, 0.0],
3176f336411SStefano Zampini        [1.0, 1.0, 0.0],
3186f336411SStefano Zampini        [0.0, 0.0, 1.0],
3196f336411SStefano Zampini        [1.0, 0.0, 1.0],
3206f336411SStefano Zampini        [0.0, 1.0, 1.0],
3216f336411SStefano Zampini        [1.0, 1.0, 1.0],
3226f336411SStefano Zampini    ]
3235808f684SSatish Balay    DOFS = [1, 0, 0, 0]
3245808f684SSatish Balay
3256f336411SStefano Zampini
3265808f684SSatish Balay# --------------------------------------------------------------------
3275808f684SSatish Balay
3286f336411SStefano Zampini
3295808f684SSatish Balayclass TestPlex_1D(BaseTestPlex, unittest.TestCase):
3305808f684SSatish Balay    pass
3315808f684SSatish Balay
3324aa747acSUmberto Zerbinati
3336f336411SStefano Zampiniclass TestPlex_2D(BaseTestPlex_2D, unittest.TestCase):
3344aa747acSUmberto Zerbinati    def testTransform(self):
3354aa747acSUmberto Zerbinati        plex = self.plex
3364aa747acSUmberto Zerbinati        cstart, cend = plex.getHeightStratum(0)
3374aa747acSUmberto Zerbinati        tr = PETSc.DMPlexTransform().create(comm=PETSc.COMM_WORLD)
3384aa747acSUmberto Zerbinati        tr.setType(PETSc.DMPlexTransformType.REFINEALFELD)
3394aa747acSUmberto Zerbinati        tr.setDM(plex)
3404aa747acSUmberto Zerbinati        tr.setUp()
3414aa747acSUmberto Zerbinati        newplex = tr.apply(plex)
3424aa747acSUmberto Zerbinati        tr.destroy()
3434aa747acSUmberto Zerbinati        newcstart, newcend = newplex.getHeightStratum(0)
3444aa747acSUmberto Zerbinati        newplex.destroy()
3454aa747acSUmberto Zerbinati        self.assertTrue((newcend - newcstart) == 3 * (cend - cstart))
3465808f684SSatish Balay
3476f336411SStefano Zampini
3485808f684SSatish Balayclass TestPlex_3D(BaseTestPlex_3D, unittest.TestCase):
3495808f684SSatish Balay    pass
3505808f684SSatish Balay
3516f336411SStefano Zampini
3525808f684SSatish Balayclass TestPlex_2D_P3(BaseTestPlex_2D, unittest.TestCase):
3535808f684SSatish Balay    DOFS = [1, 2, 1]
3545808f684SSatish Balay
3556f336411SStefano Zampini
3565808f684SSatish Balayclass TestPlex_3D_P3(BaseTestPlex_3D, unittest.TestCase):
3575808f684SSatish Balay    DOFS = [1, 2, 1, 0]
3585808f684SSatish Balay
3596f336411SStefano Zampini
3605808f684SSatish Balayclass TestPlex_3D_P4(BaseTestPlex_3D, unittest.TestCase):
3615808f684SSatish Balay    DOFS = [1, 3, 3, 1]
3625808f684SSatish Balay
3636f336411SStefano Zampini
3645808f684SSatish Balayclass TestPlex_2D_BoxTensor(BaseTestPlex_2D, unittest.TestCase):
3655808f684SSatish Balay    CELLS = None
3665808f684SSatish Balay    COORDS = None
3676f336411SStefano Zampini
3685808f684SSatish Balay    def setUp(self):
3695808f684SSatish Balay        self.plex = PETSc.DMPlex().createBoxMesh([3, 3], simplex=False)
3705808f684SSatish Balay
3716f336411SStefano Zampini
3725808f684SSatish Balayclass TestPlex_3D_BoxTensor(BaseTestPlex_3D, unittest.TestCase):
3735808f684SSatish Balay    CELLS = None
3745808f684SSatish Balay    COORDS = None
3756f336411SStefano Zampini
3765808f684SSatish Balay    def setUp(self):
3775808f684SSatish Balay        self.plex = PETSc.DMPlex().createBoxMesh([3, 3, 3], simplex=False)
3785808f684SSatish Balay
3796f336411SStefano Zampini
3806f336411SStefano Zampini# FIXME
3815808f684SSatish Balaytry:
3825808f684SSatish Balay    raise PETSc.Error
3835808f684SSatish Balay    PETSc.DMPlex().createBoxMesh([2, 2], simplex=True, comm=PETSc.COMM_SELF).destroy()
3845808f684SSatish Balayexcept PETSc.Error:
3855808f684SSatish Balay    pass
3865808f684SSatish Balayelse:
3876f336411SStefano Zampini
3885808f684SSatish Balay    class TestPlex_2D_Box(BaseTestPlex_2D, unittest.TestCase):
3895808f684SSatish Balay        CELLS = None
3905808f684SSatish Balay        COORDS = None
3916f336411SStefano Zampini
3925808f684SSatish Balay        def setUp(self):
3935808f684SSatish Balay            self.plex = PETSc.DMPlex().createBoxMesh([1, 1], simplex=True)
3945808f684SSatish Balay
3955808f684SSatish Balay    class TestPlex_2D_Boundary(BaseTestPlex_2D, unittest.TestCase):
3965808f684SSatish Balay        CELLS = None
3975808f684SSatish Balay        COORDS = None
3986f336411SStefano Zampini
3995808f684SSatish Balay        def setUp(self):
4005808f684SSatish Balay            boundary = PETSc.DMPlex().create(self.COMM)
4016f336411SStefano Zampini            boundary.createSquareBoundary([0.0, 0.0], [1.0, 1.0], [2, 2])
4025808f684SSatish Balay            boundary.setDimension(self.DIM - 1)
4035808f684SSatish Balay            self.plex = PETSc.DMPlex().generate(boundary)
4045808f684SSatish Balay
4055808f684SSatish Balay    class TestPlex_3D_Box(BaseTestPlex_3D, unittest.TestCase):
4065808f684SSatish Balay        CELLS = None
4075808f684SSatish Balay        COORDS = None
4086f336411SStefano Zampini
4095808f684SSatish Balay        def setUp(self):
4105808f684SSatish Balay            self.plex = PETSc.DMPlex().createBoxMesh([1, 1, 1], simplex=True)
4115808f684SSatish Balay
4125808f684SSatish Balay    class TestPlex_3D_Boundary(BaseTestPlex_3D, unittest.TestCase):
4135808f684SSatish Balay        CELLS = None
4145808f684SSatish Balay        COORDS = None
4156f336411SStefano Zampini
4165808f684SSatish Balay        def setUp(self):
4175808f684SSatish Balay            boundary = PETSc.DMPlex().create(self.COMM)
4186f336411SStefano Zampini            boundary.createCubeBoundary([0.0, 0.0, 0.0], [1.0, 1.0, 1.0], [1, 1, 1])
4195808f684SSatish Balay            boundary.setDimension(self.DIM - 1)
4205808f684SSatish Balay            self.plex = PETSc.DMPlex().generate(boundary)
4215808f684SSatish Balay
4225808f684SSatish Balay# --------------------------------------------------------------------
4235808f684SSatish Balay
424728cfed7SksagiyamPETSC_DIR = petsc4py.get_config()['PETSC_DIR']
425728cfed7Sksagiyam
4266f336411SStefano Zampini
427728cfed7Sksagiyamdef check_dtype(method):
428728cfed7Sksagiyam    def wrapper(self, *args, **kwargs):
429728cfed7Sksagiyam        if PETSc.ScalarType is PETSc.ComplexType:
4306f336411SStefano Zampini            return None
431728cfed7Sksagiyam        return method(self, *args, **kwargs)
4326f336411SStefano Zampini
433728cfed7Sksagiyam    return wrapper
434728cfed7Sksagiyam
4356f336411SStefano Zampini
436728cfed7Sksagiyamdef check_package(method):
437728cfed7Sksagiyam    def wrapper(self, *args, **kwargs):
4386f336411SStefano Zampini        if not PETSc.Sys.hasExternalPackage('hdf5'):
4396f336411SStefano Zampini            return None
4406f336411SStefano Zampini        if self.PARTITIONERTYPE != 'simple' and not PETSc.Sys.hasExternalPackage(
4416f336411SStefano Zampini            self.PARTITIONERTYPE
4426f336411SStefano Zampini        ):
4436f336411SStefano Zampini            return None
444728cfed7Sksagiyam        return method(self, *args, **kwargs)
4456f336411SStefano Zampini
446728cfed7Sksagiyam    return wrapper
447728cfed7Sksagiyam
4486f336411SStefano Zampini
449728cfed7Sksagiyamdef check_nsize(method):
450728cfed7Sksagiyam    def wrapper(self, *args, **kwargs):
451728cfed7Sksagiyam        if PETSc.COMM_WORLD.size != self.NSIZE:
4526f336411SStefano Zampini            return None
453728cfed7Sksagiyam        return method(self, *args, **kwargs)
4546f336411SStefano Zampini
455728cfed7Sksagiyam    return wrapper
456728cfed7Sksagiyam
4576f336411SStefano Zampini
4586f336411SStefano Zampiniclass BaseTestPlexHDF5:
459728cfed7Sksagiyam    NSIZE = 4
460728cfed7Sksagiyam    NTIMES = 3
461728cfed7Sksagiyam
462728cfed7Sksagiyam    def tearDown(self):
463728cfed7Sksagiyam        if not PETSc.COMM_WORLD.rank:
464728cfed7Sksagiyam            if os.path.exists(self.outfile()):
465728cfed7Sksagiyam                os.remove(self.outfile())
466728cfed7Sksagiyam            if os.path.exists(self.tmp_output_file()):
467728cfed7Sksagiyam                os.remove(self.tmp_output_file())
468728cfed7Sksagiyam
469728cfed7Sksagiyam    def _name(self):
4706f336411SStefano Zampini        return f'{self.SUFFIX}_outformat-{self.OUTFORMAT}_{self.PARTITIONERTYPE}'
471728cfed7Sksagiyam
472728cfed7Sksagiyam    def infile(self):
4736f336411SStefano Zampini        return os.path.join(
4746f336411SStefano Zampini            PETSC_DIR, 'share/petsc/datafiles/', 'meshes/blockcylinder-50.h5'
4756f336411SStefano Zampini        )
476728cfed7Sksagiyam
477728cfed7Sksagiyam    def outfile(self):
4786f336411SStefano Zampini        return os.path.join('./temp_test_dmplex_%s.h5' % self._name())
479728cfed7Sksagiyam
480728cfed7Sksagiyam    def informat(self):
481728cfed7Sksagiyam        return PETSc.Viewer.Format.HDF5_XDMF
482728cfed7Sksagiyam
483728cfed7Sksagiyam    def outformat(self):
4846f336411SStefano Zampini        d = {
4856f336411SStefano Zampini            'hdf5_petsc': PETSc.Viewer.Format.HDF5_PETSC,
4866f336411SStefano Zampini            'hdf5_xdmf': PETSc.Viewer.Format.HDF5_XDMF,
4876f336411SStefano Zampini        }
488728cfed7Sksagiyam        return d[self.OUTFORMAT]
489728cfed7Sksagiyam
490728cfed7Sksagiyam    def partitionerType(self):
4916f336411SStefano Zampini        d = {
4926f336411SStefano Zampini            'simple': PETSc.Partitioner.Type.SIMPLE,
4936f336411SStefano Zampini            'ptscotch': PETSc.Partitioner.Type.PTSCOTCH,
4946f336411SStefano Zampini            'parmetis': PETSc.Partitioner.Type.PARMETIS,
4956f336411SStefano Zampini        }
496728cfed7Sksagiyam        return d[self.PARTITIONERTYPE]
497728cfed7Sksagiyam
498728cfed7Sksagiyam    def ref_output_file(self):
4996f336411SStefano Zampini        return os.path.join(
5006f336411SStefano Zampini            PETSC_DIR,
5016f336411SStefano Zampini            'src/dm/impls/plex/tutorials/',
5026f336411SStefano Zampini            'output/ex5_%s.out' % self._name(),
5036f336411SStefano Zampini        )
504728cfed7Sksagiyam
505728cfed7Sksagiyam    def tmp_output_file(self):
5066f336411SStefano Zampini        return os.path.join('./temp_test_dmplex_%s.out' % self._name())
507728cfed7Sksagiyam
508728cfed7Sksagiyam    def outputText(self, msg, comm):
509728cfed7Sksagiyam        if not comm.rank:
510728cfed7Sksagiyam            with open(self.tmp_output_file(), 'a') as f:
511728cfed7Sksagiyam                f.write(msg)
512728cfed7Sksagiyam
513728cfed7Sksagiyam    def outputPlex(self, plex):
514afa732d8SStefano Zampini        txtvwr = PETSc.Viewer().createASCII(
515afa732d8SStefano Zampini            self.tmp_output_file(), mode='a', comm=plex.comm
516afa732d8SStefano Zampini        )
517afa732d8SStefano Zampini        plex.view(viewer=txtvwr)
518afa732d8SStefano Zampini        txtvwr.destroy()
519728cfed7Sksagiyam
520728cfed7Sksagiyam    @check_dtype
521728cfed7Sksagiyam    @check_package
522728cfed7Sksagiyam    @check_nsize
523728cfed7Sksagiyam    def testViewLoadCycle(self):
524afa732d8SStefano Zampini        if importlib.util.find_spec('mpi4py') is None:
525afa732d8SStefano Zampini            self.skipTest('mpi4py')  # throws special exception to signal test skip
526728cfed7Sksagiyam        grank = PETSc.COMM_WORLD.rank
527728cfed7Sksagiyam        for i in range(self.NTIMES):
528728cfed7Sksagiyam            if i == 0:
529728cfed7Sksagiyam                infname = self.infile()
530728cfed7Sksagiyam                informt = self.informat()
531728cfed7Sksagiyam            else:
532728cfed7Sksagiyam                infname = self.outfile()
533728cfed7Sksagiyam                informt = self.outformat()
534728cfed7Sksagiyam            if self.HETEROGENEOUS:
5356f336411SStefano Zampini                mycolor = grank > self.NTIMES - i
536728cfed7Sksagiyam            else:
537728cfed7Sksagiyam                mycolor = 0
538728cfed7Sksagiyam            mpicomm = PETSc.COMM_WORLD.tompi4py()
539728cfed7Sksagiyam            comm = PETSc.Comm(comm=mpicomm.Split(color=mycolor, key=grank))
540728cfed7Sksagiyam            if mycolor == 0:
5416f336411SStefano Zampini                self.outputText('Begin cycle %d\n' % i, comm)
542728cfed7Sksagiyam                plex = PETSc.DMPlex()
543728cfed7Sksagiyam                vwr = PETSc.ViewerHDF5()
544728cfed7Sksagiyam                # Create plex
545728cfed7Sksagiyam                plex.create(comm=comm)
5466f336411SStefano Zampini                plex.setName('DMPlex Object')
547728cfed7Sksagiyam                # Load data from XDMF into dm in parallel
548728cfed7Sksagiyam                vwr.create(infname, mode='r', comm=comm)
549728cfed7Sksagiyam                vwr.pushFormat(format=informt)
550728cfed7Sksagiyam                plex.load(viewer=vwr)
5516f336411SStefano Zampini                plex.setOptionsPrefix('loaded_')
552e600fa54SMatthew G. Knepley                plex.distributeSetDefault(False)
553728cfed7Sksagiyam                plex.setFromOptions()
554728cfed7Sksagiyam                vwr.popFormat()
555728cfed7Sksagiyam                vwr.destroy()
556728cfed7Sksagiyam                self.outputPlex(plex)
557728cfed7Sksagiyam                # Test DM is indeed distributed
558728cfed7Sksagiyam                flg = plex.isDistributed()
5596f336411SStefano Zampini                self.outputText(
5606f336411SStefano Zampini                    'Loaded mesh distributed? %s\n' % str(flg).upper(), comm
5616f336411SStefano Zampini                )
562728cfed7Sksagiyam                # Interpolate
563728cfed7Sksagiyam                plex.interpolate()
5646f336411SStefano Zampini                plex.setOptionsPrefix('interpolated_')
565728cfed7Sksagiyam                plex.setFromOptions()
566728cfed7Sksagiyam                self.outputPlex(plex)
567728cfed7Sksagiyam                # Redistribute
568728cfed7Sksagiyam                part = plex.getPartitioner()
569728cfed7Sksagiyam                part.setType(self.partitionerType())
570afa732d8SStefano Zampini                sf = plex.distribute(overlap=0)
571afa732d8SStefano Zampini                if sf:
572afa732d8SStefano Zampini                    sf.destroy()
5736f336411SStefano Zampini                part.destroy()
5746f336411SStefano Zampini                plex.setName('DMPlex Object')
5756f336411SStefano Zampini                plex.setOptionsPrefix('redistributed_')
576728cfed7Sksagiyam                plex.setFromOptions()
577728cfed7Sksagiyam                self.outputPlex(plex)
578728cfed7Sksagiyam                # Save redistributed dm to XDMF in parallel
579728cfed7Sksagiyam                vwr.create(self.outfile(), mode='w', comm=comm)
580728cfed7Sksagiyam                vwr.pushFormat(format=self.outformat())
5816f336411SStefano Zampini                plex.setName('DMPlex Object')
582728cfed7Sksagiyam                plex.view(viewer=vwr)
583728cfed7Sksagiyam                vwr.popFormat()
584728cfed7Sksagiyam                vwr.destroy()
585728cfed7Sksagiyam                # Destroy plex
586728cfed7Sksagiyam                plex.destroy()
5876f336411SStefano Zampini                self.outputText('End   cycle %d\n--------\n' % i, comm)
588afa732d8SStefano Zampini            comm.tompi4py().Free()
589728cfed7Sksagiyam            PETSc.COMM_WORLD.Barrier()
590728cfed7Sksagiyam        # Check that the output is identical to that of plex/tutorial/ex5.c.
5916f336411SStefano Zampini        self.assertTrue(
5926f336411SStefano Zampini            filecmp.cmp(self.tmp_output_file(), self.ref_output_file(), shallow=False),
593690e8b0dSJames Wright            f'Contents of the files not the same. Reference file: {self.ref_output_file()}',
5946f336411SStefano Zampini        )
595728cfed7Sksagiyam        PETSc.COMM_WORLD.Barrier()
596728cfed7Sksagiyam
5976f336411SStefano Zampini
598728cfed7Sksagiyamclass BaseTestPlexHDF5Homogeneous(BaseTestPlexHDF5):
599728cfed7Sksagiyam    """Test save on N / load on N."""
6006f336411SStefano Zampini
601728cfed7Sksagiyam    SUFFIX = 0
602728cfed7Sksagiyam    HETEROGENEOUS = False
603728cfed7Sksagiyam
6046f336411SStefano Zampini
605728cfed7Sksagiyamclass BaseTestPlexHDF5Heterogeneous(BaseTestPlexHDF5):
606728cfed7Sksagiyam    """Test save on N / load on M."""
6076f336411SStefano Zampini
608728cfed7Sksagiyam    SUFFIX = 1
609728cfed7Sksagiyam    HETEROGENEOUS = True
610728cfed7Sksagiyam
6116f336411SStefano Zampini
6126f336411SStefano Zampiniclass TestPlexHDF5PETSCSimpleHomogeneous(
6136f336411SStefano Zampini    BaseTestPlexHDF5Homogeneous, unittest.TestCase
6146f336411SStefano Zampini):
6156f336411SStefano Zampini    OUTFORMAT = 'hdf5_petsc'
6166f336411SStefano Zampini    PARTITIONERTYPE = 'simple'
6176f336411SStefano Zampini
618728cfed7Sksagiyam
619728cfed7Sksagiyam"""
620728cfed7SksagiyamSkipping. PTScotch produces different distributions when run
621728cfed7Sksagiyamin a sequence in a single session.
622728cfed7Sksagiyam
623728cfed7Sksagiyamclass TestPlexHDF5PETSCPTScotchHomogeneous(BaseTestPlexHDF5Homogeneous,
624728cfed7Sksagiyam                                           unittest.TestCase):
625728cfed7Sksagiyam    OUTFORMAT = "hdf5_petsc"
626728cfed7Sksagiyam    PARTITIONERTYPE = "ptscotch"
627728cfed7Sksagiyam"""
628728cfed7Sksagiyam
629728cfed7Sksagiyam
6306f336411SStefano Zampiniclass TestPlexHDF5PETSCParmetisHomogeneous(
6316f336411SStefano Zampini    BaseTestPlexHDF5Homogeneous, unittest.TestCase
6326f336411SStefano Zampini):
6336f336411SStefano Zampini    OUTFORMAT = 'hdf5_petsc'
6346f336411SStefano Zampini    PARTITIONERTYPE = 'parmetis'
6356f336411SStefano Zampini
6366f336411SStefano Zampini
6376f336411SStefano Zampiniclass TestPlexHDF5XDMFSimpleHomogeneous(BaseTestPlexHDF5Homogeneous, unittest.TestCase):
6386f336411SStefano Zampini    OUTFORMAT = 'hdf5_xdmf'
6396f336411SStefano Zampini    PARTITIONERTYPE = 'simple'
6406f336411SStefano Zampini
641728cfed7Sksagiyam
642728cfed7Sksagiyam"""
643728cfed7SksagiyamSkipping. PTScotch produces different distributions when run
644728cfed7Sksagiyamin a sequence in a single session.
645728cfed7Sksagiyam
646728cfed7Sksagiyamclass TestPlexHDF5XDMFPTScotchHomogeneous(BaseTestPlexHDF5Homogeneous,
647728cfed7Sksagiyam                                          unittest.TestCase):
648728cfed7Sksagiyam    OUTFORMAT = "hdf5_xdmf"
649728cfed7Sksagiyam    PARTITIONERTYPE = "ptscotch"
650728cfed7Sksagiyam"""
651728cfed7Sksagiyam
652728cfed7Sksagiyam
6536f336411SStefano Zampiniclass TestPlexHDF5XDMFParmetisHomogeneous(
6546f336411SStefano Zampini    BaseTestPlexHDF5Homogeneous, unittest.TestCase
6556f336411SStefano Zampini):
6566f336411SStefano Zampini    OUTFORMAT = 'hdf5_xdmf'
6576f336411SStefano Zampini    PARTITIONERTYPE = 'parmetis'
6586f336411SStefano Zampini
6596f336411SStefano Zampini
6606f336411SStefano Zampiniclass TestPlexHDF5PETSCSimpleHeterogeneous(
6616f336411SStefano Zampini    BaseTestPlexHDF5Heterogeneous, unittest.TestCase
6626f336411SStefano Zampini):
6636f336411SStefano Zampini    OUTFORMAT = 'hdf5_petsc'
6646f336411SStefano Zampini    PARTITIONERTYPE = 'simple'
6656f336411SStefano Zampini
666728cfed7Sksagiyam
667728cfed7Sksagiyam"""
668728cfed7SksagiyamSkipping. PTScotch produces different distributions when run
669728cfed7Sksagiyamin a sequence in a single session.
670728cfed7Sksagiyam
671728cfed7Sksagiyamclass TestPlexHDF5PETSCPTScotchHeterogeneous(BaseTestPlexHDF5Heterogeneous,
672728cfed7Sksagiyam                                             unittest.TestCase):
673728cfed7Sksagiyam    OUTFORMAT = "hdf5_petsc"
674728cfed7Sksagiyam    PARTITIONERTYPE = "ptscotch"
675728cfed7Sksagiyam"""
676728cfed7Sksagiyam
677728cfed7Sksagiyam
6786f336411SStefano Zampiniclass TestPlexHDF5PETSCParmetisHeterogeneous(
6796f336411SStefano Zampini    BaseTestPlexHDF5Heterogeneous, unittest.TestCase
6806f336411SStefano Zampini):
6816f336411SStefano Zampini    OUTFORMAT = 'hdf5_petsc'
6826f336411SStefano Zampini    PARTITIONERTYPE = 'parmetis'
683728cfed7Sksagiyam
684728cfed7Sksagiyam
6856f336411SStefano Zampiniclass TestPlexHDF5XDMFSimpleHeterogeneous(
6866f336411SStefano Zampini    BaseTestPlexHDF5Heterogeneous, unittest.TestCase
6876f336411SStefano Zampini):
6886f336411SStefano Zampini    OUTFORMAT = 'hdf5_xdmf'
6896f336411SStefano Zampini    PARTITIONERTYPE = 'simple'
6906f336411SStefano Zampini
6916f336411SStefano Zampini
6926f336411SStefano Zampiniclass TestPlexHDF5XDMFPTScotchHeterogeneous(
6936f336411SStefano Zampini    BaseTestPlexHDF5Heterogeneous, unittest.TestCase
6946f336411SStefano Zampini):
6956f336411SStefano Zampini    OUTFORMAT = 'hdf5_xdmf'
6966f336411SStefano Zampini    PARTITIONERTYPE = 'ptscotch'
6976f336411SStefano Zampini
6986f336411SStefano Zampini
6996f336411SStefano Zampiniclass TestPlexHDF5XDMFParmetisHeterogeneous(
7006f336411SStefano Zampini    BaseTestPlexHDF5Heterogeneous, unittest.TestCase
7016f336411SStefano Zampini):
7026f336411SStefano Zampini    OUTFORMAT = 'hdf5_xdmf'
7036f336411SStefano Zampini    PARTITIONERTYPE = 'parmetis'
7046f336411SStefano Zampini
705728cfed7Sksagiyam
706728cfed7Sksagiyam# --------------------------------------------------------------------
707728cfed7Sksagiyam
7085808f684SSatish Balayif __name__ == '__main__':
7095808f684SSatish Balay    unittest.main()
710