1 # -*- coding: iso-8859-1 -*-
2 # Copyright (C) 2007-2013 CEA/DEN, EDF R&D
4 # This library is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU Lesser General Public
6 # License as published by the Free Software Foundation; either
7 # version 2.1 of the License.
9 # This library is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 # Lesser General Public License for more details.
14 # You should have received a copy of the GNU Lesser General Public
15 # License along with this library; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 # Author Anthony GEAY (CEA/DEN/DM2S/STMF/LGLS)
23 from CaseIO import CaseIO
24 from MEDLoader import *
27 ### www-vis.lbl.gov/NERSC/Software/ensight/doc/OnlineHelp/UM-C11.pdf
29 class CaseWriter(CaseIO):
30 """ Converting MED file format in memory to a the Case file format (Ensight).
31 A new file with the same base name and the .case extension is created with its depencies (.geo ...).
37 model: %(geofilewithoutpath)s
39 header_varpart="""VARIABLE"""
40 header_timepart="""TIME
42 number of steps: %(NbTimeSteps)i
43 filename start number: 0
51 """ Static constructor. """
57 self.__export_groups=False
60 def setMEDFileDS(self,medData):
61 """ Input should be MEDFileData instance """
62 self._med_data=medData
65 def isExportingGroups(self):
66 """ return the status of exporting groups policy """
67 return self.__export_groups
69 def setExportingGroups(self,status):
70 assert(isinstance(status,bool))
71 self.__export_groups=status
75 def write(self,fileName):
76 """ Write into the specified fileName series the result """
77 self._file_name=fileName
78 self._base_name_without_dir=os.path.splitext(os.path.basename(self._file_name))[0]
79 self._l=self._file_name.split(os.path.sep) ; self._l[-1]=os.path.splitext(self._l[-1])[0]
80 self._base_name_with_dir=os.path.sep.join(self._l)
81 self._real_written_file_name=[]
83 for mesh in self._med_data.getMeshes():
84 additionnalFileNamePart=""
85 if len(self._med_data.getMeshes())!=1:
86 additionnalFileNamePart="_%s"%(mesh.getName())
88 self._dico["geofilewithoutpath"]="%s%s.geo"%(self._base_name_without_dir,additionnalFileNamePart)
89 h0=self.header%self._dico
90 self.__writeMeshesPart(mesh,"%s%s.geo"%(self._base_name_with_dir,additionnalFileNamePart))
92 h2=self.__writeFieldsPart(self._med_data.getFields().partOfThisLyingOnSpecifiedMeshName(mesh.getName()))
93 realWrittenCaseFileNameForCurMesh="%s%s.case"%(self._base_name_with_dir,additionnalFileNamePart)
94 fheader=open(realWrittenCaseFileNameForCurMesh,"w") ; fheader.write((h0+h2)%self._dico)
95 self._real_written_file_name.append(realWrittenCaseFileNameForCurMesh)
97 return self._real_written_file_name
99 def __writeMeshesPart(self,mdm,meshfn):
107 assert(isinstance(mdm,MEDFileUMesh))
108 ms2=[[mdm.getMeshAtLevel(lev) for lev in mdm.getNonEmptyLevels()[:1]]]
109 if self.__export_groups:
110 for grpnm in mdm.getGroupsNames():
112 for lev in mdm.getGrpNonEmptyLevels(grpnm)[:1]:
113 m=mdm.getGroup(lev,grpnm) ; m.zipCoords()
120 nn=ms[0].getNumberOfNodes()
121 sz+=self.__computeSizeOfGeoFile(ms,nn)
124 a=np.memmap(f,dtype='byte',mode='w+',offset=0,shape=(sz,)) ; a.flush() # truncate to set the size of the file
125 mm=mmap.mmap(f.fileno(),offset=0,length=0)
126 mm.write(self.__str80("C Binary"))
127 mm.write(self.__str80("Exported from MEDCoupling/MEDLoader SALOME version %s"%(MEDCouplingVersionStr())))
128 mm.write(self.__str80("Conversion using CaseWriter class"))
129 mm.write(self.__str80("node id off"))
130 mm.write(self.__str80("element id off"))
131 for iii,ms in enumerate(ms2):
132 nn=ms[0].getNumberOfNodes()
133 mm.write(self.__str80("part"))
134 a=np.memmap(f,dtype='int32',mode='w+',offset=mm.tell(),shape=(1,))
135 a[0]=iii+1 ; a.flush() ; mm.seek(mm.tell()+4) # part number maybe to change ?
138 name="%s_%s"%(ms2[0][0].getName(),name)
140 mm.write(self.__str80(name))
141 mm.write(self.__str80("coordinates"))
142 a=np.memmap(f,dtype='int32',mode='w+',offset=mm.tell(),shape=(1,))
143 a[0]=nn ; a.flush() # number of nodes
145 coo=ms[0].getCoords()
146 spaceDim=coo.getNumberOfComponents()
148 coo=coo.changeNbOfComponents(3,0.)
150 a=np.memmap(f,dtype='float32',mode='w+',offset=mm.tell(),shape=(3,nn))
151 c=coo.toNoInterlace() ; c.rearrange(1) ; cnp=c.toNumPyArray() ; cnp=cnp.reshape(3,nn)
152 a[:]=cnp ; a.flush() ; mm.seek(mm.tell()+3*nn*4)
155 for typ2,nbelem,dummy in m.getDistributionOfTypes():
157 if typ not in self.dictMCTyp:
158 typ=MEDCouplingMesh.GetCorrespondingPolyType(typ)
161 mm.write(self.__str80(self.dictMCTyp[typ]))
162 a=np.memmap(f,dtype='int32',mode='w+',offset=mm.tell(),shape=(1,))
163 a[0]=nbelem ; a.flush() ; mm.seek(mm.tell()+4)
164 if typ!=NORM_POLYHED and typ!=NORM_POLYGON:
165 nbNodesPerElem=MEDCouplingMesh.GetNumberOfNodesOfGeometricType(typ)
166 c=mp.getNodalConnectivity() ; c.rearrange(nbNodesPerElem+1) ; c=c[:,1:] ; c.rearrange(1) ; c+=1
167 a=np.memmap(f,dtype='int32',mode='w+',offset=mm.tell(),shape=(nbNodesPerElem*nbelem,))
168 a[:]=c.toNumPyArray() ; a.flush() ; mm.seek(mm.tell()+nbNodesPerElem*nbelem*4)
170 elif typ==NORM_POLYHED:
171 mp.orientCorrectlyPolyhedrons()
172 c=mp.computeNbOfFacesPerCell()
173 a=np.memmap(f,dtype='int32',mode='w+',offset=mm.tell(),shape=(nbelem,))
174 a[:]=c.toNumPyArray(); a.flush() ; mm.seek(mm.tell()+nbelem*4)
175 c=mp.getNodalConnectivity()[:] ; c.pushBackSilent(-1) ; c[mp.getNodalConnectivityIndex()[:-1]]=-1 ; ids=c.getIdsEqual(-1) ; nbOfNodesPerFace=ids.deltaShiftIndex()-1
176 a=np.memmap(f,dtype='int32',mode='w+',offset=mm.tell(),shape=(len(nbOfNodesPerFace),))
177 a[:]=nbOfNodesPerFace.toNumPyArray() ; a.flush() ; mm.seek(mm.tell()+len(nbOfNodesPerFace)*4)
178 ids2=ids.buildComplement(ids.back()+1)
179 c2=mp.getNodalConnectivity()[ids2]+1
180 a=np.memmap(f,dtype='int32',mode='w+',offset=mm.tell(),shape=(len(c2),))
181 a[:]=c2.toNumPyArray() ; a.flush() ; mm.seek(mm.tell()+len(c2)*4)
184 nbOfNodesPerCell=mp.getNodalConnectivityIndex().deltaShiftIndex()-1
185 a=np.memmap(f,dtype='int32',mode='w+',offset=mm.tell(),shape=(len(nbOfNodesPerCell),))
186 a[:]=nbOfNodesPerCell.toNumPyArray() ; a.flush() ; mm.seek(mm.tell()+len(nbOfNodesPerCell)*4)
187 ids2=mp.getNodalConnectivityIndex().buildComplement(mp.getNodalConnectivityIndex().back()+1)
188 c2=mp.getNodalConnectivity()[ids2]+1
189 a=np.memmap(f,dtype='int32',mode='w+',offset=mm.tell(),shape=(len(c2),))
190 a[:]=c2.toNumPyArray() ; a.flush() ; mm.seek(mm.tell()+len(c2)*4)
198 def __writeFieldsPart(self,mdfs):
202 its,areForgottenTS=mdfs.getCommonIterations()
204 print "WARNING : some iterations are NOT present in all fields ! Kept iterations are : %s !"%(str(its))
208 TimeValues+="%s\n"%(str(mdfs[0][it].getTime()[-1]))
212 nbCompo=mdf.getNumberOfComponents()
213 if nbCompo not in self.dictCompo:
214 l=filter(lambda x:x-nbCompo>0,self.dictCompo.keys())
216 print "Field \"%s\" will be ignored because number of components (%i) is too big to be %s supported by case files !"%(mdf.getName(),nbCompo,str(self.dictCompo.keys()))
219 print "WARNING : Field \"%s\" will have its number of components (%i) set to %i, in order to be supported by case files (must be in %s) !"%(mdf.getName(),nbCompo,l[0],str(self.dictCompo.keys()))
222 if nbCompo in dictVars:
223 dictVars[nbCompo].append(mdf)
226 dictVars[nbCompo]=[mdf]
230 nbCompo=mdf.getNumberOfComponents()
231 if nbCompo not in self.dictCompo:
232 l=filter(lambda x:x-nbCompo>0,self.dictCompo.keys())
237 for iii,it in enumerate(its):
239 isMultiDisc=len(ff.getTypesOfFieldAvailable())>1
240 for typ in ff.getTypesOfFieldAvailable():
241 l=self._l[:] ; l[-1]="%s%s.%s"%(self._base_name_without_dir,str(iii).rjust(4,"0"),ff.getName())
243 l[-1]="%s_%s"(l[-1],MEDCouplingFieldDiscretization.New(typ).getStringRepr())
247 os.remove(os.path.sep.join(l))
250 f=open(os.path.sep.join(l),"w+b")
252 for geo,[(curTyp,(bg,end),pfl,loc)] in ff.getFieldSplitedByType():
254 summ+=4*nbCompo*(end-bg)+80
257 a=np.memmap(f,dtype='byte',mode='w+',offset=0,shape=(2*80+4+summ,)) ; a.flush() # truncate to set the size of the file
258 mm=mmap.mmap(f.fileno(),offset=0,length=0)
261 k1="%s_%s"%(k1,MEDCouplingFieldDiscretization.New(typ).getStringRepr())
263 mm.write(self.__str80(k1))
264 mm.write(self.__str80("part"))
265 a=np.memmap(f,dtype='int32',mode='w+',offset=mm.tell(),shape=(1,))
266 a[0]=1 ; a.flush() ; mm.seek(mm.tell()+4) # part number maybe to change ?
267 for geo,[(curTyp,(bg,end),pfl,loc)] in ff.getFieldSplitedByType():
269 raise Exception("Field \"%s\" contains profiles ! Profiles are not supported yet !"%(mdf.getName()))
271 arr=ff.getUndergroundDataArray()[bg:end].changeNbOfComponents(nbCompo,0.) ; arr=arr.toNoInterlace()
273 mm.write(self.__str80(self.dictMCTyp[geo]))
276 mm.write(self.__str80("coordinates"))
279 print "UnManaged type of field for field \"%s\" !"%(mdf.getName())
281 a=np.memmap(f,dtype='float32',mode='w+',offset=mm.tell(),shape=(nbCompo,end-bg))
282 b=arr.toNumPyArray() ; b=b.reshape(nbCompo,end-bg)
284 a.flush() ; mm.seek(mm.tell()+nbCompo*(end-bg)*4)
287 k="%s per %s"%(self.dictCompo[nbCompo],self.discSpatial[typ])
288 if k in self._ze_top_dict:
289 if k1 in self._ze_top_dict[k]:
290 self._ze_top_dict[k][k1].append(fffn)
293 self._ze_top_dict[k][k1]=[fffn]
296 self._ze_top_dict[k]={k1:[fffn]}
302 if len(self._ze_top_dict)!=0:
303 hvp=self.header_varpart[:]
304 for k in self._ze_top_dict:
305 for k1 in self._ze_top_dict[k]:
306 hvp+="\n%s: %s %s"%(k,k1,re.sub("([\d]{4})",4*"*",self._ze_top_dict[k][k1][0]))
312 ddd={"NbTimeSteps":len(its),"TimeValues":TimeValues}
313 htp=self.header_timepart%ddd
321 raise Exception("String \"%s\" is too long (>79) !"%(st))
322 return st.ljust(79)+"\n"
324 def __computeSizeOfGeoFile(self,listOfMeshes,nn):
326 for m in listOfMeshes:
327 distribTypes=m.getDistributionOfTypes()
328 sz+=80+4+2*80+4+nn*3*4
330 for typ2,nbelem,dummy in distribTypes:
332 if typ not in self.dictMCTyp:
333 typ=MEDCouplingMesh.GetCorrespondingPolyType()
335 if typ!=NORM_POLYHED and typ!=NORM_POLYGON:
336 sz+=80+4+MEDCouplingMesh.GetNumberOfNodesOfGeometricType(typ)*nbelem*4
338 elif typ==NORM_POLYHED:
339 mplh=m[i:i+nbelem] ; delta=len(mplh.getNodalConnectivity())+nbelem
343 mplh=m[i:i+nbelem] ; delta=len(mplh.getNodalConnectivity())