medcoupling 9.13.0__cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
CaseWriter.py ADDED
@@ -0,0 +1,349 @@
1
+ # -*- coding: iso-8859-1 -*-
2
+ # Copyright (C) 2007-2024 CEA, EDF
3
+ #
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, or (at your option) any later version.
8
+ #
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.
13
+ #
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
17
+ #
18
+ # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19
+ #
20
+ # Author : Anthony GEAY (CEA/DEN/DM2S/STMF/LGLS)
21
+
22
+ import numpy as np
23
+ from CaseIO import CaseIO
24
+ from MEDLoader import *
25
+ import sys,re,os,mmap
26
+
27
+ ### www-vis.lbl.gov/NERSC/Software/ensight/doc/OnlineHelp/UM-C11.pdf
28
+
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 dependencies (.geo ...).
32
+ """
33
+
34
+ header="""FORMAT
35
+ type: ensight gold
36
+ GEOMETRY
37
+ model: %(geofilewithoutpath)s
38
+ """
39
+ header_varpart="""VARIABLE"""
40
+ header_timepart="""TIME
41
+ time set: 1
42
+ number of steps: %(NbTimeSteps)i
43
+ filename start number: 0
44
+ filename increment: 1
45
+ time values:
46
+ %(TimeValues)s
47
+ """
48
+
49
+ @classmethod
50
+ def New(cls):
51
+ """ Static constructor. """
52
+ return CaseWriter()
53
+ pass
54
+
55
+ def __init__(self):
56
+ """ Constructor """
57
+ self.__export_groups=False
58
+ pass
59
+
60
+ def setMEDFileDS(self,medData):
61
+ """ Input should be MEDFileData instance """
62
+ self._med_data=medData
63
+ pass
64
+
65
+ def isExportingGroups(self):
66
+ """ return the status of exporting groups policy """
67
+ return self.__export_groups
68
+
69
+ def setExportingGroups(self,status):
70
+ assert(isinstance(status,bool))
71
+ self.__export_groups=status
72
+ pass
73
+
74
+
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=[]
82
+ self._dico={}
83
+ for mesh in self._med_data.getMeshes():
84
+ additionnalFileNamePart=""
85
+ if len(self._med_data.getMeshes())!=1:
86
+ additionnalFileNamePart="_%s"%(mesh.getName())
87
+ pass
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))
91
+ #
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)
96
+ pass
97
+ return self._real_written_file_name
98
+
99
+ def __writeMeshesPart(self,mdm,meshfn):
100
+ try:
101
+ os.remove(meshfn)
102
+ except:
103
+ pass
104
+ f=open(meshfn,"w+b")
105
+ sz=5*80
106
+ #
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():
111
+ ms3=[]
112
+ for lev in mdm.getGrpNonEmptyLevels(grpnm)[:1]:
113
+ m=mdm.getGroup(lev,grpnm) ; m.zipCoords()
114
+ ms3.append(m)
115
+ pass
116
+ ms2.append(ms3)
117
+ pass
118
+ pass
119
+ for ms in ms2:
120
+ nn=ms[0].getNumberOfNodes()
121
+ sz+=self.__computeSizeOfGeoFile(ms,nn)
122
+ pass
123
+ pass
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 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 ?
136
+ name=ms[0].getName()
137
+ if iii>0:
138
+ name="%s_%s"%(ms2[0][0].getName(),name)
139
+ pass
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
144
+ mm.seek(mm.tell()+4)
145
+ coo=ms[0].getCoords()
146
+ spaceDim=coo.getNumberOfComponents()
147
+ if spaceDim!=3:
148
+ coo=coo.changeNbOfComponents(3,0.)
149
+ pass
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)
153
+ for m in ms:
154
+ i=0
155
+ for typ2,nbelem,dummy in m.getDistributionOfTypes():
156
+ typ=typ2
157
+ if typ not in self.dictMCTyp:
158
+ typ=MEDCouplingMesh.GetCorrespondingPolyType(typ)
159
+ pass
160
+ mp=m[i:i+nbelem]
161
+ mm.write(self.__str80(self.dictMCTyp_str[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)
169
+ pass
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.findIdsEqual(-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)
182
+ pass
183
+ else:
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)
191
+ pass
192
+ i+=nbelem
193
+ pass
194
+ pass
195
+ pass
196
+ pass
197
+
198
+ def __writeFieldsPart(self,mdfs):
199
+ if not mdfs:
200
+ return ""
201
+ self._ze_top_dict={}
202
+ its,areForgottenTS=mdfs.getCommonIterations()
203
+ if areForgottenTS:
204
+ print(("WARNING : some iterations are NOT present in all fields ! Kept iterations are : %s !"%(str(its))))
205
+ pass
206
+ TimeValues=""
207
+ for it in its:
208
+ TimeValues+="%s\n"%(str(mdfs[0][it].getTime()[-1]))
209
+ pass
210
+ dictVars={}
211
+ for mdf in mdfs:
212
+ nbCompo=mdf.getNumberOfComponents()
213
+ if nbCompo not in self.dictCompo:
214
+ l = [x for x in self.dictCompo if x - nbCompo > 0]
215
+ if len(l)==0:
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(list(self.dictCompo.keys())))))
217
+ continue
218
+ pass
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(list(self.dictCompo.keys())))))
220
+ nbCompo=l[0]
221
+ pass
222
+ if nbCompo in dictVars:
223
+ dictVars[nbCompo].append(mdf)
224
+ pass
225
+ else:
226
+ dictVars[nbCompo]=[mdf]
227
+ pass
228
+ pass
229
+ for mdf in mdfs:
230
+ nbCompo=mdf.getNumberOfComponents()
231
+ if nbCompo not in self.dictCompo:
232
+ l = [x for x in self.dictCompo if x - nbCompo > 0]
233
+ if len(l)==0:
234
+ continue;
235
+ nbCompo=l[0]
236
+ pass
237
+ for iii,it in enumerate(its):
238
+ ff=mdf[it]
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())
242
+ if isMultiDisc:
243
+ l[-1]="%s_%s"(l[-1],MEDCouplingFieldDiscretization.New(typ).getStringRepr())
244
+ pass
245
+ fffn=l[-1]
246
+ try:
247
+ os.remove(os.path.sep.join(l))
248
+ except:
249
+ pass
250
+ f=open(os.path.sep.join(l),"w+b")
251
+ summ=0
252
+ for geo,[(curTyp,(bg,end),pfl,loc)] in ff.getFieldSplitedByType():
253
+ if typ==curTyp:
254
+ summ+=4*nbCompo*(end-bg)+80
255
+ pass
256
+ pass
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)
259
+ k1=ff.getName()
260
+ if isMultiDisc:
261
+ k1="%s_%s"%(k1,MEDCouplingFieldDiscretization.New(typ).getStringRepr())
262
+ pass
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():
268
+ if pfl!="":
269
+ raise Exception("Field \"%s\" contains profiles ! Profiles are not supported yet !"%(mdf.getName()))
270
+ if typ==curTyp:
271
+ arr=ff.getUndergroundDataArray()[bg:end].changeNbOfComponents(nbCompo,0.) ; arr=arr.toNoInterlace()
272
+ if typ==ON_CELLS:
273
+ mm.write(self.__str80(self.dictMCTyp_str[geo]))
274
+ pass
275
+ elif typ==ON_NODES:
276
+ mm.write(self.__str80("coordinates"))
277
+ pass
278
+ else:
279
+ print(("UnManaged type of field for field \"%s\" !"%(mdf.getName())))
280
+ pass
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)
283
+ a[:]=b
284
+ a.flush() ; mm.seek(mm.tell()+nbCompo*(end-bg)*4)
285
+ pass
286
+ pass
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)
291
+ pass
292
+ else:
293
+ self._ze_top_dict[k][k1]=[fffn]
294
+ pass
295
+ else:
296
+ self._ze_top_dict[k]={k1:[fffn]}
297
+ pass
298
+ pass
299
+ pass
300
+ pass
301
+ headerPart=""
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]))
307
+ pass
308
+ pass
309
+ hvp+="\n"
310
+ headerPart+=hvp
311
+ #
312
+ ddd={"NbTimeSteps":len(its),"TimeValues":TimeValues}
313
+ htp=self.header_timepart%ddd
314
+ headerPart+=htp
315
+ pass
316
+ return headerPart
317
+
318
+ @classmethod
319
+ def __str80(cls,st):
320
+ if len(st)>79:
321
+ raise Exception("String \"%s\" is too long (>79) !"%(st))
322
+ return bytes(str(st).ljust(79)+"\n", "ascii")
323
+
324
+ def __computeSizeOfGeoFile(self,listOfMeshes,nn):
325
+ sz=0
326
+ for m in listOfMeshes:
327
+ distribTypes=m.getDistributionOfTypes()
328
+ sz+=80+4+2*80+4+nn*3*4
329
+ i=0
330
+ for typ2,nbelem,dummy in distribTypes:
331
+ typ=typ2
332
+ if typ not in self.dictMCTyp:
333
+ typ=MEDCouplingMesh.GetCorrespondingPolyType()
334
+ pass
335
+ if typ!=NORM_POLYHED and typ!=NORM_POLYGON:
336
+ sz+=80+4+MEDCouplingMesh.GetNumberOfNodesOfGeometricType(typ)*nbelem*4
337
+ pass
338
+ elif typ==NORM_POLYHED:
339
+ mplh=m[i:i+nbelem] ; delta=len(mplh.getNodalConnectivity())+nbelem
340
+ sz+=80+4+delta*4
341
+ pass
342
+ else:
343
+ mplh=m[i:i+nbelem] ; delta=len(mplh.getNodalConnectivity())
344
+ sz+=80+4+delta*4
345
+ pass
346
+ i+=nbelem
347
+ pass
348
+ pass
349
+ return sz