1import petsc4py 2from petsc4py import PETSc 3import unittest 4import os 5import filecmp 6import numpy as np 7import importlib 8 9# -------------------------------------------------------------------- 10 11ERR_ARG_OUTOFRANGE = 63 12 13 14class BaseTestPlex: 15 COMM = PETSc.COMM_WORLD 16 DIM = 1 17 CELLS = [[0, 1], [1, 2]] 18 COORDS = [[0.0], [0.5], [1.0]] 19 COMP = 1 20 DOFS = [1, 0] 21 22 def setUp(self): 23 self.plex = PETSc.DMPlex().createFromCellList( 24 self.DIM, self.CELLS, self.COORDS, comm=self.COMM 25 ) 26 27 def tearDown(self): 28 self.plex.destroy() 29 self.plex = None 30 PETSc.garbage_cleanup() 31 32 def testTopology(self): 33 rank = self.COMM.rank 34 dim = self.plex.getDimension() 35 pStart, pEnd = self.plex.getChart() 36 cStart, cEnd = self.plex.getHeightStratum(0) 37 vStart, vEnd = self.plex.getDepthStratum(0) 38 numDepths = self.plex.getLabelSize('depth') 39 coords_raw = self.plex.getCoordinates().getArray() 40 coords = np.reshape(coords_raw, (vEnd - vStart, dim)) 41 self.assertEqual(dim, self.DIM) 42 self.assertEqual(numDepths, self.DIM + 1) 43 if rank == 0 and self.CELLS is not None: 44 self.assertEqual(cEnd - cStart, len(self.CELLS)) 45 if rank == 0 and self.COORDS is not None: 46 self.assertEqual(vEnd - vStart, len(self.COORDS)) 47 self.assertTrue((coords == self.COORDS).all()) 48 49 def testClosure(self): 50 pStart, pEnd = self.plex.getChart() 51 for p in range(pStart, pEnd): 52 closure = self.plex.getTransitiveClosure(p)[0] 53 for c in closure: 54 cone = self.plex.getCone(c) 55 self.assertEqual(self.plex.getConeSize(c), len(cone)) 56 for i in cone: 57 self.assertIn(i, closure) 58 star = self.plex.getTransitiveClosure(p, useCone=False)[0] 59 for s in star: 60 support = self.plex.getSupport(s) 61 self.assertEqual(self.plex.getSupportSize(s), len(support)) 62 for i in support: 63 self.assertIn(i, star) 64 65 def testAdjacency(self): 66 PETSc.DMPlex.setAdjacencyUseAnchors(self.plex, False) 67 flag = PETSc.DMPlex.getAdjacencyUseAnchors(self.plex) 68 self.assertFalse(flag) 69 PETSc.DMPlex.setAdjacencyUseAnchors(self.plex, True) 70 flag = PETSc.DMPlex.getAdjacencyUseAnchors(self.plex) 71 self.assertTrue(flag) 72 PETSc.DMPlex.setBasicAdjacency(self.plex, False, False) 73 flagA, flagB = PETSc.DMPlex.getBasicAdjacency(self.plex) 74 self.assertFalse(flagA) 75 self.assertFalse(flagB) 76 PETSc.DMPlex.setBasicAdjacency(self.plex, True, True) 77 flagA, flagB = PETSc.DMPlex.getBasicAdjacency(self.plex) 78 self.assertTrue(flagA) 79 self.assertTrue(flagB) 80 pStart, pEnd = self.plex.getChart() 81 for p in range(pStart, pEnd): 82 adjacency = self.plex.getAdjacency(p) 83 self.assertTrue(p in adjacency) 84 self.assertTrue(len(adjacency) > 1) 85 86 def testSectionDofs(self): 87 self.plex.setNumFields(1) 88 section = self.plex.createSection([self.COMP], [self.DOFS]) 89 size = section.getStorageSize() 90 entity_dofs = [ 91 self.plex.getStratumSize('depth', d) * self.DOFS[d] 92 for d in range(self.DIM + 1) 93 ] 94 self.assertEqual(sum(entity_dofs), size) 95 96 def testSectionClosure(self): 97 section = self.plex.createSection([self.COMP], [self.DOFS]) 98 self.plex.setSection(section) 99 vec = self.plex.createLocalVec() 100 pStart, pEnd = self.plex.getChart() 101 for p in range(pStart, pEnd): 102 for i in range(section.getDof(p)): 103 off = section.getOffset(p) 104 vec.setValue(off + i, p) 105 106 for p in range(pStart, pEnd): 107 point_closure = self.plex.getTransitiveClosure(p)[0] 108 dof_closure = self.plex.vecGetClosure(section, vec, p) 109 for p in dof_closure: 110 self.assertIn(p, point_closure) 111 112 def testBoundaryLabel(self): 113 pStart, pEnd = self.plex.getChart() 114 if pEnd - pStart == 0: 115 return 116 117 self.assertFalse(self.plex.hasLabel('boundary')) 118 self.plex.markBoundaryFaces('boundary') 119 self.assertTrue(self.plex.hasLabel('boundary')) 120 121 faces = self.plex.getStratumIS('boundary', 1) 122 for f in faces.getIndices(): 123 points, orient = self.plex.getTransitiveClosure(f, useCone=True) 124 for p in points: 125 self.plex.setLabelValue('boundary', p, 1) 126 127 for p in range(pStart, pEnd): 128 if self.plex.getLabelValue('boundary', p) != 1: 129 self.plex.setLabelValue('boundary', p, 2) 130 131 numBoundary = self.plex.getStratumSize('boundary', 1) 132 numInterior = self.plex.getStratumSize('boundary', 2) 133 self.assertNotEqual(numBoundary, pEnd - pStart) 134 self.assertNotEqual(numInterior, pEnd - pStart) 135 self.assertEqual(numBoundary + numInterior, pEnd - pStart) 136 137 def testMetric(self): 138 if self.DIM == 1: 139 return 140 self.plex.distribute() 141 if self.CELLS is None and not self.plex.isSimplex(): 142 return 143 self.plex.orient() 144 145 h_min = 1.0e-30 146 h_max = 1.0e30 147 a_max = 1.0e10 148 target = 8.0 149 p = 1.0 150 beta = 1.3 151 hausd = 0.01 152 self.plex.metricSetUniform(False) 153 self.plex.metricSetIsotropic(False) 154 self.plex.metricSetRestrictAnisotropyFirst(False) 155 self.plex.metricSetNoInsertion(False) 156 self.plex.metricSetNoSwapping(False) 157 self.plex.metricSetNoMovement(False) 158 self.plex.metricSetNoSurf(False) 159 self.plex.metricSetVerbosity(-1) 160 self.plex.metricSetNumIterations(3) 161 self.plex.metricSetMinimumMagnitude(h_min) 162 self.plex.metricSetMaximumMagnitude(h_max) 163 self.plex.metricSetMaximumAnisotropy(a_max) 164 self.plex.metricSetTargetComplexity(target) 165 self.plex.metricSetNormalizationOrder(p) 166 self.plex.metricSetGradationFactor(beta) 167 self.plex.metricSetHausdorffNumber(hausd) 168 169 self.assertFalse(self.plex.metricIsUniform()) 170 self.assertFalse(self.plex.metricIsIsotropic()) 171 self.assertFalse(self.plex.metricRestrictAnisotropyFirst()) 172 self.assertFalse(self.plex.metricNoInsertion()) 173 self.assertFalse(self.plex.metricNoSwapping()) 174 self.assertFalse(self.plex.metricNoMovement()) 175 self.assertFalse(self.plex.metricNoSurf()) 176 self.assertTrue(self.plex.metricGetVerbosity() == -1) 177 self.assertTrue(self.plex.metricGetNumIterations() == 3) 178 self.assertTrue(np.isclose(self.plex.metricGetMinimumMagnitude(), h_min)) 179 self.assertTrue(np.isclose(self.plex.metricGetMaximumMagnitude(), h_max)) 180 self.assertTrue(np.isclose(self.plex.metricGetMaximumAnisotropy(), a_max)) 181 self.assertTrue(np.isclose(self.plex.metricGetTargetComplexity(), target)) 182 self.assertTrue(np.isclose(self.plex.metricGetNormalizationOrder(), p)) 183 self.assertTrue(np.isclose(self.plex.metricGetGradationFactor(), beta)) 184 self.assertTrue(np.isclose(self.plex.metricGetHausdorffNumber(), hausd)) 185 186 metric1 = self.plex.metricCreateUniform(0.5) 187 metric2 = self.plex.metricCreateUniform(1.0) 188 metric = self.plex.metricCreate() 189 det = self.plex.metricDeterminantCreate() 190 self.plex.metricAverage2(metric1, metric2, metric) 191 metric1.array[:] *= 1.5 192 self.assertTrue(np.allclose(metric.array, metric1.array)) 193 self.plex.metricIntersection2(metric1, metric2, metric) 194 self.assertTrue(np.allclose(metric.array, metric2.array)) 195 self.plex.metricEnforceSPD(metric, metric1, det[0]) 196 self.assertTrue(np.allclose(metric.array, metric1.array)) 197 198 if self.DIM == 2 and PETSc.COMM_WORLD.getSize() > 6: 199 # Error with 7 processes in 2D: normalization factor is -1 200 return 201 202 self.plex.metricNormalize( 203 metric, metric1, det[0], restrictSizes=False, restrictAnisotropy=False 204 ) 205 metric2.scale(pow(target, 2.0 / self.DIM)) 206 self.assertTrue(np.allclose(metric1.array, metric2.array)) 207 208 def testAdapt(self): 209 if self.DIM == 1: 210 return 211 if self.DIM == 3 and PETSc.COMM_WORLD.getSize() > 4: 212 # Error with 5 processes in 3D 213 # ---------------------------- 214 # Warning: MMG5_mmgIntextmet: Unable to diagonalize at least 1 metric. 215 # Error: MMG3D_defsiz_ani: unable to intersect metrics at point 8. 216 # Metric undefined. Exit program. 217 # MMG remeshing problem. Exit program. 218 return 219 self.plex.orient() 220 plex = self.plex.refine() 221 plex.distribute() 222 if self.CELLS is None and not plex.isSimplex(): 223 return 224 if sum(self.DOFS) > 1: 225 return 226 metric = plex.metricCreateUniform(9.0) 227 try: 228 newplex = plex.adaptMetric(metric, '') 229 newplex.destroy() 230 except PETSc.Error as exc: 231 if exc.ierr != ERR_ARG_OUTOFRANGE: 232 raise 233 234 235# -------------------------------------------------------------------- 236 237 238class BaseTestPlex_2D(BaseTestPlex): 239 DIM = 2 240 CELLS = [ 241 [0, 1, 3], 242 [1, 3, 4], 243 [1, 2, 4], 244 [2, 4, 5], 245 [3, 4, 6], 246 [4, 6, 7], 247 [4, 5, 7], 248 [5, 7, 8], 249 ] 250 COORDS = [ 251 [0.0, 0.0], 252 [0.5, 0.0], 253 [1.0, 0.0], 254 [0.0, 0.5], 255 [0.5, 0.5], 256 [1.0, 0.5], 257 [0.0, 1.0], 258 [0.5, 1.0], 259 [1.0, 1.0], 260 ] 261 DOFS = [1, 0, 0] 262 263 264class BaseTestPlex_3D(BaseTestPlex): 265 DIM = 3 266 CELLS = [ 267 [0, 2, 3, 7], 268 [0, 2, 6, 7], 269 [0, 4, 6, 7], 270 [0, 1, 3, 7], 271 [0, 1, 5, 7], 272 [0, 4, 5, 7], 273 ] 274 COORDS = [ 275 [0.0, 0.0, 0.0], 276 [1.0, 0.0, 0.0], 277 [0.0, 1.0, 0.0], 278 [1.0, 1.0, 0.0], 279 [0.0, 0.0, 1.0], 280 [1.0, 0.0, 1.0], 281 [0.0, 1.0, 1.0], 282 [1.0, 1.0, 1.0], 283 ] 284 DOFS = [1, 0, 0, 0] 285 286 287# -------------------------------------------------------------------- 288 289 290class TestPlex_1D(BaseTestPlex, unittest.TestCase): 291 pass 292 293 294class TestPlex_2D(BaseTestPlex_2D, unittest.TestCase): 295 def testTransform(self): 296 plex = self.plex 297 cstart, cend = plex.getHeightStratum(0) 298 tr = PETSc.DMPlexTransform().create(comm=PETSc.COMM_WORLD) 299 tr.setType(PETSc.DMPlexTransformType.REFINEALFELD) 300 tr.setDM(plex) 301 tr.setUp() 302 newplex = tr.apply(plex) 303 tr.destroy() 304 newcstart, newcend = newplex.getHeightStratum(0) 305 newplex.destroy() 306 self.assertTrue((newcend - newcstart) == 3 * (cend - cstart)) 307 308 309class TestPlex_3D(BaseTestPlex_3D, unittest.TestCase): 310 pass 311 312 313class TestPlex_2D_P3(BaseTestPlex_2D, unittest.TestCase): 314 DOFS = [1, 2, 1] 315 316 317class TestPlex_3D_P3(BaseTestPlex_3D, unittest.TestCase): 318 DOFS = [1, 2, 1, 0] 319 320 321class TestPlex_3D_P4(BaseTestPlex_3D, unittest.TestCase): 322 DOFS = [1, 3, 3, 1] 323 324 325class TestPlex_2D_BoxTensor(BaseTestPlex_2D, unittest.TestCase): 326 CELLS = None 327 COORDS = None 328 329 def setUp(self): 330 self.plex = PETSc.DMPlex().createBoxMesh([3, 3], simplex=False) 331 332 333class TestPlex_3D_BoxTensor(BaseTestPlex_3D, unittest.TestCase): 334 CELLS = None 335 COORDS = None 336 337 def setUp(self): 338 self.plex = PETSc.DMPlex().createBoxMesh([3, 3, 3], simplex=False) 339 340 341# FIXME 342try: 343 raise PETSc.Error 344 PETSc.DMPlex().createBoxMesh([2, 2], simplex=True, comm=PETSc.COMM_SELF).destroy() 345except PETSc.Error: 346 pass 347else: 348 349 class TestPlex_2D_Box(BaseTestPlex_2D, unittest.TestCase): 350 CELLS = None 351 COORDS = None 352 353 def setUp(self): 354 self.plex = PETSc.DMPlex().createBoxMesh([1, 1], simplex=True) 355 356 class TestPlex_2D_Boundary(BaseTestPlex_2D, unittest.TestCase): 357 CELLS = None 358 COORDS = None 359 360 def setUp(self): 361 boundary = PETSc.DMPlex().create(self.COMM) 362 boundary.createSquareBoundary([0.0, 0.0], [1.0, 1.0], [2, 2]) 363 boundary.setDimension(self.DIM - 1) 364 self.plex = PETSc.DMPlex().generate(boundary) 365 366 class TestPlex_3D_Box(BaseTestPlex_3D, unittest.TestCase): 367 CELLS = None 368 COORDS = None 369 370 def setUp(self): 371 self.plex = PETSc.DMPlex().createBoxMesh([1, 1, 1], simplex=True) 372 373 class TestPlex_3D_Boundary(BaseTestPlex_3D, unittest.TestCase): 374 CELLS = None 375 COORDS = None 376 377 def setUp(self): 378 boundary = PETSc.DMPlex().create(self.COMM) 379 boundary.createCubeBoundary([0.0, 0.0, 0.0], [1.0, 1.0, 1.0], [1, 1, 1]) 380 boundary.setDimension(self.DIM - 1) 381 self.plex = PETSc.DMPlex().generate(boundary) 382 383# -------------------------------------------------------------------- 384 385PETSC_DIR = petsc4py.get_config()['PETSC_DIR'] 386 387 388def check_dtype(method): 389 def wrapper(self, *args, **kwargs): 390 if PETSc.ScalarType is PETSc.ComplexType: 391 return None 392 return method(self, *args, **kwargs) 393 394 return wrapper 395 396 397def check_package(method): 398 def wrapper(self, *args, **kwargs): 399 if not PETSc.Sys.hasExternalPackage('hdf5'): 400 return None 401 if self.PARTITIONERTYPE != 'simple' and not PETSc.Sys.hasExternalPackage( 402 self.PARTITIONERTYPE 403 ): 404 return None 405 return method(self, *args, **kwargs) 406 407 return wrapper 408 409 410def check_nsize(method): 411 def wrapper(self, *args, **kwargs): 412 if PETSc.COMM_WORLD.size != self.NSIZE: 413 return None 414 return method(self, *args, **kwargs) 415 416 return wrapper 417 418 419class BaseTestPlexHDF5: 420 NSIZE = 4 421 NTIMES = 3 422 423 def setUp(self): 424 self.txtvwr = PETSc.Viewer() 425 426 def tearDown(self): 427 if not PETSc.COMM_WORLD.rank: 428 if os.path.exists(self.outfile()): 429 os.remove(self.outfile()) 430 if os.path.exists(self.tmp_output_file()): 431 os.remove(self.tmp_output_file()) 432 self.txtvwr = None 433 434 def _name(self): 435 return f'{self.SUFFIX}_outformat-{self.OUTFORMAT}_{self.PARTITIONERTYPE}' 436 437 def infile(self): 438 return os.path.join( 439 PETSC_DIR, 'share/petsc/datafiles/', 'meshes/blockcylinder-50.h5' 440 ) 441 442 def outfile(self): 443 return os.path.join('./temp_test_dmplex_%s.h5' % self._name()) 444 445 def informat(self): 446 return PETSc.Viewer.Format.HDF5_XDMF 447 448 def outformat(self): 449 d = { 450 'hdf5_petsc': PETSc.Viewer.Format.HDF5_PETSC, 451 'hdf5_xdmf': PETSc.Viewer.Format.HDF5_XDMF, 452 } 453 return d[self.OUTFORMAT] 454 455 def partitionerType(self): 456 d = { 457 'simple': PETSc.Partitioner.Type.SIMPLE, 458 'ptscotch': PETSc.Partitioner.Type.PTSCOTCH, 459 'parmetis': PETSc.Partitioner.Type.PARMETIS, 460 } 461 return d[self.PARTITIONERTYPE] 462 463 def ref_output_file(self): 464 return os.path.join( 465 PETSC_DIR, 466 'src/dm/impls/plex/tutorials/', 467 'output/ex5_%s.out' % self._name(), 468 ) 469 470 def tmp_output_file(self): 471 return os.path.join('./temp_test_dmplex_%s.out' % self._name()) 472 473 def outputText(self, msg, comm): 474 if not comm.rank: 475 with open(self.tmp_output_file(), 'a') as f: 476 f.write(msg) 477 478 def outputPlex(self, plex): 479 self.txtvwr.createASCII(self.tmp_output_file(), mode='a', comm=plex.comm) 480 plex.view(viewer=self.txtvwr) 481 self.txtvwr.destroy() 482 483 @check_dtype 484 @check_package 485 @check_nsize 486 def testViewLoadCycle(self): 487 grank = PETSc.COMM_WORLD.rank 488 for i in range(self.NTIMES): 489 if i == 0: 490 infname = self.infile() 491 informt = self.informat() 492 else: 493 infname = self.outfile() 494 informt = self.outformat() 495 if self.HETEROGENEOUS: 496 mycolor = grank > self.NTIMES - i 497 else: 498 mycolor = 0 499 if importlib.util.find_spec('mpi4py') is None: 500 self.skipTest('mpi4py') # throws special exception to signal test skip 501 mpicomm = PETSc.COMM_WORLD.tompi4py() 502 comm = PETSc.Comm(comm=mpicomm.Split(color=mycolor, key=grank)) 503 if mycolor == 0: 504 self.outputText('Begin cycle %d\n' % i, comm) 505 plex = PETSc.DMPlex() 506 vwr = PETSc.ViewerHDF5() 507 # Create plex 508 plex.create(comm=comm) 509 plex.setName('DMPlex Object') 510 # Load data from XDMF into dm in parallel 511 vwr.create(infname, mode='r', comm=comm) 512 vwr.pushFormat(format=informt) 513 plex.load(viewer=vwr) 514 plex.setOptionsPrefix('loaded_') 515 plex.distributeSetDefault(False) 516 plex.setFromOptions() 517 vwr.popFormat() 518 vwr.destroy() 519 self.outputPlex(plex) 520 # Test DM is indeed distributed 521 flg = plex.isDistributed() 522 self.outputText( 523 'Loaded mesh distributed? %s\n' % str(flg).upper(), comm 524 ) 525 # Interpolate 526 plex.interpolate() 527 plex.setOptionsPrefix('interpolated_') 528 plex.setFromOptions() 529 self.outputPlex(plex) 530 # Redistribute 531 part = plex.getPartitioner() 532 part.setType(self.partitionerType()) 533 plex.distribute(overlap=0) 534 part.destroy() 535 plex.setName('DMPlex Object') 536 plex.setOptionsPrefix('redistributed_') 537 plex.setFromOptions() 538 self.outputPlex(plex) 539 # Save redistributed dm to XDMF in parallel 540 vwr.create(self.outfile(), mode='w', comm=comm) 541 vwr.pushFormat(format=self.outformat()) 542 plex.setName('DMPlex Object') 543 plex.view(viewer=vwr) 544 vwr.popFormat() 545 vwr.destroy() 546 # Destroy plex 547 plex.destroy() 548 self.outputText('End cycle %d\n--------\n' % i, comm) 549 PETSc.COMM_WORLD.Barrier() 550 # Check that the output is identical to that of plex/tutorial/ex5.c. 551 self.assertTrue( 552 filecmp.cmp(self.tmp_output_file(), self.ref_output_file(), shallow=False), 553 'Contents of the files not the same.', 554 ) 555 PETSc.COMM_WORLD.Barrier() 556 557 558class BaseTestPlexHDF5Homogeneous(BaseTestPlexHDF5): 559 """Test save on N / load on N.""" 560 561 SUFFIX = 0 562 HETEROGENEOUS = False 563 564 565class BaseTestPlexHDF5Heterogeneous(BaseTestPlexHDF5): 566 """Test save on N / load on M.""" 567 568 SUFFIX = 1 569 HETEROGENEOUS = True 570 571 572class TestPlexHDF5PETSCSimpleHomogeneous( 573 BaseTestPlexHDF5Homogeneous, unittest.TestCase 574): 575 OUTFORMAT = 'hdf5_petsc' 576 PARTITIONERTYPE = 'simple' 577 578 579""" 580Skipping. PTScotch produces different distributions when run 581in a sequence in a single session. 582 583class TestPlexHDF5PETSCPTScotchHomogeneous(BaseTestPlexHDF5Homogeneous, 584 unittest.TestCase): 585 OUTFORMAT = "hdf5_petsc" 586 PARTITIONERTYPE = "ptscotch" 587""" 588 589 590class TestPlexHDF5PETSCParmetisHomogeneous( 591 BaseTestPlexHDF5Homogeneous, unittest.TestCase 592): 593 OUTFORMAT = 'hdf5_petsc' 594 PARTITIONERTYPE = 'parmetis' 595 596 597class TestPlexHDF5XDMFSimpleHomogeneous(BaseTestPlexHDF5Homogeneous, unittest.TestCase): 598 OUTFORMAT = 'hdf5_xdmf' 599 PARTITIONERTYPE = 'simple' 600 601 602""" 603Skipping. PTScotch produces different distributions when run 604in a sequence in a single session. 605 606class TestPlexHDF5XDMFPTScotchHomogeneous(BaseTestPlexHDF5Homogeneous, 607 unittest.TestCase): 608 OUTFORMAT = "hdf5_xdmf" 609 PARTITIONERTYPE = "ptscotch" 610""" 611 612 613class TestPlexHDF5XDMFParmetisHomogeneous( 614 BaseTestPlexHDF5Homogeneous, unittest.TestCase 615): 616 OUTFORMAT = 'hdf5_xdmf' 617 PARTITIONERTYPE = 'parmetis' 618 619 620class TestPlexHDF5PETSCSimpleHeterogeneous( 621 BaseTestPlexHDF5Heterogeneous, unittest.TestCase 622): 623 OUTFORMAT = 'hdf5_petsc' 624 PARTITIONERTYPE = 'simple' 625 626 627""" 628Skipping. PTScotch produces different distributions when run 629in a sequence in a single session. 630 631class TestPlexHDF5PETSCPTScotchHeterogeneous(BaseTestPlexHDF5Heterogeneous, 632 unittest.TestCase): 633 OUTFORMAT = "hdf5_petsc" 634 PARTITIONERTYPE = "ptscotch" 635""" 636 637 638class TestPlexHDF5PETSCParmetisHeterogeneous( 639 BaseTestPlexHDF5Heterogeneous, unittest.TestCase 640): 641 OUTFORMAT = 'hdf5_petsc' 642 PARTITIONERTYPE = 'parmetis' 643 644 645class TestPlexHDF5XDMFSimpleHeterogeneous( 646 BaseTestPlexHDF5Heterogeneous, unittest.TestCase 647): 648 OUTFORMAT = 'hdf5_xdmf' 649 PARTITIONERTYPE = 'simple' 650 651 652class TestPlexHDF5XDMFPTScotchHeterogeneous( 653 BaseTestPlexHDF5Heterogeneous, unittest.TestCase 654): 655 OUTFORMAT = 'hdf5_xdmf' 656 PARTITIONERTYPE = 'ptscotch' 657 658 659class TestPlexHDF5XDMFParmetisHeterogeneous( 660 BaseTestPlexHDF5Heterogeneous, unittest.TestCase 661): 662 OUTFORMAT = 'hdf5_xdmf' 663 PARTITIONERTYPE = 'parmetis' 664 665 666# -------------------------------------------------------------------- 667 668if __name__ == '__main__': 669 unittest.main() 670