def Create(dfsuFile: DfsuFile) -> MeshFile: """Create a mesh file from the provided dfsu file. The dfsu file must be a 2D dfsu file. """ if dfsuFile.ZUnit != eumUnit.eumUUnitUndefined: bathyQuantity = eumQuantity(eumItem.eumIBathymetry, dfsuFile.ZUnit) else: bathyQuantity = eumQuantity(eumItem.eumIBathymetry, eumUnit.eumUmeter) res = MeshFile.Create(bathyQuantity, dfsuFile.Projection.WKTString, dfsuFile.NodeIds, dfsuFile.X, dfsuFile.Y, dfsuFile.Z.astype(dtype=np.float32), dfsuFile.Code, dfsuFile.ElementIds, dfsuFile.ElementType, dfsuFile.ElementTable) return res
def CreateMesh(self) -> MeshFile: """Create and return a new MeshFile object""" self.Validate(dieOnError=True) # Creating default eumQuantity in meters if self.__eumQuantity is None: self.__eumQuantity = eumQuantity(eumItem.eumIBathymetry, eumUnit.eumUmeter) # Creating default node id's, if empty if self.__nodeIds is None: self.__nodeIds = np.arange(len(self.__x)) + 1 # Creating default element id's, if empty if self.__elementIds is None: self.__elementIds = np.arange(len(self.__connectivity)) + 1 # Creating additional element information elementType = np.zeros(len(self.__connectivity), dtype=np.int32) nodesPerElmt = np.zeros(len(self.__connectivity), dtype=np.int32) nodeElmtCount = 0 # total number of nodes listed in the connectivity table for i in range(len(elementType)): elmtTypeNumber = 0 elmt = self.__connectivity[i] if len(elmt) == 3: elmtTypeNumber = 21 elif len(elmt) == 4: elmtTypeNumber = 25 elif len(elmt) == 6: elmtTypeNumber = 32 elif len(elmt) == 8: elmtTypeNumber = 33 else: raise Exception( "Element with invalid number of nodes encountered") elementType[i] = elmtTypeNumber nodesPerElmt[i] = len(elmt) nodeElmtCount += len(elmt) # NotUsed # connectivityArray = np.zeros(nodeElmtCount, dtype=np.int32) # k = 0 # for i in range(len(elementType)): # elmt = self.__connectivity[i] # for j in range(len(elmt)): # connectivityArray[k] = elmt[j] # k += 1 res = MeshFile.Create(self.__eumQuantity, self.__projectionString, self.__nodeIds, self.__x, self.__y, self.__z, self.__code, self.__elementIds, elementType, self.__connectivity) return res
def Read(self, filename: str): """Read .mesh file and load all data. If an element specifies a node number of zero, that node number is ignored, and does not become a part of the mesh data structure. That is the case for e.g. mixed triangular/quadrilateral meshes, where all elements specify 4 nodes, and triangular elements specifies the last node as zero. """ with open(filename, 'r') as reader: # read header line line = reader.readline().lstrip() if line is None: raise IOError("Can not load mesh file. File is empty") noNodes = 0 proj = None header2012 = lambda s: re.match(r"(\d+)\s+(\d+)\s+(\d+)\s+(.+)", s) header2011 = lambda s: re.match(r"(\d+)\s+(.+)", s) # First try match the 2012 header line format match = header2012(line) if match: groups = match.groups() itemType = eumItem(int(groups[0])) itemUnit = eumUnit(int(groups[1])) self.EumQuantity = eumQuantity(itemType, itemUnit) noNodes = int(groups[2]) proj = groups[3] # If not successfull, try match the 2011 header line format if proj is None: match = header2011(line) if match: self.EumQuantity = eumQuantity(eumItem.eumIBathymetry, eumUnit.eumUmeter) groups = match.groups() noNodes = int(groups[0]) proj = groups[1] if proj is None: raise IOError( "Can not load mesh file (failed reading mesh file header line): {0}" .format(filename)) self.ProjectionString = proj.strip() self.NodeIds = np.zeros(noNodes, dtype=np.int32) self.X = np.zeros(noNodes, dtype=np.float64) self.Y = np.zeros(noNodes, dtype=np.float64) self.Z = np.zeros(noNodes, dtype=np.float64) # TODO or np.float32 ? self.Code = np.zeros(noNodes, dtype=np.int32) # Read nodes try: for i in range(noNodes): line = reader.readline().strip() if line is None: raise IOError("Unexpected end of file" ) # used as inner exception strings = re.split(r"\s+", line) self.NodeIds[i] = int(strings[0]) self.X[i] = float(strings[1]) self.Y[i] = float(strings[2]) self.Z[i] = float(strings[3]) self.Code[i] = int(strings[4]) except Exception as inner: # DfsException raise Exception( "Can not load mesh file (failed reading nodes): {0}. {1}". format(filename, inner)) # Reading element header line line = reader.readline().strip() if line is None: raise IOError( "Can not load mesh file (unexpected end of file)") strings = re.split(r"\s+", line) if (len(strings) != 3): raise IOError( "Can not load mesh file (failed reading element header line): {0}" .format(filename)) try: noElements = int(strings[0]) elmtCode = int(strings[2]) except Exception as ex: raise Exception( "Can not load mesh file (failed reading element header line): {0}. {1}" .format(filename, ex)) # Element code must be 21 or 25 (21 for triangular meshes, 25 for mixed meshes) if (elmtCode != 21) or (elmtCode != 25): pass # TODO?? Do we care? # Allocate memory for elements self.ElementIds = np.zeros(noElements, dtype=np.int32) self.ElementType = np.zeros(noElements, dtype=np.int32) self.ElementTable = [] # Read all elements try: for i in range(noElements): line = reader.readline().strip() if line is None: raise IOError("Unexpected end of file" ) # used as inner exception strings = re.split(r"\s+", line) self.ElementIds[i] = int(strings[0]) noNodesInElmt = len(strings) - 1 nodesInElement = np.zeros(noNodesInElmt, dtype=np.int32) for j in range(noNodesInElmt): nodeNumber = int(strings[j + 1]) if (nodeNumber < 0) or (nodeNumber > noNodes ): # used as inner exception: raise IOError( "Node number in element table is negative or larger than number of nodes" ) # It is only a node in the element if the node number is positive if nodeNumber > 0: nodesInElement[j] = nodeNumber self.ElementTable.append( nodesInElement[nodesInElement > 0]) # Get element type from number of nodes if len(self.ElementTable[i]) == 3: self.ElementType[i] = 21 elif len(self.ElementTable[i]) == 4: self.ElementType[i] = 25 self._hasQuads = True else: self.ElementType[i] = 0 # TODO: Throw an exception? except Exception as inner: raise Exception( "Can not load mesh file (failed reading elements): {0}. {1}" .format(filename, inner))
def CreateDfsu(self, dfsBuilder, elementType, nodesPerElmt, connectivityArray): # Add static items # Static items in a dfsu file: # "Node id" , int # "X-coord" , float # "Y-coord" , float # "Z-coord" , float # "Code" , int # "Element id" , int # "Element type" , int # "No of nodes" , int # "Connectivity" , int intCode = eumQuantity(eumItem.eumIIntegerCode, eumUnit.eumUintCode) xyQuantity = eumQuantity(eumItem.eumIGeographicalCoordinate, eumUnit.eumUmeter) # TODO: reenable: #if (MapProjection.IsValid(self.__dfsProjection.WKTString)): # if (MapProjection.IsGeographical(self.__dfsProjection.WKTString)): # xyQuantity = eumQuantity(eumItem.eumILatLong, eumUnit.eumUdegree) # Node id nodeIdItem = dfsBuilder.AddCreateStaticItem("Node id", intCode, self.__nodeIds) # X-coord xItem = dfsBuilder.AddCreateStaticItem("X-coord", xyQuantity, self.__x) # Y-coord yItem = dfsBuilder.AddCreateStaticItem("Y-coord", xyQuantity, self.__y) # Z-coord zItem = dfsBuilder.AddCreateStaticItem("Z-coord", self.__zQuantity, self.__z) # Code codeItem = dfsBuilder.AddCreateStaticItem("Code", intCode, self.__code) # Element id elmtIdItem = dfsBuilder.AddCreateStaticItem("Element id", intCode, self.__elementIds) # Element type elmtTypeItem = dfsBuilder.AddCreateStaticItem("Element type", intCode, elementType) # No of nodes (per element) nodesPerElmtItem = dfsBuilder.AddCreateStaticItem( "No of nodes", intCode, nodesPerElmt) # Connectivity connectivityItem = dfsBuilder.AddCreateStaticItem( "Connectivity", intCode, connectivityArray) dfsFile = dfsBuilder.GetFile() dfsuFile = DfsuFile() dfsuFile.DfsuFileBuild(dfsFile, nodeIdItem, xItem, yItem, zItem, codeItem, elmtIdItem, self.__nodeIds, self.__x, self.__y, self.__z, self.__code, self.__elementIds, elementType, self.__connectivity, self.__zUnit) return (dfsuFile)
def SetupBuilder(self): self.__zQuantity = eumQuantity(eumItem.eumIItemGeometry3D, self.__zUnit) factory = DfsFactory() dfsBuilder = DfsBuilder.Create(self.FileTitle, self.ApplicationTitle, self.ApplicationVersion) dfsBuilder.SetDataType(2001) dfsBuilder.SetGeographicalProjection(self.__dfsProjection) if (self.__timeAxis != None): dfsBuilder.SetTemporalAxis(self.__timeAxis) else: dfsBuilder.SetTemporalAxis( factory.CreateTemporalEqCalendarAxis(eumUnit.eumUsec, self.__startDateTime, 0, self.__timeStepInSeconds)) dfsBuilder.DeleteValueFloat = np.float32(1e-35) # Set up custom block if self.__dfsuFileType == DfsuFileType.Dfsu2D: dfsBuilder.AddCreateCustomBlock( "MIKE_FM", np.array([self.__x.size, len(self.__connectivity), 2, 0, 0], np.int32)) elif self.__dfsuFileType == DfsuFileType.DfsuVerticalColumn: maxNumberOfLayers = len(self.__connectivity) dfsBuilder.AddCreateCustomBlock( "MIKE_FM", np.array([ self.__x.size, len(self.__connectivity), 1, maxNumberOfLayers, self.__numberOfSigmaLayers ], np.int32)) elif self.__dfsuFileType == DfsuFileType.DfsuVerticalProfileSigma: maxNumberOfLayers = self.__numberOfSigmaLayers dfsBuilder.AddCreateCustomBlock( "MIKE_FM", np.array([ self.__x.size, len(self.__connectivity), 2, maxNumberOfLayers, self.__numberOfSigmaLayers ], np.int32)) elif self.__dfsuFileType == DfsuFileType.DfsuVerticalProfileSigmaZ: maxNumberOfLayers = DfsuUtil.FindMaxNumberOfLayers( DfsuUtil.FindTopLayerElements(self.__connectivity)) dfsBuilder.AddCreateCustomBlock( "MIKE_FM", np.array([ self.__x.size, len(self.__connectivity), 2, maxNumberOfLayers, self.__numberOfSigmaLayers ], np.int32)) elif self.__dfsuFileType == DfsuFileType.Dfsu3DSigma: maxNumberOfLayers = self.__numberOfSigmaLayers dfsBuilder.AddCreateCustomBlock( "MIKE_FM", np.array([ self.__x.size, len(self.__connectivity), 3, maxNumberOfLayers, self.__numberOfSigmaLayers ], np.int32)) elif self.__dfsuFileType == DfsuFileType.Dfsu3DSigmaZ: maxNumberOfLayers = DfsuUtil.FindMaxNumberOfLayers( DfsuUtil.FindTopLayerElements(self.__connectivity)) dfsBuilder.AddCreateCustomBlock( "MIKE_FM", np.array([ self.__x.size, len(self.__connectivity), 3, maxNumberOfLayers, self.__numberOfSigmaLayers ], np.int32)) else: raise Exception() # For the files with a vertical dimension, the first dynamic item is the Z-coordinate if (self.__dfsuFileType == DfsuFileType.DfsuVerticalColumn or self.__dfsuFileType == DfsuFileType.DfsuVerticalProfileSigma or self.__dfsuFileType == DfsuFileType.DfsuVerticalProfileSigmaZ or self.__dfsuFileType == DfsuFileType.Dfsu3DSigma or self.__dfsuFileType == DfsuFileType.Dfsu3DSigmaZ): dfsItem = dfsBuilder.CreateDynamicItemBuilder() dfsItem.Set("Z coordinate", self.__zQuantity, DfsSimpleType.Float) dfsItem.SetValueType(DataValueType.Instantaneous) # Disabled to make the dfsu files exactly match those from the engine. Not necessary, # but enables binary compares #if (false): # dfsItem.SetAxis(factory.CreateAxisDummy(len(self.__connectivity))) #else # Set axis to have meter unit (not necessary, just to make file exactly equal) dfsItem.SetAxis( factory.CreateAxisEqD1(eumUnit.eumUmeter, self.__x.size, 0, 1)) # Set to default ufs delete values (not used anyway, just to make file exactly equal) dfsItem.SetReferenceCoordinates(-1e-35, -1e-35, -1e-35) dfsItem.SetOrientation(-1e-35, -1e-35, -1e-35) dfsBuilder.AddDynamicItem(dfsItem.GetDynamicItemInfo()) # Set up dynamic items for i in range(len(self.__dynamicItemData)): itemData = self.__dynamicItemData[i] dfsItem = dfsBuilder.CreateDynamicItemBuilder() dfsItem.Set(itemData[0], itemData[1], DfsSimpleType.Float) dfsItem.SetValueType(DataValueType.Instantaneous) # Disabled to make the dfsu files exactly match those from the engine. Not necessary, # but enables binary compares #if (false): # dfsItem.SetAxis(factory.CreateAxisDummy(len(self.__connectivity))) #else # Set axis to have meter unit (not necessary, just to make file exactly equal) dfsItem.SetAxis( factory.CreateAxisEqD1(eumUnit.eumUmeter, len(self.__connectivity), 0, 1)) # Set to default ufs delete values (not used anyway, just to make file exactly equal) dfsItem.SetReferenceCoordinates(-1e-35, -1e-35, -1e-35) dfsItem.SetOrientation(-1e-35, -1e-35, -1e-35) dfsBuilder.AddDynamicItem(dfsItem.GetDynamicItemInfo()) return dfsBuilder