Salome HOME
Copyright update 2020
[plugins/ghs3dprlplugin.git] / src / tepal2med / tetrahpc2med.cxx
1 // Copyright (C) 2007-2020  CEA/DEN, 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 // ---
21 // File   : tetrahpc2med.cxx
22 // Author : Christian VAN WAMBEKE (CEA) 
23 // ---
24 //
25 /*
26 ** prog principal de ghs3dprl
27 */
28
29 #include <stdio.h> /* printf clrscr fopen fread fwrite fclose */
30 #include <string>
31 #include <cstring>
32 #include <cstdlib>
33 #include <iostream>
34 #include <sstream>
35 #include <fstream>
36 #include <vector>
37 #ifndef WIN32
38 #include <unistd.h>
39 #endif
40
41 #include <qstring.h>
42
43 #include <QXmlSimpleReader>
44 #include <QXmlInputSource>
45 #include <QApplication>
46
47 #include "ghs3dprl_msg_parser.h"
48 //#include "dlg_ghs3dmain.h"
49
50 #ifdef WIN32
51 #include <io.h>
52 #include <windows.h>
53 #define F_OK 0
54 #endif
55
56 //#include "MEDMEM_Exception.hxx"
57 //#include "MEDMEM_define.hxx"
58
59 #include <med.h>
60 //#include <med_config.h>
61 //#include <med_utils.h>
62 //#include <med_misc.h>
63
64 //************************************
65 med_idt ouvre_fichier_MED(char *fichier,int verbose)
66 {
67   med_idt fid = 0;
68   med_err ret = 0;
69   med_int majeur,mineur,release;
70
71   /* on regarde si le fichier existe */
72   ret = (int) access(fichier,F_OK);
73   if (ret < 0) return fid;
74
75   /* on regarde s'il s'agit d'un fichier au format HDF5 */
76   med_bool hdfok,medok;
77   ret = MEDfileCompatibility(fichier,&hdfok,&medok);
78   if (ret < 0){
79      std::cerr<<"File "<<fichier<<" not MED or HDF V5 formatted\n";
80      return fid;
81   }
82
83   /* Quelle version de MED est utilise par mdump ? */
84   MEDlibraryNumVersion(&majeur,&mineur,&release);
85   if (verbose>0)fprintf(stdout,"\nReading %s with MED V%d.%d.%d",
86                         fichier,majeur,mineur,release);
87
88   /* Ouverture du fichier MED en lecture seule */
89   fid = MEDfileOpen(fichier,MED_ACC_RDONLY);
90   if (ret < 0) return fid;
91
92   MEDfileNumVersionRd(fid, &majeur, &mineur, &release);
93   if (( majeur < 2 ) || ( majeur == 2 && mineur < 2 )) {
94     fprintf(stderr,"File %s from MED V%d.%d.%d not assumed\n",
95                    fichier,majeur,mineur,release);
96     //" version est ant�ieure �la version 2.2";
97     ret = MEDfileClose(fid);
98     fid=0; }
99   else {
100     if (verbose>0)fprintf(stdout,", file from MED V%d.%d.%d\n",majeur,mineur,release); }
101
102   return fid;
103 }
104
105 //************************************
106 bool ReadFileMED(QString nomfilemed,ghs3dprl_mesh_wrap *mymailw)
107 {
108    med_err ret;
109    med_idt fid=0;
110    med_int i,j,sdim,mdim,nmaa,/*edim,majeur_lu,mineur_lu,release_lu,nprofils,*/nstep;
111    med_mesh_type type_maillage;
112    char dtunit[MED_SNAME_SIZE+1];
113    char axisname[MED_SNAME_SIZE+1];
114    char axisunit[MED_SNAME_SIZE*3+1];
115    med_sorting_type sortingtype;
116    med_axis_type axistype;
117    int numero=1;
118    QString key,tmp;
119    med_bool chan;
120    med_bool tran;
121    
122    //version qt3
123    char* chaine = (char*)malloc((nomfilemed.length()+1)*sizeof(char));
124    strncpy(chaine,nomfilemed.toLatin1().constData(),nomfilemed.length()+1);
125    //std::cout<<"*** ReadFileMED *** "<<chaine<<"\n";
126
127    fid=ouvre_fichier_MED(chaine,mymailw->verbose);
128    free(chaine);
129    if (fid == 0) {
130       std::cerr<<"Problem opening file "<<nomfilemed.toLatin1().constData()<<"\n";
131       return false;
132    }
133
134    nmaa = MEDnMesh(fid);
135    if (nmaa <= 0){
136       std::cerr<<"No meshes in "<<nomfilemed.toLatin1().constData()<<"\n";
137       ret = MEDfileClose(fid);
138       return false;
139    }
140    if (nmaa > 1) std::cout<<"More than one mesh in "<<nomfilemed.toLatin1().constData()<<", first one taken\n";
141    ret = MEDmeshInfo(fid,numero,mymailw->nommaa,&sdim,&mdim,&type_maillage,mymailw->maillage_description,
142                         dtunit,&sortingtype,&nstep,&axistype,axisname,axisunit);
143    if (ret < 0){
144       std::cerr<<"Problem MEDmeshInfo in "<<nomfilemed.toLatin1().constData()<<"\n";
145       ret = MEDfileClose(fid);
146       return false;
147    }
148    //changed with version med: a triangles mesh in 3d is dim 2 now and 3 before 2014
149    if (mdim != 2 && mdim != 3){
150       std::cerr<<"Problem mesh dimension should be 2 or 3: "<<mdim<<"\n";
151       ret = MEDfileClose(fid);
152       return false;
153    }
154    if (sdim != 3){
155       std::cerr<<"Problem space dimension should be 3: "<<sdim<<"\n";
156       ret = MEDfileClose(fid);
157       return false;
158    }
159    if (type_maillage != MED_UNSTRUCTURED_MESH){
160       std::cerr<<"Problem type mesh should be MED_NON_STRUCTURE: "<<type_maillage<<std::endl;
161       ret = MEDfileClose(fid);
162       return false;
163    }
164
165    //lecture nb de noeuds
166    //cf med-3.0.0_install/share/doc/html/maillage_utilisateur.html
167    med_int nnoe=MEDmeshnEntity(fid,mymailw->nommaa,MED_NO_DT,MED_NO_IT,
168       MED_NODE,MED_NO_GEOTYPE,MED_COORDINATE,MED_NO_CMODE,&chan,&tran);
169               //(med_geometrie_element)0,(med_connectivite)0);
170    if (nnoe<1){
171       std::cerr<<"Problem number of Vertices < 1\n";
172       ret = MEDfileClose(fid);
173       return false;
174    }
175
176    //nombre d'objets MED : mailles, faces, aretes , ... 
177    med_int /*nmailles[MED_N_CELL_GEO],*/nbtria3;
178    //med_int nfaces[MED_N_FACE_GEO];
179    med_int /*naretes[MED_N_EDGE_FIXED_GEO],*/nbseg2;
180    //med_int nmailles[MED_NBR_GEOMETRIE_MAILLE],nbtria3;
181    //med_int nfaces[MED_NBR_GEOMETRIE_FACE];
182    //med_int naretes[MED_NBR_GEOMETRIE_ARETE],nbseg2;
183    //polygones et polyedres familles equivalences joints
184    med_int /*nmpolygones,npolyedres,nfpolygones,*/nfam/*,nequ,njnt*/;
185
186    //Combien de mailles, faces ou aretes pour chaque type geometrique ?
187    /*for (i=0;i<MED_NBR_GEOMETRIE_MAILLE;i++){
188       nmailles[i]=MEDnEntMaa(fid,mymailw->nommaa,MED_CONN,MED_MAILLE,typmai[i],typ_con);
189       //lecture_nombre_mailles_standards(fid,nommaa,typmai[i],typ_con,i);
190       if (mymailw->verbose>6) std::cout<<"NumberOf"<<nommai[i]<<"="<<nmailles[i]<<std::endl;
191    }*/
192    
193    nbtria3=MEDmeshnEntity(fid,mymailw->nommaa,MED_NO_DT,MED_NO_IT,
194       MED_CELL,MED_TRIA3,MED_CONNECTIVITY,MED_NODAL,&chan,&tran);
195    nbseg2=MEDmeshnEntity(fid,mymailw->nommaa,MED_NO_DT,MED_NO_IT,
196       MED_CELL,MED_SEG2,MED_CONNECTIVITY,MED_NODAL,&chan,&tran);
197
198    //combien de familles ?
199    nfam=MEDnFamily(fid,mymailw->nommaa);
200    if (mymailw->verbose>2) {
201       std::cout<<"\nNumberOfFamilies="<<nfam<<std::endl;
202       std::cout<<"NumberOfVertices="<<nnoe<<std::endl;
203       std::cout<<"NumberOfMED_SEG2="<<nbseg2<<std::endl;
204       std::cout<<"NumberOfMED_TRIA3="<<nbtria3<<"\n\n";
205    }
206    if (nbtria3<3){
207       std::cerr<<"Problem number of MED_TRIA3 < 3, not a skin of a volume\n";
208       ret = MEDfileClose(fid);
209       return false;
210    }
211
212 med_int ifamdelete=0,idelete;
213 std::vector<med_int> famdelete = std::vector<med_int>(nfam);
214 {
215   med_int ngro;
216   char *gro;
217   char nomfam[MED_NAME_SIZE+1];
218   med_int numfam;
219   //char str1[MED_COMMENT_SIZE+1];
220   char str2[MED_LNAME_SIZE+1];
221   med_err ret = 0;
222   
223   for (i=0;i<nfam;i++) famdelete[i]=0;
224   for (i=0;i<nfam;i++) {
225
226     //nombre de groupes
227     ngro = MEDnFamilyGroup(fid,mymailw->nommaa,i+1);
228     if (ngro < 0){
229        std::cerr<<"Problem reading number of groups of family\n";
230        continue;
231     }
232
233     //atributs obsolete MED3
234     //allocation memoire par exces
235     gro = (char*) malloc(MED_LNAME_SIZE*(ngro+1));
236     
237     ret = MEDfamilyInfo(fid,mymailw->nommaa,i+1,nomfam,&numfam,gro);
238     if (ret < 0){
239        std::cerr<<"Problem reading informations of family\n";
240        continue;
241     }
242
243     if (mymailw->verbose>8) {
244      std::cout<<"Family "<<numfam<<" have "<<ngro<<" groups\n";
245      //affichage des resultats
246      for (j=0;j<ngro;j++) {
247       if (j==0) std::cout<<"  Groups :\n";
248       strncpy(str2,gro+j*MED_LNAME_SIZE,MED_LNAME_SIZE);
249       str2[MED_LNAME_SIZE] = '\0';
250       fprintf(stdout,"    name = %s\n",str2);
251      }
252      if (i==nfam-1) std::cout<<std::endl;
253     }
254     QString sfam,sgro;
255     sfam=sfam.sprintf("%d",numfam);
256     idelete=0;
257     for (j=0;j<ngro;j++){
258        strncpy(str2,gro+j*MED_LNAME_SIZE,MED_LNAME_SIZE);
259        str2[MED_LNAME_SIZE]='\0';
260        sgro=str2;
261        if (sgro.contains(mymailw->deletegroups)>0) {
262           //std::cout<<"idelete++ "<<sgro<<std::endl;
263           idelete++;
264        }
265     }
266
267     if (idelete==ngro && ngro>0) { //only delete family whith all delete groups
268        //std::cout<<"famdelete++ "<<numfam<<" "<<ifamdelete<<" "<<ngro<<std::endl;
269        famdelete[ifamdelete]=numfam;
270        ifamdelete++;
271     }
272
273     else {
274      for (j=0;j<ngro;j++){
275        strncpy(str2,gro+j*MED_LNAME_SIZE,MED_LNAME_SIZE);
276        str2[MED_LNAME_SIZE]='\0';
277        sgro=str2;
278        QRegExp qgroup=QRegExp("Group_Of_All",Qt::CaseSensitive,QRegExp::RegExp);
279        if (sgro.contains(mymailw->deletegroups)==0){
280           if (sgro.contains(qgroup)>0) {
281              sgro="Skin_"+sgro; //pas sur que ce soit pertinent
282           }
283           if (mymailw->verbose>8) std::cout<<"families.add("<<sfam.toLatin1().constData()<<
284                                         ","<<sgro.toLatin1().constData()<<")\n";
285           mymailw->families.add(sfam,sgro);
286        }
287        else {
288           //sgro="Skin_"+sgro; //pas sur que ce soit pertinent
289           //std::cout<<"--deletegroups matches \""<<sfam<<","<<sgro<<"\"\n";
290           if (mymailw->verbose>3) std::cout<<"--deletegroups matches \""<<
291                                         sgro.toLatin1().constData()<<
292                                         "\" in family "<<numfam<<std::endl;
293        }
294      }
295     }
296     
297     /*for (j=0;j<ngro;j++){
298        strncpy(str2,gro+j*MED_LNAME_SIZE,MED_LNAME_SIZE);
299        str2[MED_LNAME_SIZE]='\0';
300        sgro=str2;
301        //std::cout<<"families.add("<<sfam<<","<<sgro<<")\n";
302        if (sgro.contains(mymailw->deletegroups)==0){
303           //sgro="Skin_"+sgro; //pas sur que ce soit pertinent
304           std::cout<<"families.add("<<sfam<<","<<sgro<<")\n";
305           mymailw->families.add(sfam,sgro);
306        }
307        else {
308           std::cout<<"--deletegroups matches \""<<sgro<<"\"\n";
309           famdelete[ifamdelete]=numfam
310           ifamdelete++;
311        }
312     }*/
313
314     //on libere la memoire
315     free(gro);
316   }
317 }
318
319 //std::cout<<"famdelete"; for (j=0;j<ifamdelete;j++) std::cout<<" "<<famdelete[j]; std::cout<<std::endl;
320
321 if (mymailw->verbose>3){
322    std::cout<<"\nFamiliesAndGroupsOf "<<nomfilemed.toLatin1().constData()<<std::endl;
323    mymailw->families.write();
324 }
325    /* Allocations memoires */
326    /* table des coordonnees profil : (space dimension * nombre de noeuds ) */
327    med_float *coo=new med_float[nnoe*sdim];
328    /* table des numeros de familles des noeuds profil : (nombre de noeuds) */
329    med_int *famnodesskin=new med_int[nnoe];
330    //med_int *pfltab=new med_int[1]; //inutilise car on lit tout 
331    //lecture des noeuds : coordonnees
332    ret=MEDmeshNodeCoordinateRd(fid,mymailw->nommaa,MED_NO_DT,MED_NO_IT,MED_FULL_INTERLACE,coo);
333           //mdim,coo,mode_coo,MED_ALL,pfltab,0,&rep,mymailw->nomcoo,mymailw->unicoo);
334    if (ret < 0){
335       std::cerr<<"Problem reading nodes\n";
336       ret = MEDfileClose(fid);
337       //return false;
338    }
339    ret=MEDmeshEntityFamilyNumberRd(fid,mymailw->nommaa,MED_NO_DT,MED_NO_IT,MED_NODE,MED_NONE,famnodesskin);
340       //famnodesskin,nnoe,MED_NOEUD,(med_geometrie_element) 0);
341    if (ret < 0){
342       std::cerr<<"Problem reading families of nodes\n";
343       ret = MEDfileClose(fid);
344       return false;
345    }
346    if (mymailw->verbose>9) {
347      std::cout<<"\nVertices: no x y z family\n";
348      for (i=0;i<nnoe*mdim;i=i+3) {
349       fprintf(stdout,"%5d %13.5e %13.5e %13.5e %5d \n",
350           (i/3+1), coo[i], coo[i+1], coo[i+2], famnodesskin[i/3]);
351      } 
352      std::cout<<std::endl;
353    }
354
355    med_int *conn2=new med_int[nbseg2*2];
356    ret=MEDmeshElementConnectivityRd(fid,mymailw->nommaa,MED_NO_DT,MED_NO_IT,
357            MED_CELL,MED_SEG2,MED_NODAL,MED_FULL_INTERLACE,conn2);
358             //mdim,conn2,mode_coo,pfltab,0,MED_MAILLE,MED_SEG2,MED_NOD);
359    if (ret < 0){
360       std::cerr<<"Problem reading MED_SEG2\n";
361       ret = MEDfileClose(fid);
362       //return false;
363    }
364    med_int *famseg2skin=new med_int[nbseg2];
365    ret=MEDmeshEntityFamilyNumberRd(fid,mymailw->nommaa,MED_NO_DT,MED_NO_IT,MED_CELL,MED_SEG2,famseg2skin);
366       //MEDfamLire(fid,mymailw->nommaa,famseg2skin,nbseg2,MED_MAILLE,MED_SEG2);
367    if (ret < 0){
368       std::cerr<<"Problem reading families of MED_SEG2\n";
369       ret = MEDfileClose(fid);
370       return false;
371    }
372    if (mymailw->verbose>9) {
373      std::cout<<"\nConnectivity MED_SEG2: no node1 node2 family\n";
374      for (i=0;i<nbseg2*2;i=i+2) {
375       fprintf(stdout,"%5d %5d %5d %5d \n",
376           (i/2+1), conn2[i], conn2[i+1], famseg2skin[i/2]);
377      } 
378      std::cout<<std::endl;
379    }
380    //std::cout<<"\ncvw1 conn nbtria3 "<<nbtria3<<"dt "<<MED_NO_DT<<"it "<<MED_NO_IT<<"cell "<<MED_CELL<<"tria3 "<<MED_TRIA3<<std::endl;
381    med_int *conn3=new med_int[nbtria3*3];
382    ret=MEDmeshElementConnectivityRd(fid,mymailw->nommaa,MED_NO_DT,MED_NO_IT,
383            MED_CELL,MED_TRIA3,MED_NODAL,MED_FULL_INTERLACE,conn3);
384            //MEDconnLire(fid,mymailw->nommaa,mdim,conn3,mode_coo,pfltab,0,MED_MAILLE,MED_TRIA3,MED_NOD);
385    if (ret < 0){
386       std::cerr<<"Problem reading MED_TRIA3\n";
387       ret = MEDfileClose(fid);
388       //return false;
389    }
390    med_int *famtria3skin=new med_int[nbtria3];
391    ret=MEDmeshEntityFamilyNumberRd(fid,mymailw->nommaa,MED_NO_DT,MED_NO_IT,MED_CELL,MED_TRIA3,famtria3skin);
392         //MEDfamLire(fid,mymailw->nommaa,famtria3skin,nbtria3,MED_MAILLE,MED_TRIA3);
393    if (ret < 0){
394       std::cerr<<"Problem reading families of MED_TRIA3\n";
395       ret = MEDfileClose(fid);
396       return false;
397    }
398    if (mymailw->verbose>9) {
399      std::cout<<"\nConnectivity MED_TRIA3: no node1 node2 node3 family\n";
400      for (i=0;i<nbtria3*3;i=i+3) {
401       fprintf(stdout,"%5d %5d %5d %5d %5d \n",
402           (i/3+1), conn3[i], conn3[i+1], conn3[i+2], famtria3skin[i/3]);
403      } 
404      std::cout<<std::endl;
405    }
406
407   /*liberation memoire?
408   delete[] coo;
409   delete[] nomnoe;
410   delete[] numnoe;
411   delete[] nufano;*/
412
413   if (ifamdelete>0) {
414    //std::cout<<"!!!!!!!!nodes "<<famnodesskin[0]<<" "<<nnoe<<famdelete[1]<<std::endl;
415    for (i=0;i<nnoe;i++) {
416     for (j=0;j<ifamdelete;j++) {
417       if (famnodesskin[i]==famdelete[j]) {
418        //std::cout<<"nodes "<<famnodesskin[i]<<" "<<i<<" "<<famdelete[j]<<std::endl;
419        famnodesskin[i]=0; }
420     }
421    }
422    for (i=0;i<nbseg2;i++) {
423     for (j=0;j<ifamdelete;j++) {
424       if (famseg2skin[i]==famdelete[j]) famseg2skin[i]=0;
425     }
426    }
427    for (i=0;i<nbtria3;i++) {
428     for (j=0;j<ifamdelete;j++) {
429       if (famtria3skin[i]==famdelete[j]) famtria3skin[i]=0;
430     }
431    }
432   }
433    //stocks data for future use 
434    CVWtab *montab;
435    bool ok;
436
437    montab=new CVWtab(nnoe*mdim,coo);
438    tmp="SKIN_VERTICES_COORDINATES";
439    ok=mymailw->insert_key(tmp,montab);
440
441    montab=new CVWtab(nnoe,famnodesskin);
442    tmp="SKIN_VERTICES_FAMILIES";
443    ok=mymailw->insert_key(tmp,montab);
444    
445    montab=new CVWtab(nbseg2*2,conn2);
446    tmp="SKIN_SEG2_CONNECTIVITIES";
447    ok=mymailw->insert_key(tmp,montab);
448
449    montab=new CVWtab(nbtria3,famseg2skin);
450    tmp="SKIN_SEG2_FAMILIES";
451    ok=mymailw->insert_key(tmp,montab);
452
453    montab=new CVWtab(nbtria3*3,conn3);
454    tmp="SKIN_TRIA3_CONNECTIVITIES";
455    ok=mymailw->insert_key(tmp,montab);
456
457    montab=new CVWtab(nbtria3,famtria3skin);
458    tmp="SKIN_TRIA3_FAMILIES";
459    ok=mymailw->insert_key(tmp,montab);
460
461    //if (mymailw->verbose>6) ok=mymailw->list_keys_mesh_wrap();
462
463    ret = MEDfileClose(fid);
464    if (ret < 0){
465       std::cerr<<"Problem closing "<<nomfilemed.toLatin1().constData()<<"\n";
466       return false;
467    }
468    return true;
469 }
470
471 /*
472 mg-tetra_hpc_mpi.exe --help
473
474     =============================================
475     MG-Tetra_HPC -- MeshGems 2.9-6 (August, 2019)
476     =============================================
477
478         Distene SAS
479            Campus Teratec
480            2, rue de la Piquetterie
481            91680 Bruyeres le Chatel
482            FRANCE
483         Phone: +33(0)970-650-219   Fax: +33(0)169-269-033
484         EMail: <support@distene.com>
485
486         Running MG-Tetra_HPC (Copyright 2014-2019 by Distene SAS)
487            date of run: 25-Feb-2020 AT 08:47:20
488            running on : Linux 3.10.0-1062.9.1.el7.x86_64 x86_64
489            using modules: 
490                 MeshGems-Core 2.9-6
491
492         MeshGems is a Registered Trademark of Distene SAS
493
494
495
496 Usage: tetra_hpc_mpi.exe [options]
497
498 Options: 
499
500      Short option (if it exists)
501     /    Long option
502    |    /   Description
503    |   |   /
504    v   v  v
505
506      --components <components>
507           Selects which mesh components to process.
508           If <components> is:
509               all : all components are to be meshed.
510               outside_components : only the main (outermost) component is to be
511           meshed.
512                     Default: all
513
514      --gradation <g>
515           Sets the size gradation value.
516           <gradation> is the desired maximum ratio between 2 adjacent
517           tetrahedron edges. The closer it is to 1.0, the more uniform the mesh
518           will be.
519           Default: 1.05
520
521      --gradation_mode <mode>
522           Sets the gradation behaviour.
523           Possible values for <mode> are :
524               without_size: apply gradation only when no size is provided by
525           the input sizemap(s)
526               always: always apply the gradation. This can partially smooth the
527           provided input sizemap(s)
528           Default: without_size
529
530      --help
531           Prints this help.
532
533      --in <input mesh file name>
534           Sets the input file.
535           (MANDATORY)
536
537      --max_edge_length <maximum edge length>
538           Sets the desired maximum accepted edge length.
539           Default: 0 (no maximum length).
540
541      --max_size <maximum size>
542           Sets the desired maximum cell size value.
543           Default: 0 (no maximum size).
544
545      --metric <type>
546           Sets the type of metric governing the mesh generation.
547           Possible values for <type> are :
548               isotropic: the metric induces the same size in all directions.
549               anisotropic: the metric induces different sizes depending on the
550           directions.
551           Default: isotropic
552
553      --min_edge_length <minimum edge length>
554           Sets the desired minimum accepted edge length.
555           Default: 0 (no minimum length).
556
557      --min_size <minimum size>
558           Sets the desired minimum cell size value.
559           Default: 0 (no minimum size).
560
561      --optimisation <boolean>
562           Sets whether to optimise mesh quality or not.
563           Default: yes.
564
565      --optimisation_level <level>
566           Sets the desired optimisation level for mesh quality.
567           Possible values for <level> are (in increasing order of quality vs
568           speed ratio): light, standard, strong
569           Default: standard.
570
571      --out <output mesh file name>
572           Sets the output file.
573           Using an existing file is not allowed.
574           Using the same file as --in is not allowed.
575           If unset, _tetra_hpc is appended to the input file basename.
576           
577      --parallel_strategy <strategy>
578           Sets the desired parallel strategy, influencing the level of
579           reproducibility of the result and the potential performances.
580           Possible values for <strategy> are (in decreasing order for
581           reproducibility and increasing order for performances):
582               reproducible: result is entirely reproducible but performances
583           may not be optimal.
584               aggressive: result may not be reproducible but all parallel
585           optimizations are allowed.
586           Default: reproducible.
587
588      --sizemap <input sizemap file name>
589           Sets the optional input sizemap file. The sizemap must provide the
590           requested size at the input surface or volume mesh vertices.
591                     Default : none.
592
593      --split_overconstrained_edges <boolean>
594           Sets whether to split over-constrained edges or not. An edge is
595           considered as over-constrained when its two vertices belong to the
596           surface.
597           If <boolean> is:
598               yes: correction is applied upon mesh generation/optimisation
599               no: no correction is applied.
600           Default: no
601
602      --split_overconstrained_elements <boolean>
603           Sets whether to split over-constrained elements or not. An edge is
604           considered as over-constrained when its two vertices belong to the
605           surface. A tetrahedron is considered as over-constrained  when at
606           least two of its faces belong to the surface.
607           If <boolean> is:
608               yes: correction is applied upon mesh generation/optimisation
609               no: no correction is applied.
610           Default: no
611
612      --split_overconstrained_tetrahedra <boolean>
613           Sets whether to split over-constrained tetrahedra or not. A
614           tetrahedron is considered as over-constrained  when at least two of
615           its faces belong to the surface.
616           If <boolean> is:
617               yes: correction is applied upon mesh generation/optimisation
618               no: no correction is applied.
619           Default: no
620
621      --verbose <verbose>
622           Set the verbosity level, increasing from 0 to 10.
623           Possible <verbose> values are increasing from 0 to 10 :
624              0 : no details.
625             10 : very detailed.
626           Default: 3.
627
628      --volume_proximity_layers <minimum number of layers>
629           Sets the desired minimum number of tetrahedra layers inside the
630           volume.
631           Default: 0 (no minimum).
632
633      --write_sizemap <output sizemap file name>
634           Sets the optional output sizemap file.
635           Using an existing file is not allowed.
636           If unset, the output sizemap will not be written.
637
638
639 ================================================================================
640                  MG-Tetra_HPC -- MeshGems 2.9-6 (August, 2019)
641        END OF SESSION - MG-Tetra_HPC (Copyright 2014-2019 by Distene SAS)
642                    compiled Sep  2 2019 09:58:40 on Linux_64
643                MeshGems is a Registered Trademark of Distene SAS
644 ================================================================================
645        ( Distene SAS
646         Phone: +33(0)970-650-219   Fax: +33(0)169-269-033
647         EMail: <support@distene.com> )
648 */
649
650
651 //************************************
652 int main(int argc, char *argv[])
653 {
654    bool ok;
655    int i,nb,nbfiles,limit_swap,nbelem_limit_swap,limit_swap_defaut,verbose,res;
656    float gradation,min_size,max_size;
657    QString path,pathini,casename,casenamemed,fileskinmed,
658            tmp,cmd,format,format_tetra,
659            test,launchtetra,background,multithread,deletegroups,
660            version="V4.0 (MED3 + tetra-hpc v2.3 Sept 2016)";
661    
662    char *chelp=NULL,
663         *ccasename=NULL,
664         *cnumber=NULL,
665         *cmedname=NULL,
666         *climitswap=NULL,
667         *cverbose=NULL,
668         *claunchtetra=NULL,
669         *cgradation=NULL,
670         *cmin_size=NULL,
671         *cmax_size=NULL,
672         *cbackground=NULL,
673         *cmultithread=NULL,
674         *cdeletegroups=NULL;
675
676    for (i = 0; i < argc; i++){
677       if (!strncmp (argv[i], "--help", sizeof ("--help"))) chelp = &(argv[i][0]);
678       else if (!strncmp (argv[i], "--casename=", sizeof ("--casename"))) ccasename = &(argv[i][sizeof ("--casename")]);
679       else if (!strncmp (argv[i], "--number=", sizeof ("--number"))) cnumber = &(argv[i][sizeof ("--number")]);
680       else if (!strncmp (argv[i], "--limitswap=", sizeof ("--limitswap"))) climitswap = &(argv[i][sizeof ("--limitswap")]);
681       else if (!strncmp (argv[i], "--medname=", sizeof ("--medname"))) cmedname = &(argv[i][sizeof ("--medname")]);
682       else if (!strncmp (argv[i], "--verbose=", sizeof ("--verbose"))) cverbose = &(argv[i][sizeof ("--verbose")]);
683       else if (!strncmp (argv[i], "--launchtetra=", sizeof ("--launchtetra"))) claunchtetra = &(argv[i][sizeof ("--launchtetra")]);
684       else if (!strncmp (argv[i], "--gradation=", sizeof ("--gradation"))) cgradation = &(argv[i][sizeof ("--gradation")]);
685       else if (!strncmp (argv[i], "--min_size=", sizeof ("--min_size"))) cmin_size = &(argv[i][sizeof ("--min_size")]);
686       else if (!strncmp (argv[i], "--max_size=", sizeof ("--max_size"))) cmax_size = &(argv[i][sizeof ("--max_size")]);
687       else if (!strncmp (argv[i], "--background=", sizeof ("--background"))) cbackground = &(argv[i][sizeof ("--background")]);
688       else if (!strncmp (argv[i], "--multithread=", sizeof ("--multithread"))) cmultithread = &(argv[i][sizeof ("--multithread")]);
689       else if (!strncmp (argv[i], "--deletegroups=", sizeof ("--deletegroups"))) cdeletegroups = &(argv[i][sizeof ("--deletegroups")]);
690       }
691
692    if (argc < 2 || chelp){
693       std::cout<<"tetrahpc2med "<<version.toLatin1().constData()<<" Available options:\n"
694       "   --help               : produces this help message\n"<<
695       "   --casename           : path and name of input tetrahpc2med files which are\n"<<
696       "                           - output files of GHS3DPRL_Plugin .mesh\n"<<
697       "                           - output file of GHS3DPRL_Plugin casename_skin.med (optional)\n"<<
698       "                          with initial skin and its initial groups\n"<<
699       "   --number             : number of partitions\n"<<
700       "   --medname            : path and name of output MED files\n"<<
701       "   --limitswap          : max size of working cpu memory (Mo) (before swapping on .temp files)\n"<<
702       "   --verbose            : trace of execution (0->6)\n"<<
703       "   --launchtetra        : launch mg_tetra_hpc on files casename.mesh and option number,\n"<<
704       "                            else only use existing input/output files\n"<<
705       "   --gradation          : the desired maximum ratio between 2 adjacent tetrahedron edges (Default 1.05). The closer it is to 1.0\n"<<
706       "   --min_size           : the desired maximum cell size value (Default: 0 no maximum size)\n"<<
707       "   --max_size           : the desired minimum cell size value (Default: 0 no minimum size)\n"<<
708       "   --background         : force background mode from launch tetra-hpc and generation of final MED files (big meshes)\n"<<
709       "   --multithread        : launch mg_tetra_hpc multithread version, else mpi version\n"<<
710       "   --deletegroups       : regular expression (see QRegExp) which matches unwanted groups in final MED files\n"<<
711       "                            (try --deletegroups=\"(\\bJOINT)\"\n"<<
712       "                            (try --deletegroups=\"(\\bAll_Nodes|\\bAll_Faces)\"\n"<<
713       "                            (try --deletegroups=\"((\\bAll_|\\bNew_)(N|F|T))\"\n";
714       std::cout<<"example:\n   tetrahpc2med --casename=/tmp/GHS3DPRL --number=2 --medname=DOMAIN "<<
715                  "--verbose=0 --launchtetra=no\n\n";
716       return 1;  //no output files
717    }
718    
719    if (!ccasename){
720       std::cerr<<"--casename: a path/name is expected\n\n";
721       return 1;
722    }
723    casename=ccasename;
724    if (!cnumber){
725       std::cerr<<"--number: an integer is expected\n\n";
726       return 1;
727    }
728    tmp=cnumber;
729    nbfiles=tmp.toLong(&ok,10);
730    if (!ok){
731       std::cerr<<"--number: an integer is expected\n\n";
732       return 1;
733    }
734    if (nbfiles<=0){
735       std::cerr<<"--number: a positive integer is expected\n\n";
736       return 1;
737    }
738    if (nbfiles>2048){ //delirium in 2016
739       std::cerr<<"--number: a positive integer <= 2048 is expected\n\n";
740       return 1;
741    }
742    if (!cmedname) cmedname=ccasename;
743    casenamemed=cmedname;
744
745    limit_swap_defaut=1000; //1000Mo
746    limit_swap=limit_swap_defaut;
747    if (climitswap){
748       tmp=climitswap;
749       limit_swap=tmp.toLong(&ok,10);
750       if (!ok){
751          std::cerr<<"--limitswap: an integer is expected. try 1000\n\n";
752          return 1;
753       }
754       if (limit_swap<1 || limit_swap>32000){
755          std::cerr<<"--limitswap: [1->32000] expected. try 1000\n\n";
756          return 1;
757       }
758    }
759    
760    verbose=1; //default
761    if (cverbose){
762       tmp=cverbose;
763       verbose=tmp.toLong(&ok,10);
764       if (!ok){
765          std::cerr<<"--verbose: an integer is expected\n\n";
766          return 1;
767       }
768       if (verbose<0){
769          std::cerr<<"--verbose: a positive integer is expected\n\n";
770          return 1;
771       }
772    }
773
774    launchtetra="no"; //default
775    if (claunchtetra){
776       tmp=claunchtetra;
777       if (tmp=="yes") launchtetra="yes";
778    }
779
780    gradation=1.05; //default
781    if (cgradation){
782       tmp=cgradation;
783       gradation=tmp.toFloat(&ok);
784       if (!ok){
785          std::cerr<<"--gradation: a float { 0; ]1,3] } is expected\n\n";
786          return 1;
787       }
788       if (gradation>3.){
789          std::cerr<<"--gradation: a float <= 3. is expected\n\n";
790          return 1;
791       }
792       if (gradation<0.){
793          std::cerr<<"--gradation: a float >= 0. is expected\n\n";
794          return 1;
795       }
796    }
797
798    if (cmin_size){
799       tmp=cmin_size;
800       min_size=tmp.toFloat(&ok);
801       if (!ok){
802          std::cerr<<"--min_size: a float >= 0. is expected\n\n";
803          return 1;
804       }
805       if (gradation<0.){
806          std::cerr<<"--min_size: a float >= 0. is expected\n\n";
807          return 1;
808       }
809    }
810
811    if (cmax_size){
812       tmp=cmax_size;
813       max_size=tmp.toFloat(&ok);
814       if (!ok){
815          std::cerr<<"--max_size: a float >= 0. is expected\n\n";
816          return 1;
817       }
818       if (gradation<0.){
819          std::cerr<<"--max_size: a float >= 0. is expected\n\n";
820          return 1;
821       }
822    }
823
824    background="no"; //default
825    if (cbackground){
826       tmp=cbackground;
827       if (tmp=="yes") background="yes";
828    }
829
830    multithread="no"; //default
831    if (cmultithread){
832       tmp=cmultithread;
833       if (tmp=="yes") multithread="yes";
834    }
835
836
837    int n=casenamemed.count('/');
838    if (n>0)
839       path=casenamemed.section('/',-n-1,-2)+"/";
840    else
841       path="./";
842       casenamemed=casenamemed.section('/',-1);
843    if (casenamemed.length()>20){
844       std::cerr<<"--medname truncated (no more 20 characters)"<<std::endl;
845       casenamemed.truncate(20);
846    }
847
848    n=casename.count('/');
849    if (n>0)
850       pathini=casename.section('/',-n-1,-2)+"/";
851    else
852       pathini="./";
853       casename=casename.section('/',-1);
854    if (casename.length()>20){
855       std::cerr<<"--casename truncated (no more 20 characters)"<<std::endl;
856       casename.truncate(20);
857    }
858
859    //std::cout<<"CaseNameMed="<<casenamemed.toLatin1().constData()<<std::endl;
860    //std::cout<<"PathMed="<<path.toLatin1().constData()<<std::endl;
861
862    deletegroups="(\\bxyz)"; //default improbable name
863    if (cdeletegroups){
864       deletegroups=cdeletegroups;
865    }
866    
867    //verbose=5;
868    if (verbose>0)
869    std::cout<<
870            "tetrahpc2med "<<version.toLatin1().constData()<<" parameters:"<<
871          "\n   --casename="<<pathini.toLatin1().constData()<<casename.toLatin1().constData()<<
872          "\n   --number="<<nbfiles<<
873          "\n   --medname="<<path.toLatin1().constData()<<casenamemed.toLatin1().constData()<<
874          "\n   --verbose="<<verbose<<
875          "\n   --launchtetra="<<launchtetra.toLatin1().constData()<<
876          "\n   --gradation="<<gradation<<
877          "\n   --min_size="<<min_size<<
878          "\n   --max_size="<<max_size<<
879          "\n   --background="<<background.toLatin1().constData()<<
880          "\n   --multithread="<<multithread.toLatin1().constData()<<
881          "\n   --deletegroups=\""<<deletegroups.toLatin1().constData()<<"\"\n";
882          
883    if (launchtetra=="yes"){
884      
885       //call tetra_hpc.py is python script which assumes mpirun or else if no multithread
886       //after compilation openmpi or else acrobatic DISTENE_LICENCE change...
887       
888       cmd="mg-tetra_hpc.py --number=" + QString::number(nbfiles)+
889           " --in=" + pathini+casename + ".mesh" +
890           " --out=" + pathini+casename + "_out.mesh" +
891           " --gradation=" + QString::number(gradation) +
892           " --min_size=" + QString::number(min_size) +
893           " --max_size=" + QString::number(max_size) +
894           " --multithread=" + multithread.toLatin1().constData() +
895           " > " + path + "tetrahpc.log";
896       std::cout<<"\nlaunch tetra_hpc command:"<<
897                  "\n   "<<cmd.toLatin1().constData()<<"\n"<<std::endl;
898    }
899    else if ( std::ifstream(( pathini+casename + "_out.mesh").toLatin1().constData() ).is_open() )
900    {
901      // mesh file exists (created by using MG as a library), copy it to *.000001.mesh
902      QString copyCmd = ( QString("cp -f %1_out.mesh %2_out.000001.mesh")
903                          .arg( pathini+casename ).arg( pathini+casename ));
904      system( copyCmd.toLatin1().constData()); // run
905    }
906    
907    //utile si appel par plugin ghs3dprl sur big meshes et tetra_hpc sur plusieurs jours
908 #ifndef WIN32
909    if (background=="yes"){
910       pid_t pid = fork();
911       if (pid > 0) {
912          //Process father
913          exit(0); //temporary ok for plugin
914       }
915       //process children
916       //On rend le fils independant de tout terminal
917       //from here everything in background: tetrahpc AND generation of final MED files
918       setsid();
919       system("sleep 10");  //for debug
920    }
921 #else
922    printf("background mode is not supported on win32 platform !\n");
923 #endif
924
925    if (launchtetra=="yes"){
926       //sometimes it is better to wait flushing files on slow filesystem...
927       system("sleep 3");
928       res = system(cmd.toLatin1().constData()); // run
929       if (res>0) 
930       {
931         std::cout<<std::endl<<"===end KO PROBLEM of "<<argv[0]<<"==="<<std::endl;
932         return res; // KO
933       }
934       system("sleep 3");
935    }
936    ghs3dprl_mesh_wrap *mymailw=new ghs3dprl_mesh_wrap;
937    //no constructor, later maybe
938    mymailw->nbfiles=0;
939    mymailw->nbfilestot=nbfiles;
940    //for huge cases big array swap in huge binary files
941    mymailw->verbose=verbose;
942    mymailw->casename=casename;
943    mymailw->medname=casenamemed;
944    mymailw->path=path;
945    mymailw->pathini=pathini;
946    mymailw->deletegroups=QRegExp(deletegroups,Qt::CaseSensitive,QRegExp::RegExp);
947    mymailw->for_multithread=false;
948    if (multithread=="yes") mymailw->for_multithread=true;
949    ghs3dprl_msg_parser handler;
950    //constructor later maybe
951    //handler.verbose=true;
952    handler.mailw=mymailw;
953    mymailw->families.no=1;
954    //std::cout<<"coucou1 "<<mymailw->families.no<<std::endl;
955    //mymailw->families.add(casename,casenamemed);
956    format=format.sprintf("%d",nbfiles);
957    int nbf=format.length();
958    format=format.sprintf(".%%0%dd.%%0%dd",nbf,nbf);
959    format_tetra=".%06d";
960    if (verbose>10)std::cout<<"format "<<format.toLatin1().constData()<<std::endl;
961    if (verbose>10)std::cout<<"format_tetra "<<format_tetra.toLatin1().constData()<<std::endl;
962    mymailw->format=format;
963    mymailw->format_tetra=format_tetra;
964    mymailw->for_tetrahpc=true; //to know what files to read: .noboite or .mesh
965    
966    //default 1GOctet/8(for float)
967    nbelem_limit_swap=limit_swap*1000000; //100%
968    CVWtab::memorymax=nbelem_limit_swap;
969    mymailw->nbelem_limit_swap=nbelem_limit_swap;
970
971    
972    //something like "/home/wambeke/tmp/GHS3DPRL_skin.med"
973    fileskinmed=pathini+casename+"_skin.med";
974    //fileskinmed="/home/wambeke/tmp/GHS3DPRL_skin.med";
975    /*for debug
976    {
977    char ctmp[fileskinmed.length()+1] ; strcpy(ctmp,fileskinmed);
978    int res=dumpMED(&ctmp[0],1);
979    }*/
980    int ret = access(fileskinmed.toLatin1().constData(),F_OK); //on regarde si le fichier existe
981    if (ret >= 0) {
982       ok=ReadFileMED(fileskinmed,mymailw); }
983    else {
984       if (verbose>0)std::cout<<"Initial skin file <"<<fileskinmed.toLatin1().constData()<<"> does not exist\n"; }
985    
986
987    //if test quickly read all files before (or only small files)
988    if (test=="yes"){
989      if (verbose>0) std::cout<<"\nReading output files of tetrahpc as input files of tetrahpc2med...\n";
990      //only read beginning of files .xxxxx.mesh
991      //supposed big files big arrays so only see first lines
992      mymailw->nbfiles=0;
993      for (int i=1; i<=nbfiles; i++){
994         mymailw->nofile=i;
995         tmp=pathini+casename+tmp.sprintf(format_tetra.toLatin1().constData(),i)+".mesh";
996         if (verbose>0) std::cout<<"FileName="<<tmp.toLatin1().constData()<<std::endl;
997         ok=mymailw->TestExistingFileMESHnew(tmp);
998      }
999      if (verbose>0)
1000         std::cout<<"NumberOfFilesMESHTested="<<mymailw->nbfiles<<": ok\n\n";
1001      if (mymailw->nbfiles != nbfiles){
1002         std::cerr<<"NumberOfFiles != NumberOfFilesTested is unexpected\n\n";
1003         return 1;
1004      }
1005    }  //end if test
1006  
1007    ok=mymailw->Write_MEDfiles_v2(true); //deletekeys=true
1008    
1009    nb=mymailw->remove_all_keys_mesh_wrap();
1010    if (verbose>3)std::cout<<"***remove_all_key_mesh_wrap*** "<<nb<<" keys removed\n";
1011
1012    if (verbose>=0)std::cout<<std::endl<<"===end OK of "<<argv[0]<<"==="<<std::endl;
1013
1014    //for debug
1015    //int res=dumpMED("/home/wambeke/tmp/DOMAIN_1.med",1);
1016
1017    return 0; //ok
1018 }