Source code for BasicTools.Containers.UnstructuredMesh

# -*- coding: utf-8 -*-
#
# This file is subject to the terms and conditions defined in
# file 'LICENSE.txt', which is part of this source code package.
#
from __future__ import annotations
from typing import Dict, Union

import numpy as np

from BasicTools.NumpyDefs import PBasicFloatType, PBasicIndexType, ArrayLike
import BasicTools.Containers.ElementNames as ElementNames
from BasicTools.Containers.MeshBase import MeshBase
from BasicTools.Containers.MeshBase import Tags, Tag

from BasicTools.Helpers.BaseOutputObject import BaseOutputObject, froze_it

[docs]@froze_it class ElementsContainer(BaseOutputObject): """ Class to hold a list of element of the same type * elementType : a string from BasicTools.Containers.ElementNames * connectivity : the connectivity matrix starting form 0 * tags : the tags holder class * originalIds : the id or number from the previous mesh/file The user can use this data to find the mapping from the initial mesh/file to the current mesh (self). * self.globaloffset : this value is calculate automatically by the mesh .. deprecated:: 2.0.0 * self.cpt : an internal counter to do efficient add of elements one by one The user is responsible to call self.tighten() to compact the connectivity matrix after the population ( calls AddNewElement(...) or allocate(...)) """ def __init__(self,elementType): super(ElementsContainer,self).__init__() self.elementType = elementType self.connectivity = np.empty((0,ElementNames.numberOfNodes[elementType]),dtype=PBasicIndexType) self.globaloffset = 0 self.tags = Tags() self.cpt = 0 self.originalIds = np.empty((0,),dtype=PBasicIndexType) self.originalOffset = 0 self.mutable = True def __eq__(self, other:ElementsContainer) -> bool: """return True if 2 container are equal Parameters ---------- other : ElementsContainer _description_ Returns ------- bool True if the 2 containers are equal, False ir not """ if self.elementType != other.elementType: return False self.tighten() other.tighten() if not np.array_equal(self.connectivity, other.connectivity): return False if not np.array_equal(self.originalIds, other.originalIds): return False if self.tags != other.tags: return False if self.originalOffset != other.originalOffset: return False return True
[docs] def GetNumberOfElements(self)->int : """return the number of elements in this container Returns ------- int Number of elements """ return self.cpt
#return self.connectivity.shape[0]
[docs] def Merge(self,other:ElementsContainer, offset:int=None): """ Merge the elements from the other container into this. Warning!!! Non elimination of double elements is done if an offset is supplied the connectivity of the other container is shifted by the value of the offset during the merge """ other.tighten() if other.cpt == 0: return self.Reserve(self.cpt+other.cpt) if offset is None: offset = 0 self.connectivity[self.cpt:,:] = other.connectivity+offset self.originalIds[self.cpt:] = -1*np.arange(other.cpt) for tag in other.tags: self.GetTag(tag.name).AddToTag(tag.GetIds() + self.cpt) self.cpt += other.cpt
[docs] def AddNewElements(self, conn: ArrayLike, originalids: ArrayLike=None) -> int: """Append a new elements to the connectivity Parameters ---------- conn : ArrayLike connectivity of the added elements originalids : ArrayLike, optional the original id of the added element, by default -1 is used Returns ------- int the total number of elements in the container """ onoe = self.GetNumberOfElements() self.Allocate(onoe+conn.shape[0]) self.connectivity[onoe:onoe+conn.shape[0],:] = conn if originalids is None: self.originalIds[onoe:onoe+conn.shape[0]] = -1 else: self.originalIds[onoe:onoe+conn.shape[0]] = originalids return self.cpt
[docs] def AddNewElement(self, conn: ArrayLike, originalid:int)-> int: """append a single element to the connectivity Parameters ---------- conn : ArrayLike connectivity of the added element originalid : int the original id of the added element Returns ------- int the total number of elements in the container """ if self.cpt >= self.connectivity.shape[0]: self.Reserve(2*self.cpt+1) self.connectivity[self.cpt,:] = conn self.originalIds[self.cpt] = originalid self.cpt +=1 return self.cpt
[docs] def GetNumberOfNodesPerElement(self) -> int : """return the number of nodes per element for the elements in this container Returns ------- int the number of nodes per element for the elements in this container """ if self.connectivity.shape[1]: return self.connectivity.shape[1] return ElementNames.numberOfNodes[self.elementType]
[docs] def GetNodesIdFor(self, ids:Union[int,ArrayLike] ) -> np.ndarray: """return the nodes used by the list of elements input: ids : Parameters ---------- ids : Union[int,ArrayLike] the id or a list of ids of elements to treat (always a local id list) Returns ------- np.ndarray the ids of the nodes used by the elements ids """ return np.unique(self.connectivity[ids,:])
[docs] def GetTag(self, tagName:str)->Tag: """ return the tag by name. If the tag does not exist a new tag is created Parameters ---------- tagName : str the name of the tag to retrieve Returns ------- Tag a tag with the name tagName """ return self.tags.CreateTag(tagName,False)
[docs] def Reserve(self,nbElements:int): """Reserve the storage for nbElements The user is responsible to call self.tighten() to compact the connectivity and the originalIds. matrix after the population Parameters ---------- nbElements : int Number of element to reserve """ if nbElements != self.connectivity.shape[0]: self.connectivity = np.resize(self.connectivity, (nbElements,self.GetNumberOfNodesPerElement())) self.originalIds = np.resize(self.originalIds, (nbElements,))
[docs] def Allocate(self,nbElements:int): """Allocate the storage for nbElements the user is responsible of filling the connectivity and the originalIds with valid values Parameters ---------- nbElements : int Number of element to Allocate """ self.Reserve(nbElements) self.cpt = nbElements
[docs] def tighten(self)-> None: """Compact the storage and free non used space. """ self.Reserve(self.cpt) self.tags.Tighten()
[docs] def AddElementToTag(self, globalElemNumber:int, tagname:str)-> bool: """Add an element to a tag using a global element number, if the global number The user must compute the globaloffset first to make this function work .. deprecated:: 2.0.0 This function is to complex and to many side effects. Returns ------- bool True if the element is added to the tag (in the case globalElemNumber element is in this ElementContainers ). """ if globalElemNumber -self.globaloffset < self.GetNumberOfElements(): self.tags.CreateTag(tagname,False).AddToTag(globalElemNumber-self.globaloffset) return True else: return False
def __str__(self): res = " ElementsContainer, " res += " Type : ({},{}), ".format(self.elementType,self.GetNumberOfElements()) res += " Tags : " + " ".join([ ("("+x.name+":"+str(len(x)) +")") for x in self.tags]) + "\n" return res
[docs]@froze_it class AllElements(object): """ Class to store a list of element containers. This class is mostly a re-implementation of dict but with ordered keys. This class is sorted by keys, in lexicographic order, so the retrieving order is stable. note: FB: the number of different types of elements is low, I don't think this is gonna add alot of overhead to the library """ def __init__(self): super(AllElements,self).__init__() self.storage = {} def __eq__(self, other): if len(self.storage) != len(other.storage): return False for i in self: if i in other: if self[i] != other[i]: return False else: return False return True
[docs] def keys(self): return sorted(self.storage.keys())
[docs] def values(self): return [ values for key,values in sorted(self.storage.items()) ]
def __iter__(self): return iter(self.keys())
[docs] def items(self): return sorted(self.storage.items())
#send basis functions calls to the storage dictionary def __setitem__(self, key, value): self.storage[key] = value def __len__(self): return len(self.storage) def __contains__(self, k): return k in self.storage def __getitem__(self,key): return self.storage[key] def __delitem__(self,key): del self.storage[key]
[docs] def GetElementsOfType(self, typename:str) -> ElementsContainer: """return a ElementContainer by name Parameters ---------- typename : str the name of the elements to retrieve Returns ------- ElementsContainer the container """ if not typename in self: self[typename] = ElementsContainer(typename) return self[typename]
[docs] def GetTagsNames(self)-> List[str]: """return a list with all the tags in this container Returns ------- List[str] the list of the tag names """ res = set() for data in self.values(): res.update(data.tags.keys() ) return list(res)
def __str__(self): res = "" for data in self.storage.values(): res += str(data) return res
[docs]@froze_it class UnstructuredMesh(MeshBase): """ Class to store an unstructured (i.e. general) mesh: * self.nodes : the points positions * self.originalIdNodes : the ids of the previous mesh/file * self.elements : the list of all the element in the mesh * self.boundingMin/Max : the bounding box of the mesh (use ComputeBoundingBox to compute it) The manual construction of this class must always end with a call to the function PrepareForOutput or with the context manager mesh.WithModification(). """
[docs] def IsUnstructured(self): return True
def __init__(self): super(UnstructuredMesh, self).__init__() self.nodes = np.empty((0,3),dtype=PBasicFloatType) self.originalIDNodes = np.empty((0,),dtype=PBasicIndexType) self.elements = AllElements() self.boundingMin = np.array([0.,0,0]) self.boundingMax = np.array([0.,0,0]) def __copy__(self): res = UnstructuredMesh() res._assign(self) res.nodes = self.nodes res.originalIDNodes = self.originalIDNodes res.elements = self.elements res.boundingMin = self.boundingMin res.boundingMax = self.boundingMax return res def __eq__(self, other): if not super(UnstructuredMesh,self).__eq__(other): return False if not np.array_equal(self.nodes,other.nodes): return False if not np.array_equal(self.originalIDNodes, other.originalIDNodes): return False if self.elements != other.elements: return False return True
[docs] def ConvertDataForNativeTreatment(self): """Ensure all the data is compatible with the cpp treatment (continuous in C order) """ self.originalIDNodes = np.asarray(self.originalIDNodes, dtype=PBasicIndexType, order="C") self.nodes = np.asarray(self.nodes, dtype=PBasicFloatType, order="C") for data in self.elements.values(): data.connectivity = np.asarray(data.connectivity, dtype=PBasicIndexType, order="C")
[docs] def GetNumberOfNodes(self) -> int: """return the total number of nodes in the mesh Returns ------- int Number of node in the mesh """ return self.nodes.shape[0]
[docs] def SetNodes(self, nodes:ArrayLike, originalIDNodes:ArrayLike=None, generateOriginalIDs:bool = False): """Set nodes and original Ids in the correct internal format. Parameters ---------- nodes : ArrayLike Nodes positions of size (number of node, space dimensionality ) originalIDNodes : ArrayLike, optional original Ids, by default None generateOriginalIDs : bool, optional if True to generate original ids with numpy.arange, by default False """ self.nodes = np.require(nodes, dtype=PBasicFloatType, requirements=['C','A']) if originalIDNodes is not None: self.originalIDNodes = np.require(originalIDNodes,dtype=PBasicIndexType,requirements=['C','A']) elif generateOriginalIDs: self.originalIDNodes = np.arange(self.GetNumberOfNodes(), dtype=PBasicIndexType)
[docs] def GetPointsDimensionality(self) -> int: """Return the number of coordinates of the points Returns ------- int number of columns in the point array """ return self.nodes.shape[1]
[docs] def GetDimensionality(self): """ .. deprecated:: 2.0.0 Please use GetPointsDimensionality() return the dimensionality 2/3 """ return self.nodes.shape[1]
[docs] def GetNumberOfElements(self, dim : int= None) -> int: """Compute and return the total number of elements in the mesh Parameters ---------- dim : int, optional dimensionality filter, by default None Returns ------- int number of element in the mesh (filtered by dim if dim != None) """ numberOfElements = 0 if dim == None: for elemname, data in self.elements.items(): numberOfElements += data.GetNumberOfElements() else: for elemname, data in self.elements.items(): if ElementNames.dimension[elemname] == dim: numberOfElements += data.GetNumberOfElements() return numberOfElements
[docs] def Merge(self, other:UnstructuredMesh): nbNodes = self.GetNumberOfNodes() self.nodes = np.vstack((self.nodes,other.nodes)) self.originalIDNodes = np.hstack((self.originalIDNodes,-other.originalIDNodes)) for tagName in other.nodesTags.keys(): tag = other.nodesTags[tagName] self.nodesTags.CreateTag(tagName,False).AddToTag(tag.GetIds()+nbNodes) def MergeFields(dest, origin, dsize, osize): names = set() names.update(dest.keys()) names.update(origin.keys()) for name in names: dv = dest.get(name,None) ov = origin.get(name,None) if dv is not None and ov is None: shape = list(dv.shape) shape[0] = osize ov = np.zeros(shape,dtype=dv.dtype) elif dv is None and ov is not None: shape = list(ov.shape) shape[0] = dsize dv = np.zeros(shape,dtype=ov.dtype) else: shape = list(ov.shape) if len(shape) == 1: dest[name] = np.hstack((dv,ov)) else: dest[name] = np.vstack((dv,ov)) MergeFields(self.nodeFields, other.nodeFields, self.GetNumberOfNodes(), other.GetNumberOfNodes()) MergeFields(self.elemFields, other.elemFields, self.GetNumberOfElements(), other.GetNumberOfElements()) for name,data in other.elements.items(): self.GetElementsOfType(name).Merge(data,nbNodes)
[docs] def MergeElements(self, other:UnstructuredMesh, force:bool=False): """Merge the elements for a second mesh into this the nodes array must be the same (not only equal) the user can force the merge if needed (force variable) Parameters ---------- other : UnstructuredMesh the other mesh force : bool, optional True to force the merge even if the nodes are not the same, by default False """ if (self.nodes is not other.nodes) and (not force) : raise(RuntimeError("the two meshes does not share the same nodes fields (potentially dangerous)")) for name,data in other.elements.items(): self.GetElementsOfType(name).Merge(data)
[docs] def ComputeGlobalOffset(self) -> Dict[str,PBasicIndexType]: """ Recompute the Global Offset, This is necessary for some operation. Recomendation : Call it after changing the topology .. deprecated:: 2.0.0 The globaloffset variable will be deprecated """ offsets = dict() cpt = 0 for data in self.elements.values(): offsets[data.elementType] = cpt data.globaloffset = cpt cpt += data.GetNumberOfElements() return offsets
[docs] def ComputeBoundingBox(self)->None: """to recompute the bounding box (min and max) """ self.boundingMin = np.amin(self.nodes, axis=0) self.boundingMax = np.amax(self.nodes, axis=0)
[docs] def AddNodeToTagUsingOriginalId(self, oid:int, tagname:str)->None: """add a node (using the original id ) to a tag (tagname) Parameters ---------- oid : int Original id node tagname : str Tag name Raises ------ Exception if the original id is not found """ w = np.where(self.originalIDNodes == oid) if len(w[0]) > 0 : self.GetNodalTag(tagname).AddToTag(w[0]) else: raise Exception("No node with id " + str(oid)) #pragma: no cover
[docs] def AddElementToTagUsingOriginalId(self, oid:int, tagname:str): """Add an element (using the originalId) to a tag (tagname) Parameters ---------- oid : int the original id of the element tagname : str Tag name Raises ------ Exception if the element with the original id is not found """ for data in self.elements.values(): w = np.where(data.originalIds[:data.cpt] == oid) if len(w[0]) > 0 : data.tags.CreateTag(tagname,False).AddToTag(w[0]) break else: raise Exception("No element with id " + str(oid)) #pragma: no cover
[docs] def AddElementsToTag(self, globalElemNumbers:ArrayLike, tagname:str): """Add elements (using the global element number) to a tag (tagname) you must compute the globaloffset first to make this function work Parameters ---------- globalElemNumbers : ArrayLike the list of the global ids of the element tagname : str Tag name Raises ------ Exception if some elementid are greater than the number of elements. """ elementNotTreated = np.unique(globalElemNumbers) cpt = 0 for data in self.elements.values(): cpt2 = data.GetNumberOfElements() +cpt f = elementNotTreated < cpt2 dataToTreat = elementNotTreated[f] if len(dataToTreat): data.tags.CreateTag(tagname,False).AddToTag(dataToTreat-data.globaloffset) elementNotTreated = elementNotTreated[np.logical_not(f)] cpt += data.GetNumberOfElements() if len(elementNotTreated): raise Exception("No element found") #pragma: no cover
[docs] def AddElementToTag(self, globalElemNumber:int, tagname:str): """Add an element (using the global element number) to a tag (tagname) # you must compute the globaloffset first to make this function work Parameters ---------- globalElemNumber : int the element number tagname : str Tag name Raises ------ Exception if the the element is not found """ for data in self.elements.values(): if data.AddElementToTag(globalElemNumber,tagname): return raise Exception("No element found") #pragma: no cover
[docs] def DeleteElemTags(self, tagNames: List[str]): """Delete element tags Parameters ---------- tagNames : List[str] List of element tags to be deleted """ #check not a string but a list like assert not isinstance(tagNames, str) for data in self.elements.values(): data.tags.DeleteTags(tagNames)
[docs] def GetPosOfNode(self, i:int ) -> np.ndarray: """Return the position of the node i Parameters ---------- i : int id of the node Returns ------- np.ndarray position of the point """ return self.nodes[i,:]
[docs] def GetPosOfNodes(self) -> np.ndarray: """return the position of all the nodes Returns ------- np.ndarray The position for all the nodes in the mesh """ return self.nodes
[docs] def GetElementsOriginalIDs(self,dim:int = None)-> np.ndarray: """return a single list with all the originalid concatenated Parameters ---------- dim : int, optional dimensionality filter, by default None Returns ------- np.ndarray array with all the originalId for the selected elements """ if dim is None: res = np.empty(self.GetNumberOfElements(),dtype=PBasicIndexType) cpt =0 for name, data in self.elements.items(): n = data.originalIds.shape[0] res[0+cpt:n+cpt] = data.originalIds cpt += n else: res = np.empty(self.GetNumberOfElements(dim=dim),dtype=PBasicIndexType) cpt = 0 from BasicTools.Containers.Filters import ElementFilter for name, data, ids in ElementFilter(self,dimensionality = dim): res[0+cpt:len(ids)+cpt] = data.originalIds[ids] cpt += len(ids) return res
[docs] def SetElementsOriginalIDs(self, originalIDs:ArrayLike): """Set from a single list all the element original Ids Parameters ---------- originalIDs : ArrayLike the list of all the original ids in the order of the mesh """ cpt = 0 for data in self.elements.values(): data.originalIds = originalIDs[cpt:data.GetNumberOfElements()+cpt] cpt += data.GetNumberOfElements()
[docs] def GetElementsInTag(self, tagname:str, useOriginalId:bool=False) ->np.ndarray: """return a list with the ids of the elements in a tag Parameters ---------- tagname : str the tag name useOriginalId : bool, optional to return the list of original ids and not the global numbers, by default False Returns ------- np.ndarray the list off all the element in the tag named "tagname" """ res = np.zeros((self.GetNumberOfElements(),),dtype=PBasicIndexType) cpt =0 offsets = self.ComputeGlobalOffset() for name,data in self.elements.items(): if tagname in data.tags: tag = data.tags[tagname].GetIds() if useOriginalId: res[cpt:cpt+len(tag) ] = data.originalIds[tag] else: res[cpt:cpt+len(tag) ] = offsets[name]+tag cpt += len(tag) return res[0:cpt]
[docs] def PrepareForOutput(self) -> None: """Function to free the extra memory used after the incremental creation of a mesh and final treatment (offset computation). """ self.nodesTags.Tighten() for data in self.elements.values(): data.tags.RemoveDoubles() data.tighten() self.ComputeGlobalOffset() self.VerifyIntegrity()
def __str__(self) -> str: """Return a string with a summary of the mesh Returns ------- str summary of the mesh """ res = "UnstructuredMesh \n" res += " Number Of Nodes : {} \n".format(self.GetNumberOfNodes()) res += " Tags : " + " ".join( ["("+x.name+":"+str(len(x))+")" for x in self.nodesTags ]) + "\n" res += " Number Of Elements : {} \n".format(self.GetNumberOfElements()) for data in self.elements.values(): res += str(data) if len(self.nodeFields.keys()) > 0: res += " nodeFields : " + str(list(self.nodeFields.keys())) + "\n" if len(self.elemFields.keys()) > 0: res += " elemFields : " + str(list(self.elemFields.keys())) + "\n" return res
[docs] def Clean(self)->None: """Remove unnecessary data : 1) empty tags 2) empty element containers """ self.nodesTags.RemoveEmptyTags() for k in list(self.elements.keys()): if self.elements[k].GetNumberOfElements() == 0: del self.elements[k] continue self.elements[k].tags.RemoveEmptyTags()
[docs] def VerifyIntegrity(self) -> None: """Integrity verification of the mesh., Raises ------ Exception if the integrity of the mesh is compromised """ #verification nodes an originalIdNodes are compatible if len(self.nodes.shape) !=2: raise Exception("Error in the shape of nodes") if self.nodes.flags['C_CONTIGUOUS'] is False: raise Exception("Error in the order of nodes") if len(self.originalIDNodes.shape) !=1: print(self.originalIDNodes.shape) raise Exception("Error in the shape of originalIDNodes") if self.originalIDNodes.flags['C_CONTIGUOUS'] is False: raise Exception("Error in the order of originalIDNodes") if self.originalIDNodes.shape[0] != self.nodes.shape[0]: print(self.originalIDNodes.shape) print(self.nodes.shape) raise Exception("nodes and originalIDNodes are incompatible") nbnodes = self.nodes.shape[0] #verification of min max in nodes tags for elemtype,data in self.nodesTags.items(): ids = data.GetIds() if len(ids) == 0: continue if ids[0] < 0: raise Exception("Ids of '"+ elemtype +"' tag out of bound (<0)") if ids[-1] >= nbnodes: print(ids) print(nbnodes) raise Exception("Ids of '"+ elemtype +"' tag out of bound > nbnodes") # verification of elements for elemtype, data in self.elements.items(): if data.connectivity.flags['C_CONTIGUOUS'] is False: raise Exception("Error : connectivity not C_CONTIGUOUS") if len(data.connectivity.shape) != 2: raise Exception("Wrong shape of connetivity of elements '"+ elemtype +"'") if data.connectivity.shape is False: raise Exception("Error in the order of connecitivty") if data.originalIds.shape[0] != data.connectivity.shape[0]: print(data.originalIds.shape[0]) print(data.connectivity.shape[0]) raise Exception("connectivity and originalIds are incompatible '"+elemtype+"'") if data.originalIds.flags['C_CONTIGUOUS'] is False: raise Exception("Error in the order of originalIds") if ElementNames.numberOfNodes[elemtype] != data.connectivity.shape[1]: print(elemtype) print(ElementNames.numberOfNodes[elemtype]) print(data.connectivity.shape[1]) raise Exception("Incompatible number of columns of the connectivity array") if len(data.connectivity) and np.amin(data.connectivity) < 0: raise Exception("connectivity of '"+elemtype+"' out of bound (<0)") if len(data.connectivity) and np.amax(data.connectivity) >= nbnodes: print(data.connectivity) print(nbnodes) raise Exception("connectivity of '"+elemtype+"' out of bound > nbnodes") nbelements = data.connectivity.shape[0] #verification of min max in nodes tags for tagName,tagData in data.tags.items(): ids = tagData.GetIds() if len(ids) == 0: continue if ids[0] < 0: print(nbelements) print(ids) raise Exception("Ids of '"+ tagName +"' tag out of bound (<0)") if ids[-1] >= nbelements: print(nbelements) print(ids) raise Exception("Ids of '"+ tagName +"' tag out of bound > nbelements")
[docs]def CheckIntegrity(): from BasicTools.Containers.UnstructuredMeshCreationTools import CreateMeshOfTriangles res = CreateMeshOfTriangles([[0,0,0],[1,2,3],[0,1,0]], [[0,1,2]]) res.ConvertDataForNativeTreatment() elements = res.GetElementsOfType(ElementNames.Triangle_3) elements = res.GetElementsOfType(ElementNames.Bar_2) elements.AddNewElement([1,2],1) elements.GetNumberOfNodesPerElement() print(res.IsUnstructured()) res.ComputeGlobalOffset() res.AddElementToTag(1,"SecondElement") if res.GetNumberOfElements() != 2: raise Exception() res.ComputeGlobalOffset() print(res.GetDimensionality()) res.ComputeBoundingBox() print(res.boundingMin) print(res.boundingMax) res.nodesTags.CreateTag('toto') print(res.GetNodalTag('toto')) print(res.GetNodalTag('toto2')) res.AddElementToTagUsingOriginalId(1,"bars") if res.GetPosOfNodes()[1,1] != 2: raise Exception() print(res.PrepareForOutput()) print(res.GetElementsInTag("bars")) print(res.GetElementsInTag("bars",useOriginalId=True)) print(res.GetElementsOfType(ElementNames.Bar_2).GetTag("toto")) print(res.GetPosOfNode(0)) print(res) res.DeleteElemTags(["SecondElement"]) print(res) resII = CreateMeshOfTriangles([[0,0,0],[1,2,3],[0,1,0]], [[0,1,2]]) resII.AddNodeToTagUsingOriginalId(0,"First Point") resII.GenerateManufacturedOriginalIDs() if resII.GetPointsDimensionality() != 3: raise #pragma: no cover if resII.GetElementsDimensionality() != 2: raise #pragma: no cover resII.Clean() try: resII.MergeElements(res) raise #pragma: no cover except: pass resII.MergeElements(res,force=True) print("----") print(resII) print(resII.GetNumberOfElements(dim=2)) print(resII.elements.GetTagsNames()) del resII.elements[ElementNames.Triangle_3] resII.nodeFields["scalarNF"] = np.zeros(resII.GetNumberOfNodes(), dtype=PBasicFloatType) res.nodeFields["scalarNF"] = np.arange(res.GetNumberOfNodes(), dtype=PBasicFloatType) resII.nodeFields["vectorNF"] = np.zeros((resII.GetNumberOfNodes(),2), dtype=PBasicFloatType) res.nodeFields["vectorNF"] = np.ones((res.GetNumberOfNodes(),2), dtype=PBasicFloatType) resII.elemFields["scalarEF"] = np.zeros(resII.GetNumberOfElements(), dtype=PBasicFloatType) res.elemFields["scalarEF"] = np.zeros(res.GetNumberOfElements(), dtype=PBasicFloatType) resII.elemFields["vectorEF"] = np.zeros((resII.GetNumberOfElements(),2), dtype=PBasicIndexType) res.elemFields["vectorEF"] = np.ones((res.GetNumberOfElements(),2), dtype=PBasicIndexType) resII.elemFields["vectorEF_X"] = np.zeros((resII.GetNumberOfElements(),2), dtype=PBasicFloatType) res.elemFields["vectorEF_Y"] = np.ones((res.GetNumberOfElements(),2), dtype=PBasicFloatType) nsize1 = resII.GetNumberOfNodes() esize1 = resII.GetNumberOfElements() nsize2 = res.GetNumberOfNodes() esize2 = res.GetNumberOfElements() resII.Merge(res) for name, value in resII.elemFields.items(): assert(value.shape[0] == esize1 +esize2) for name, value in resII.nodeFields.items(): assert(value.shape[0] == nsize1 +nsize2) return "ok"
if __name__ == '__main__': print(CheckIntegrity()) #pragma: no cover