Salome HOME
Merge branch 'V8_3_BR' into ngr/python3_dev
[modules/smesh.git] / src / Tools / ZCracksPlug / main.py
1 import sys, pickle, tempfile, shutil
2 from os import path, getpid, environ, remove, system
3
4 from PyQt5.QtCore import *
5 from PyQt5.QtGui import *
6 from PyQt5.QtWidgets import *
7
8 from . import utilityFunctions as uF
9 from . import genereCrack, Zset, output, zcracks_ui
10
11 from .output import message, init
12 from .zcracks_ui import Ui_Zui
13
14
15 #  ---------------------
16 #    FONCTIONS ANNEXES
17 #  ---------------------
18
19
20 def stringToFloat(string, typ=float):
21   if str(string).replace(' ','')=='':
22     out=[]
23   else:
24     out=list(map(typ, str(string).split()))
25   return(out)
26
27 def addExtension(string, extension):
28   cond=True
29   strLen=len(string)
30   if strLen<1:
31     out=None
32   else:
33     start=0
34     lastPt=0
35     while cond:
36       res=string.find('.',start)
37       if res==-1:
38         cond=False
39       else:
40         lastPt=res
41         start=res+1
42     if strLen<=(lastPt+1+5) and lastPt!=0:
43       out=string[:(lastPt+1)]+extension.replace('.','')
44     else:
45       out=string+'.'+extension.replace('.','')
46   return(out)
47
48
49 #  ----------------------------
50 #    DEFINITION DE LA CLASSE
51 #  ----------------------------
52 class ShipHolderApplication(QGroupBox):
53
54   def __init__(self, parent=None):
55     super (ShipHolderApplication, self).__init__(parent)
56
57     self.salomeVers=path.normpath(environ['ROOT_SALOME'])
58     self.salomeVers=path.split(self.salomeVers)[-1].split('V')[-1]
59
60     self.createWidgets()
61     self.data=dict()
62     self.GroupToLoad=None
63     self.ui.widget.setVisible(False)
64     self.tmpdir=tempfile.mkdtemp()
65     self.saneGeoName=path.join(self.tmpdir,'salome_sane.geo')
66     self.crackGeoName=path.join(self.tmpdir,'salome_crack.geo')
67     self.crackMedName=path.join(self.tmpdir,'salome_crack.med')
68     self.crackedGeoName=path.join(self.tmpdir,'cracked.geo')
69
70     global log
71     init(self.tmpdir)
72
73     self.verbose=1
74
75     self.ui.CBQuad.toggled.connect(self.pressQuad)
76     self.ui.btReset.clicked.connect(self.pressReset)
77     self.ui.btCancel.clicked.connect(self.pressCancel)
78     self.ui.btApply.clicked.connect(self.pressApply)
79     self.ui.btApplyClose.clicked.connect(self.pressApplyClose)
80     self.ui.btLoad.clicked.connect(self.pressCharger)
81     self.ui.btSave.clicked.connect(self.pressSauver)
82     self.ui.btLoadCracked.clicked.connect(self.pressLoadCracked)
83     self.ui.btLoadSane.clicked.connect(self.pressLoadSane)
84
85     self.ui.btGrVol.clicked.connect(self.pressLoadGroupVOL)
86     self.ui.btGrFace.clicked.connect(self.pressLoadGroupFACE)
87     self.ui.btGrEdge.clicked.connect(self.pressLoadGroupEDGE)
88     self.ui.btGrNode.clicked.connect(self.pressLoadGroupNODE)
89     self.ui.btGrAll.clicked.connect(self.pressLoadGroupALL)
90     self.ui.btVisu.clicked.connect(self.pressVisu)
91
92     self.ui.CBAdvanced.toggled.connect(self.pressAdvanced)
93     self.lineEditTypes=[str, str, float,
94                         float, float, str,
95                         str, str, str,
96                         float, int, int,
97                         str]
98
99     self.lineEditNames=['crackedName','saneName','minSize',
100                         'maxSize','extractLength','grVol',
101                         'grFace','grEdge','grNodes',
102                         'gradation','iterations','layers',
103                         'surfopt']
104
105     self.lineEditObjects=[self.ui.valCrackedName,self.ui.valSaneName,self.ui.valMinSize,
106                      self.ui.valMaxSize,self.ui.valExtractLength,self.ui.valGrVol,
107                      self.ui.valGrFace,self.ui.valGrEdge,self.ui.valGrNode,
108                      self.ui.valGradation,self.ui.valIterations,self.ui.valLayers,
109                      self.ui.valSurfopt]
110
111   def createWidgets(self):
112     self.ui = Ui_Zui()
113     self.ui.setupUi(self)
114
115 #  -----------------------------------
116 #    FONCTIONS D'ACTIONS DES BOUTONS
117 #  -----------------------------------
118
119   def pressQuad(self):
120     if self.ui.CBQuad.isChecked():
121       self.ui.CBBarsoum.setEnabled(True)
122       self.ui.valGradation.setText('2.3')
123     else:
124       self.ui.valGradation.setText('1.3')
125       self.ui.CBBarsoum.setChecked(False)
126       self.ui.CBBarsoum.setEnabled(False)
127
128
129   def pressReset(self):
130     for val in self.lineEditObjects:
131       val.clear()
132     self.ui.CBQuad.setChecked(False)
133     self.ui.CBBarsoum.setChecked(False)
134     nbOnglet=self.ui.tabWidget.count()
135     for iongl in range(nbOnglet):
136       onglet=self.ui.tabWidget.widget(iongl)
137       tab=onglet.findChildren(QTableWidget)[0]
138       for irow in range(tab.rowCount()):
139         if tab.item(irow,0) != None:
140           tab.item(irow,0).setText('')
141     self.ui.valGradation.setText('1.3')
142     self.ui.valLayers.setText('6')
143     self.ui.valIterations.setText('2')
144     self.ui.CBIs2D.setChecked(False)
145     self.ui.CBRefine.setChecked(False)
146
147
148   def pressApply(self):
149     message('M','\n\n -------------')
150     message('M','  Nouveau cas  ')
151     message('M',' -------------')
152     message('M','Getting parameters and checking ...')
153     self.getParameters()
154     test=uF.check(self.data)
155     self.cleanTmpFiles()
156
157     if test:
158       message('M','Parameters checked and ready to go')
159     else:
160       message('E','Parameters checking failled',goOn=True)
161       return()
162
163     message('M','\nGenerating crack ...')
164     res=genereCrack.main(self.data, self.crackMedName)
165     if res:
166       message('M','Crack generated successfully')
167     else:
168       message('E','Crack generation failed',goOn=True)
169       return()
170
171     if self.ui.CBIs2D.isChecked():
172       res=Zset.medToGeo(self.data['saneName'],self.saneGeoName, self.tmpdir, verbose=self.verbose, opt=['  **to_3d'])
173     else:
174       res=Zset.medToGeo(self.data['saneName'],self.saneGeoName, self.tmpdir, verbose=self.verbose)
175
176     if res!=0:
177       message('E','medToGeo sane failed',goOn=True)
178       return()
179
180     #opt=['**elset crack *function 1.;','**elset elset0 *function 1.;']
181     res=Zset.medToGeo(self.crackMedName,self.crackGeoName, self.tmpdir, verbose=self.verbose)
182     if res!=0:
183       message('E','medToGeo crack failed',goOn=True)
184       return()
185
186     names={'saneGeoName':self.saneGeoName, 'crackGeoName':self.crackGeoName, 'crackedGeoName':self.crackedGeoName}
187     message('M','\nInserting crack ...')
188     res=Zset.insertCrack(self.data, names, self.tmpdir, verbose=self.verbose)
189     if res!=0:
190       message('E','Crack insertion failed',goOn=True)
191       return()
192     else:
193       message('M','Crack inserted successfully')
194
195     if self.ui.CBQuad.isChecked() and self.ui.CBBarsoum.isChecked():
196       message('M','\nSaving cracked mesh in quadratic with Barsoum elements...')
197       opt=['  **lin_to_quad','  **crack_3d_quarter_nodes','   *liset FRONT0']
198       res=Zset.geoToMed(self.data['crackedName'], names['crackedGeoName'], self.tmpdir, opt=opt, verbose=self.verbose)
199
200     elif self.ui.CBQuad.isChecked() and not self.ui.CBBarsoum.isChecked():
201       message('M','\nSaving cracked mesh in quadratic...')
202       opt=['  **lin_to_quad']
203       res=Zset.geoToMed(self.data['crackedName'], names['crackedGeoName'], self.tmpdir, opt=opt, verbose=self.verbose)
204
205     else:
206       message('M','\nSaving cracked mesh...')
207       res=Zset.geoToMed(self.data['crackedName'], names['crackedGeoName'], self.tmpdir, verbose=self.verbose)
208
209     uF.extendElsets(self.data['crackedName'])
210
211     if res==0:
212       message('M','Cracked mesh ready at : %s' %(self.data['crackedName']))
213       message('M','Maximal aspect ratio is %f' %(uF.getMaxAspectRatio(self.tmpdir)))
214       #message('M','medit %s/_mesh_out_to_ghs3d.mesh' %(self.tmpdir))
215       message('M','\n ----------------')
216       message('M','    Fin cas OK   ')
217       message('M',' ----------------')
218
219
220
221   def pressApplyClose(self):
222     self.pressApply()
223     self.pressCancel()
224
225
226   def pressLoadCracked(self):
227     fileDiag = QFileDialog(self)
228     fileDiag.setFileMode(QFileDialog.AnyFile)
229     fileDiag.setNameFilters(["Parametres *.med (*.*med)","All files (*)"])
230     fileDiag.setViewMode(QFileDialog.List)
231     if fileDiag.exec_() :
232       fileNames = fileDiag.selectedFiles()
233       filedef = fileNames[0]
234       filedef = addExtension(str(filedef), 'med')
235       self.ui.valCrackedName.setText(filedef)
236
237
238   def pressLoadSane(self):
239     fileDiag = QFileDialog(self)
240     fileDiag.setFileMode(QFileDialog.AnyFile)
241     fileDiag.setNameFilters(["Parametres *.med (*.*med)","All files (*)"])
242     fileDiag.setViewMode(QFileDialog.List)
243     if fileDiag.exec_() :
244       fileNames = fileDiag.selectedFiles()
245       filedef = fileNames[0]
246       self.ui.valSaneName.setText(filedef)
247
248
249   def pressCharger(self):
250     fileDiag = QFileDialog(self)
251     fileDiag.setFileMode(QFileDialog.AnyFile)
252     fileDiag.setNameFilters(["Parametres *.dic (*.dic)","All files (*)"])
253     fileDiag.setViewMode(QFileDialog.List)
254
255     if fileDiag.exec_() :
256       fileNames = fileDiag.selectedFiles()
257       filedef = fileNames[0]
258       if not path.isfile(str(filedef)):
259         message('E','Invalid dic file')
260       self.data=pickle.load(open(str(filedef),'r'))
261       message('M','\nLoading parameters from %s' %str(filedef))
262
263       for cont, obj in enumerate(self.lineEditObjects):
264         if self.lineEditTypes[cont] in [float, int]:
265           obj.setText(self.data['TXT'+self.lineEditNames[cont]])
266         else:
267           obj.setText(self.data[self.lineEditNames[cont]])
268
269       self.ui.CBQuad.setChecked(True if 'quad' in list(self.data.keys()) and self.data['quad'] else False)
270       self.ui.CBBarsoum.setChecked(True if 'barsoum' in list(self.data.keys()) and self.data['barsoum'] else False)
271       self.ui.CBIs2D.setChecked(True if 'is2D' in list(self.data.keys()) and self.data['is2D'] else False)
272       self.ui.CBRefine.setChecked(True if 'refine' in list(self.data.keys()) and self.data['refine'] else False)
273
274       self.setTableParameters()
275
276
277   def pressSauver(self):
278     fileDiag = QFileDialog(self)
279     fileDiag.setFileMode(QFileDialog.AnyFile)
280     fileDiag.setNameFilters(["Parametres *.dic (*.dic)","All files (*)"])
281     fileDiag.setViewMode(QFileDialog.List)
282     if fileDiag.exec_() :
283       self.getParameters()
284       fileNames = fileDiag.selectedFiles()
285       filedef = fileNames[0]
286       pickle.dump(self.data, open(addExtension(str(filedef), 'dic'),'w'))
287       message('M','Saving parameters in %s' %addExtension(str(filedef), 'dic'))
288
289   def pressLoadGroupVOL(self):
290     try:
291       self.GroupToLoad='VOL'
292       self.loadGroups()
293     except:
294       message('E','Groups loading impossible',goOn=True)
295
296   def pressLoadGroupFACE(self):
297     try:
298       self.GroupToLoad='FACE'
299       self.loadGroups()
300     except:
301       message('E','Groups loading impossible',goOn=True)
302
303   def pressLoadGroupEDGE(self):
304     try:
305       self.GroupToLoad='EDGE'
306       self.loadGroups()
307     except:
308       message('E','Groups loading impossible',goOn=True)
309
310   def pressLoadGroupNODE(self):
311     try:
312       self.GroupToLoad='NODE'
313       self.loadGroups()
314     except:
315       message('E','Groups loading impossible',goOn=True)
316
317   def pressLoadGroupALL(self):
318     try:
319       self.GroupToLoad='ALL'
320       self.loadGroups()
321     except:
322       message('E','Groups loading impossible',goOn=True)
323
324   def pressAdvanced(self):
325     if self.ui.CBAdvanced.isChecked():
326       self.ui.widget.setVisible(True)
327     else:
328       self.ui.widget.setVisible(False)
329
330   def pressVisu(self):
331     meshFile1=path.join(self.tmpdir,'_mesh_out_to_ghs3d.mesh')
332     meshFile2=path.join(self.tmpdir,'_mesh_out_.mesh')
333     test1=path.isfile(meshFile1)
334     test2=path.isfile(meshFile2)
335     medit=path.join('$Z7PATH/PUBLIC/lib-Linux_64/Zmesh/bin/medit')
336     if not test1:
337       if not test2:
338         message('A','No mesh file to visualize')
339       else:
340         print(medit+' %s' %meshFile2)
341         system(medit+' %s' %meshFile2)
342     else:
343       print(medit+' %s' %meshFile1)
344       system(medit+' %s' %meshFile1)
345     return()
346
347   def pressCancel(self):
348     message('M','exiting Zcracks')
349     try:
350       shutil.rmtree(self.tmpdir)
351     except:
352       message('E','Impossible to delete %s' %self.tmpdir,goOn=True)
353       pass
354     exit()
355
356 #  ---------------------------------
357 #    FONCTIONS ANNEXES A LA CLASSE
358 #  ---------------------------------
359
360
361   def getParameters(self):
362     for cont, name in enumerate(self.lineEditNames):
363       value=str(self.lineEditObjects[cont].text())
364       #print name
365       if self.lineEditTypes[cont] == float:
366         self.data['TXT'+name]=value
367         self.data[name]= stringToFloat(value)
368       elif self.lineEditTypes[cont] == int:
369         self.data['TXT'+name]=value
370         self.data[name]= stringToFloat(value, typ=int)
371       else:
372         self.data[name]=value
373     self.data['quad']=self.ui.CBQuad.isChecked()
374     self.data['barsoum']=self.ui.CBBarsoum.isChecked()
375     self.data['TXTcrack']=self.getTableParameters()
376     self.data['crack']=self.getTableParameters(str2float=True)
377     self.data['is2D']=self.ui.CBIs2D.isChecked()
378     self.data['refine']=self.ui.CBRefine.isChecked()
379
380
381   def getTableParameters(self, str2float=False):
382     nbOnglet=self.ui.tabWidget.count()
383     out=dict()
384     iOngletActif=self.ui.tabWidget.currentIndex()
385     ongletActif=False
386     for iongl in range(nbOnglet):
387       crack=dict()
388       onglet=self.ui.tabWidget.widget(iongl)
389       tab=onglet.findChildren(QTableWidget)[0]
390       for irow in range(tab.rowCount()):
391         label=tab.verticalHeaderItem(irow).text()
392         if tab.item(irow,0) is None:
393           crack[str(label)]=''
394         elif 'med file' in str(label):
395           crack[str(label)]=str(tab.item(irow,0).text())
396         else:
397           value=tab.item(irow,0).text()
398           if str2float:
399             crack[str(label)]=stringToFloat(value)
400           else:
401             crack[str(label)]=str(value)
402       out[str(self.ui.tabWidget.tabText(iongl))]=crack
403       if iongl==iOngletActif:
404         ongletActif=str(self.ui.tabWidget.tabText(iongl))
405
406     out['actif']=ongletActif
407     return(out)
408
409
410   def setTableParameters(self):
411     nbOnglet=self.ui.tabWidget.count()
412     #iOngletActif=self.ui.tabWidget.currentIndex()
413     for iongl in range(nbOnglet):
414       onglet=self.ui.tabWidget.widget(iongl)
415       tab=onglet.findChildren(QTableWidget)[0]
416       for irow in range(tab.rowCount()):
417         label=tab.verticalHeaderItem(irow).text()
418         if tab.item(irow,0) == None:
419           item = QTableWidgetItem()
420           tab.setItem(irow, 0, item)
421         tab.item(irow,0).setText(self.data['TXTcrack'][str(self.ui.tabWidget.tabText(iongl))][str(label)])
422       if str(self.ui.tabWidget.tabText(iongl)) == self.data['TXTcrack']['actif']:
423         self.ui.tabWidget.setCurrentWidget(onglet)
424
425
426   def loadGroups(self):
427     saneFile=str(self.ui.valSaneName.text())
428     message('I','Loading Sane mesh...')
429     if not path.isfile(saneFile):
430       message('E','Sane mesh med file is not valid')
431     else:
432       import SMESH, salome
433       #salome.salome_init()
434       theStudy = salome.myStudy
435       from salome.smesh import smeshBuilder
436       smesh = smeshBuilder.New(theStudy)
437
438       ([objetSain], status) = smesh.CreateMeshesFromMED(saneFile)
439
440       groupsVOL, groupsFAC, groupsEDG, groupsNOD = '', '', '', ''
441       nGr=0
442
443       for group in objetSain.GetGroups():
444         if (self.GroupToLoad in ['VOL','ALL']) and (group.GetType()==SMESH.VOLUME):
445           groupsVOL+=self.cleanGroupName(group)
446           nGr+=1
447
448         if (self.GroupToLoad in ['FACE','ALL']) and (group.GetType()==SMESH.FACE):
449           groupsFAC+=self.cleanGroupName(group)
450           nGr+=1
451
452         if (self.GroupToLoad in ['EDGE','ALL']) and (group.GetType()==SMESH.EDGE):
453           groupsEDG+=self.cleanGroupName(group)
454           nGr+=1
455
456         if (self.GroupToLoad in ['NODE','ALL']) and (group.GetType()==SMESH.NODE):
457           groupsNOD+=self.cleanGroupName(group)
458           nGr+=1
459
460       if groupsVOL!='':  self.ui.valGrVol.setText(groupsVOL)
461       if groupsFAC!='': self.ui.valGrFace.setText(groupsFAC)
462       if groupsEDG!='': self.ui.valGrEdge.setText(groupsEDG)
463       if groupsNOD!='': self.ui.valGrNode.setText(groupsNOD)
464
465       message('I','%d group(s) found' %nGr)
466
467   def cleanTmpFiles(self):
468     for f in [self.saneGeoName, self.crackGeoName, self.crackMedName, self.crackedGeoName]:
469       try:
470         remove(f)
471       except:
472         pass
473         
474   def cleanGroupName(self, group):
475     name=group.GetName()
476     while name.endswith(' '): name=name[:-1]
477     if ' ' in name: 
478       message('A','%s group has a space in its name --> ignored' %name)
479       return('')
480     else:
481       return(name+" ")
482       
483   def checkNamesSpaces(self, names):
484     if type(names) is str: names=[names]
485     ok=True
486     for n in names:
487       if ' ' in n:
488         message('E','%s has a space in its name, please remove it' %n, goOn=True)
489         ok=False
490     return(ok)
491
492
493 #  ---------------------------------
494 #    LANCEMENT DE LA BOITE DE DIAG
495 #  ---------------------------------
496
497
498
499