@@ -537,93 +537,19 @@ def writeUBC(mesh, fileName, models=None, directory='', comment_lines=''):
537537
538538class TreeMeshIO (object ):
539539
540- def writeUBC (mesh , fileName , models = None ):
541- """Write UBC ocTree mesh and model files from a
542- octree mesh and model.
543-
544- :param string fileName: File to write to
545- :param dict models: Models in a dict, where each key is the filename
546- """
547-
548- # Calculate information to write in the file.
549- # Number of cells in the underlying mesh
550- nCunderMesh = np .array ([h .size for h in mesh .h ], dtype = np .int64 )
551- # The top-south-west most corner of the mesh
552- tswCorn = mesh .x0 + np .array ([0 , 0 , np .sum (mesh .h [2 ])])
553- # Smallest cell size
554- smallCell = np .array ([h .min () for h in mesh .h ])
555- # Number of cells
556- nrCells = mesh .nC
557-
558- # Extract information about the cells.
559- cellPointers = np .array ([c ._pointer for c in mesh ])
560- cellW = np .array ([mesh ._levelWidth (i ) for i in cellPointers [:, - 1 ]])
561- # Need to shift the pointers to work with UBC indexing
562- # UBC Octree indexes always the top-left-close (top-south-west) corner
563- # first and orders the cells in z(top-down), x, y vs x, y, z(bottom-up)
564- # Shift index up by 1
565- ubcCellPt = cellPointers [:, 0 :- 1 ].copy () + np .array ([1. , 1. , 1. ])
566- # Need re-index the z index to be from the top-left-close corner and to
567- # be from the global top.
568- ubcCellPt [:, 2 ] = (nCunderMesh [- 1 ] + 2 ) - (ubcCellPt [:, 2 ] + cellW )
569-
570- # Reorder the ubcCellPt
571- ubcReorder = np .argsort (
572- ubcCellPt .view (', ' .join (3 * ['float' ])),
573- axis = 0 ,
574- order = ['f2' , 'f1' , 'f0' ]
575- )[:, 0 ]
576- # Make a array with the pointers and the withs,
577- # that are order in the ubc ordering
578- indArr = np .concatenate (
579- (ubcCellPt [ubcReorder , :], cellW [ubcReorder ].reshape ((- 1 , 1 ))),
580- axis = 1
581- )
582- # Write the UBC octree mesh file
583- head = (
584- '{:.0f} {:.0f} {:.0f}\n ' .format (
585- nCunderMesh [0 ], nCunderMesh [1 ], nCunderMesh [2 ]
586- ) +
587- '{:.4f} {:.4f} {:.4f}\n ' .format (
588- tswCorn [0 ], tswCorn [1 ], tswCorn [2 ]
589- ) +
590- '{:.3f} {:.3f} {:.3f}\n ' .format (
591- smallCell [0 ], smallCell [1 ], smallCell [2 ]
592- ) +
593- '{:.0f}' .format (nrCells )
594- )
595- np .savetxt (fileName , indArr , fmt = '%i' , header = head , comments = '' )
596-
597- # Print the models
598- # Assign the model('s) to the object
599- if models is not None :
600- for item in six .iteritems (models ):
601- # Save the data
602- np .savetxt (item [0 ], item [1 ][ubcReorder ], fmt = '%3.5e' )
603-
604540 @classmethod
605541 def readUBC (TreeMesh , meshFile ):
606- """Read UBC 3D OcTree mesh and/or modelFiles
607-
542+ """Read UBC 3D OcTree mesh file
608543 Input:
609544 :param str meshFile: path to the UBC GIF OcTree mesh file to read
610545 :rtype: discretize.TreeMesh
611546 :return: The octree mesh
612547 """
613-
614- # Read the file lines
615548 fileLines = np .genfromtxt (meshFile , dtype = str ,
616- delimiter = '\n ' , comments = '!' )
617- # Extract the data
618- nCunderMesh = np .array (fileLines [0 ].
619- split ('!' )[0 ].split (), dtype = int )
620- # I think this is the case?
621- # Format of file changed... First 3 values are the # of cells in the
622- # underlying mesh and remaining 6 values are padding for the core region.
623- nCunderMesh = nCunderMesh [0 :3 ]
624-
625- if np .unique (nCunderMesh ).size > 1 :
626- raise Exception ('TreeMeshes have the same number of cell in all directions' )
549+ delimiter = '\n ' , comments = '!' )
550+ nCunderMesh = np .array (fileLines [0 ].split ('!' )[0 ].split (), dtype = int )
551+ nCunderMesh = nCunderMesh [0 :3 ]
552+
627553 tswCorn = np .array (
628554 fileLines [1 ].split ('!' )[0 ].split (),
629555 dtype = float
@@ -632,44 +558,37 @@ def readUBC(TreeMesh, meshFile):
632558 fileLines [2 ].split ('!' )[0 ].split (),
633559 dtype = float
634560 )
635- nrCells = np .array (
636- fileLines [3 ].split ('!' )[0 ].split (),
637- dtype = float
638- )
639561 # Read the index array
640- indArr = np .genfromtxt ((line .encode ('utf8' ) for line in fileLines [4 ::]), dtype = np .int )
562+ indArr = np .genfromtxt ((line .encode ('utf8' ) for line in fileLines [4 ::]),
563+ dtype = np .int )
641564
642- # Calculate simpeg parameters
643565 h1 , h2 , h3 = [np .ones (nr )* sz for nr , sz in zip (nCunderMesh , smallCell )]
644566 x0 = tswCorn - np .array ([0 , 0 , np .sum (h3 )])
645- # Convert the index array to a points list that complies with TreeMesh
646- # Shift to start at 0
647- simpegCellPt = indArr [:, 0 :- 1 ].copy ()
648- simpegCellPt [:, 2 ] = ( nCunderMesh [- 1 ] + 2 ) - (simpegCellPt [:, 2 ] + indArr [:, 3 ])
649- # Need reindex the z index to be from the bottom-left-close corner
650- # and to be from the global bottom.
651- simpegCellPt = simpegCellPt - np .array ([1. , 1. , 1. ])
652-
653- # Calculate the cell level
654- simpegLevel = np .log2 (np .min (nCunderMesh )) - np .log2 (indArr [:, 3 ])
655- # Make a pointer matrix
656- simpegPointers = np .concatenate ((simpegCellPt , simpegLevel .reshape ((- 1 , 1 ))), axis = 1 )
657-
658- # Make the tree mesh
567+
568+ ls = np .log2 (nCunderMesh ).astype (int )
569+ if ls [0 ] == ls [1 ] and ls [1 ] == ls [2 ]:
570+ max_level = ls [0 ]
571+ else :
572+ max_level = min (ls )+ 1
573+
659574 mesh = TreeMesh ([h1 , h2 , h3 ], x0 = x0 )
660- mesh ._cells = set ([mesh ._index (p ) for p in simpegPointers .tolist ()])
661575
662- # Figure out the reordering
663- mesh ._simpegReorderUBC = np .argsort (
664- np .array ([mesh ._index (i ) for i in simpegPointers .tolist ()])
665- )
666- # mesh._simpegReorderUBC = np.argsort((np.array([[1, 1, 1, -1]])*simpegPointers).view(', '.join(4*['float'])), axis=0, order=['f3', 'f2', 'f1', 'f0'])[:, 0]
576+ # Convert indArr to points in coordinates of underlying cpp tree
577+ # indArr is ix, iy, iz(top-down) need it in ix, iy, iz (bottom-up)
667578
579+ levels = indArr [:, - 1 ]
580+ indArr = indArr [:, :- 1 ]
581+
582+ indArr -= 1 # shift by 1....
583+ indArr = 2 * indArr + levels [:, None ] # get cell center index
584+ indArr [:, 2 ] = 2 * nCunderMesh [2 ] - indArr [:, 2 ] # switch direction of iz
585+ levels = max_level - np .log2 (levels ) # calculate level
586+
587+ mesh .__setstate__ ((indArr , levels ))
668588 return mesh
669589
670590 def readModelUBC (mesh , fileName ):
671591 """Read UBC OcTree model and get vector
672-
673592 :param string fileName: path to the UBC GIF model file to read
674593 :rtype: numpy.ndarray
675594 :return: OcTree model
@@ -681,49 +600,91 @@ def readModelUBC(mesh, fileName):
681600 out [f ] = mesh .readModelUBC (f )
682601 return out
683602
684- assert hasattr (mesh , '_simpegReorderUBC' ), 'The file must have been loaded from a UBC format.'
685603 assert mesh .dim == 3
686604
687605 modList = []
688606 modArr = np .loadtxt (fileName )
689- if len (modArr .shape ) == 1 :
690- modList .append (modArr [mesh ._simpegReorderUBC ])
691- else :
692- modList .append (modArr [mesh ._simpegReorderUBC , :])
693- return modList
694607
695- def writeVTK (mesh , fileName , models = None ):
608+ ubc_order = mesh ._ubc_order
609+ # order_ubc will re-order from treemesh ordering to UBC ordering
610+ # need the opposite operation
611+ un_order = np .empty_like (ubc_order )
612+ un_order [ubc_order ] = np .arange (len (ubc_order ))
613+
614+ model = modArr [un_order ].copy () # ensure a contiguous array
615+ return model
616+
617+ def writeUBC (mesh , fileName , models = None ):
618+ """Write UBC ocTree mesh and model files from a
619+ octree mesh and model.
620+ :param string fileName: File to write to
621+ :param dict models: Models in a dict, where each key is the filename
622+ """
623+ uniform_hs = np .array ([np .allclose (h , h [0 ]) for h in mesh .h ])
624+ if np .any (~ uniform_hs ):
625+ raise Exception ('UBC form does not support variable cell widths' )
626+ nCunderMesh = np .array ([h .size for h in mesh .h ], dtype = np .int64 )
627+ tswCorn = mesh .x0 + np .array ([0 , 0 , np .sum (mesh .h [2 ])])
628+ smallCell = np .array ([h [0 ] for h in mesh .h ])
629+ nrCells = mesh .nC
630+
631+ indArr , levels = mesh ._ubc_indArr
632+ ubc_order = mesh ._ubc_order
633+
634+ indArr = indArr [ubc_order ]
635+ levels = levels [ubc_order ]
636+
637+ # Write the UBC octree mesh file
638+ head = (
639+ '{:.0f} {:.0f} {:.0f}\n ' .format (
640+ nCunderMesh [0 ], nCunderMesh [1 ], nCunderMesh [2 ]
641+ ) +
642+ '{:.4f} {:.4f} {:.4f}\n ' .format (
643+ tswCorn [0 ], tswCorn [1 ], tswCorn [2 ]
644+ ) +
645+ '{:.3f} {:.3f} {:.3f}\n ' .format (
646+ smallCell [0 ], smallCell [1 ], smallCell [2 ]
647+ ) +
648+ '{:.0f}' .format (nrCells )
649+ )
650+ np .savetxt (fileName , np .c_ [indArr , levels ], fmt = '%i' , header = head , comments = '' )
651+
652+ # Print the models
653+ # Assign the model('s) to the object
654+ if models is not None :
655+ for item in six .iteritems (models ):
656+ # Save the data
657+ np .savetxt (item [0 ], item [1 ][ubc_order ], fmt = '%3.5e' )
658+
659+
660+ def writeVTK (self , fileName , models = None ):
696661 """Function to write a VTU file from a TreeMesh and model."""
697662 import vtk
698663 from vtk import vtkXMLUnstructuredGridWriter as Writer , VTK_VERSION
699- from vtk .util .numpy_support import numpy_to_vtk , numpy_to_vtkIdTypeArray
700-
701- if str (type (mesh )).split ()[- 1 ][1 :- 2 ] not in 'discretize.TreeMesh.TreeMesh' :
702- raise IOError ('mesh is not a TreeMesh.' )
664+ from vtk .util .numpy_support import numpy_to_vtk
703665
704666 # Make the data parts for the vtu object
705667 # Points
706- mesh .number ()
707- ptsMat = mesh ._gridN + mesh .x0
668+ ptsMat = np .vstack ((self .gridN , self .gridhN ))
708669
709670 vtkPts = vtk .vtkPoints ()
710671 vtkPts .SetData (numpy_to_vtk (ptsMat , deep = True ))
711672 # Cells
712- cellConn = np .array ([c .nodes for c in mesh ], dtype = np .int64 )
673+ cellArray = [c for c in self ]
674+ cellConn = np .array ([cell .nodes for cell in cellArray ])
713675
714- cellsMat = np .concatenate ((np .ones ((cellConn .shape [0 ], 1 ), dtype = np . int64 )* cellConn .shape [1 ], cellConn ), axis = 1 ).ravel ()
676+ cellsMat = np .concatenate ((np .ones ((cellConn .shape [0 ], 1 ))* cellConn .shape [1 ], cellConn ), axis = 1 ).ravel ()
715677 cellsArr = vtk .vtkCellArray ()
716678 cellsArr .SetNumberOfCells (cellConn .shape [0 ])
717- cellsArr .SetCells (cellConn .shape [0 ], numpy_to_vtkIdTypeArray (cellsMat , deep = True ))
679+ cellsArr .SetCells (cellConn .shape [0 ], numpy_to_vtk (cellsMat , deep = True , array_type = vtk . VTK_ID_TYPE ))
718680
719681 # Make the object
720682 vtuObj = vtk .vtkUnstructuredGrid ()
721683 vtuObj .SetPoints (vtkPts )
722684 vtuObj .SetCells (vtk .VTK_VOXEL , cellsArr )
723685 # Add the level of refinement as a cell array
724- cellSides = np .array ([np .array (vtuObj .GetCell (i ).GetBounds ()).reshape ((3 , 2 )).dot (np .array ([- 1 , 1 ])) for i in np .arange (vtuObj .GetNumberOfCells ())])
725- uniqueLevel , indLevel = np .unique (np .prod (cellSides , axis = 1 ), return_inverse = True )
726- refineLevelArr = numpy_to_vtk (indLevel .max () - indLevel , deep = 1 )
686+ cell_levels = np .array ([cell ._level for cell in cellArray ])
687+ refineLevelArr = numpy_to_vtk (cell_levels , deep = 1 )
727688 refineLevelArr .SetName ('octreeLevel' )
728689 vtuObj .GetCellData ().AddArray (refineLevelArr )
729690 # Assign the model('s) to the object
0 commit comments