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