Salome HOME
new version of ensight driver
[modules/filter.git] / src / FILTER / Filter_Gen_i.cxx
1 //  FILTER FILTER : implemetation of FILTER idl descriptions
2 //
3 //  Copyright (C) 2003  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 //  This library is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU Lesser General Public
8 //  License as published by the Free Software Foundation; either
9 //  version 2.1 of the License.
10 //
11 //  This library is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 //  Lesser General Public License for more details.
15 //
16 //  You should have received a copy of the GNU Lesser General Public
17 //  License along with this library; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 //
23 //
24 //  File   : Filter_Gen_i.cxx
25 //  Author : Paul RASCLE, EDF
26 //  Module : FILTER
27 //  $Header$
28
29 #include "Filter_Gen_i.hxx"
30
31 #include "Utils_SINGLETON.hxx"
32 #include "OpUtil.hxx"
33 #include "Utils_CorbaException.hxx"
34 #include "utilities.h"
35
36 #include "MEDMEM_EnsightMeshDriver.hxx"
37 #include <string>
38 #include <deque>
39 #include <map>
40
41 #include <TCollection_AsciiString.hxx>
42 #include <TColStd_SequenceOfAsciiString.hxx>
43 #include <HDFascii.hxx>
44
45 using namespace std;
46 using namespace SALOME_FILTER;
47 Filter_Gen_i* Filter_Gen_i::_FILTERGen = NULL;
48
49 //=============================================================================
50 /*!
51  *  default constructor: not for use
52  */
53 //=============================================================================
54
55 Filter_Gen_i::Filter_Gen_i()
56 {
57   MESSAGE("Filter_Gen_i::Filter_Gen_i");
58 }
59
60 //=============================================================================
61 /*!
62  *  standard constructor
63  */
64 //=============================================================================
65
66 Filter_Gen_i:: Filter_Gen_i(CORBA::ORB_ptr orb,
67                                 PortableServer::POA_ptr poa,
68                                 PortableServer::ObjectId * contId,
69                                 const char *instanceName,
70                                 const char *interfaceName) :
71   Engines_Component_i(orb, poa, contId, instanceName, interfaceName),_med(NULL),_newMed(NULL),_mesh(NULL),_newMesh(NULL),_myGradient(NULL),_myDField(NULL),_myIField(NULL),_criteria(NULL),_map(NULL)
72 {
73   MESSAGE("activate object");
74   _thisObj = this ;
75   _id = _poa->activate_object(_thisObj);
76
77   _duringLoad=false;
78   // get an NamingService interface
79   _NS = SINGLETON_<SALOME_NamingService>::Instance() ;
80   ASSERT(SINGLETON_<SALOME_NamingService>::IsAlreadyExisting()) ;
81   _NS->init_orb( _orb ) ;
82
83   _FILTERGen = this;
84 }
85
86 //=============================================================================
87 /*!
88  *  default destructor: not for use
89  */
90 //=============================================================================
91
92 Filter_Gen_i::~Filter_Gen_i()
93 {
94   MESSAGE("Filter_Gen_i::~Filter_Gen_i");
95
96   // destruction of gradient field
97   if(_myGradient)
98     delete _myGradient;
99
100   // destruction of support of reference field: reference field is destroyed
101   // by destruction of med object
102   if(_myIField)
103     delete _myIField->getSupport();
104   if(_myDField)
105     delete _myDField->getSupport();
106
107  // destruction of criteria: support and field
108   if(_criteria){
109     delete _criteria->getSupport();
110     delete _criteria;
111   }
112
113   if(_map)
114     delete [] _map;
115   if(_med)
116     delete _med;
117   if(_newMed)
118     delete _newMed;
119 }
120
121 void Filter_Gen_i::loadMED(const char* inMedFile)
122 {
123   SCRUTE(inMedFile);
124   _file = inMedFile;
125   _med = new ::MED(MED_DRIVER,_file);
126 }
127
128 void Filter_Gen_i::unloadMED()
129 {
130   MESSAGE("unloadMED called");
131   // destruction of gradient field
132   if(_myGradient){
133     delete _myGradient;
134     _myGradient=NULL;
135   }
136
137   // destruction of support of reference field: reference field is destroyed
138   // by destruction of med object
139   if(_myIField){
140     delete _myIField->getSupport();
141     _myIField=NULL;
142   }
143   if(_myDField){
144     delete _myDField->getSupport();
145     _myDField=NULL;
146   }
147
148  // destruction of criteria: support and field
149   if(_criteria){
150     delete _criteria->getSupport();
151     delete _criteria;
152     _criteria=NULL;
153   }
154
155   if(_med){
156     delete _med;
157     _med=NULL;
158   }
159 }
160
161 StrSeq* Filter_Gen_i::getMeshNames()
162 {
163   StrSeq *seq = new StrSeq();
164   deque<string> deq = _med->getMeshNames();
165   seq->length(deq.size());
166   for(int i=0;i<deq.size();i++)
167     (*seq)[i] = deq[i].c_str();
168   return seq;
169 }
170   
171 StrSeq * Filter_Gen_i::getFieldNames()
172 {
173   StrSeq *seq = new StrSeq();
174   deque<string> deq = _med->getFieldNames();
175   seq->length(deq.size());
176   for(int i=0;i<deq.size();i++)
177      (*seq)[i] = deq[i].c_str();
178   return seq;
179 }
180
181 CORBA::Long  Filter_Gen_i::getMeshDimension(const char* meshName)
182 {
183   return _med->getMesh(meshName)->getMeshDimension();
184 }
185
186 DTITSeq* Filter_Gen_i::getFieldIteration(const char* fieldName)
187 {
188   DTITSeq *seq = new DTITSeq();
189   deque<DT_IT_> deq = _med->getFieldIteration(fieldName);
190   seq->length(deq.size());
191   for(int i=0;i<deq.size();i++){
192     (*seq)[i].dt = deq[i].dt;
193     (*seq)[i].it = deq[i].it;
194   }
195   return seq;
196 }
197
198 char* Filter_Gen_i::getMeshName(const char* fieldName,CORBA::Long dt,CORBA::Long it)
199 {
200   return (char*)(_med->getField(fieldName,dt,it)->getSupport()->getMesh()->getName().c_str());
201 }
202
203 void Filter_Gen_i::readReferenceField(const char* meshName, const char* fieldName, CORBA::Long ts)
204 {
205   // read of input mesh
206   _mesh = _med->getMesh(meshName);
207   _mesh->read();
208   
209   // read of input field
210   deque<DT_IT_> myIteration = _med->getFieldIteration (fieldName);
211   MEDMEM::FIELD_* field = _med->getField(fieldName,myIteration[ts].dt,myIteration[ts].it);
212   if (dynamic_cast<MEDMEM::FIELD<double>*>(field)){
213     _myDField = (MEDMEM::FIELD<double>*)field;
214     _myDField->read();
215     _myIField = NULL;
216   }
217   else{
218     _myIField = (MEDMEM::FIELD<int>*)field;
219     _myIField->read();
220     _myDField = NULL;
221   }
222 }
223
224 void Filter_Gen_i::buildGradient() throw(SALOME_FILTER::FILTER_Gen::FilterError)
225 {
226   if(!_myGradient){
227     FIELD<double> * gradient;
228     try{
229       if(_myDField)
230         gradient = _myDField->buildGradient();
231       else
232         gradient = _myIField->buildGradient();
233       _myGradient = gradient->buildNorm2Field();
234       delete gradient;
235     }
236     catch(MEDEXCEPTION& Mex){
237       MESSAGE("SALOME_Exception: Can't calculate gradient");
238       throw SALOME_FILTER::FILTER_Gen::FilterError("Can't calculate gradient");
239     }
240   }
241 }
242
243 void Filter_Gen_i::getMinMax(CORBA::Double& imin, CORBA::Double& imax,ref_func rf)
244 {
245   double min, max;
246
247   switch(rf){
248   case F_FIELD:
249     if (_myDField)
250       _myDField->getMinMax(min,max);
251     else{
252       int xmin, xmax;
253       _myIField->getMinMax(xmin,xmax);
254       min = (double)xmin;
255       max = (double)xmax;
256     }
257     break;
258   case F_GRAD:
259     _myGradient->getMinMax(min,max);
260     break;
261   }
262   imin = min;
263   imax = max;
264 }
265
266 LongSeq* Filter_Gen_i::getHistogram(CORBA::Long size,ref_func rf)
267 {
268   int mysize = size;
269   vector<int> myh;
270
271   switch(rf){
272   case F_FIELD:
273     if (_myDField)
274       myh = _myDField->getHistogram(mysize);
275     else
276       myh = _myIField->getHistogram(mysize);
277     break;
278   case F_GRAD:
279     myh = _myGradient->getHistogram(mysize);
280     break;
281   }
282
283   LongSeq *seq = new LongSeq();
284   seq->length(myh.size());
285   for(int i=0;i<myh.size();i++)
286     (*seq)[i] = myh[i];
287   return seq;
288 }
289
290 void Filter_Gen_i::generateCriteria(CORBA::Long nbthresh,CORBA::Double fthresh,CORBA::Double sthresh,CORBA::Boolean areaFlag,ref_func rf) throw(SALOME_FILTER::FILTER_Gen::FilterError)
291 {
292   double val, min, max;
293   double sigmaV;
294   bool isGVal;
295   MED_EN::medEntityMesh typ;
296   const int *revC;
297   const int *indC;
298   FIELD<double> *volume;
299   set <int> listElements;
300   set <int>::iterator elemIt ;
301
302   if(_myDField)
303     typ = _myDField->getSupport()->getEntity();
304   else
305     typ = _myIField->getSupport()->getEntity();
306
307   // create support on nodes
308   SUPPORT *sup = new SUPPORT(_mesh,"Support",MED_NODE);
309
310   // create integer field on nodes
311   _criteria = new FIELD<int>(sup,1);
312
313   _criteria->setName("Criteria");
314
315   // read number of nodes
316   int NumberOf = sup->getNumberOfElements(MED_ALL_ELEMENTS);
317
318   // if reference field is on elements get reference field on nodes
319   switch(typ){
320   case MED_CELL:
321     if(_myDField){
322       // calculate reverse connectivity to have the list of elements which contains node i
323       revC = _myDField->getSupport()->getMesh()->getReverseConnectivity(MED_NODAL,typ);
324       indC = _myDField->getSupport()->getMesh()->getReverseConnectivityIndex(MED_NODAL,typ);
325       // calculate volume field on mesh
326       volume = _myDField->getSupport()->getMesh()->getVolume(_myDField->getSupport());
327     }
328     else{
329       // calculate reverse connectivity to have the list of elements which contains node i
330       revC = _myIField->getSupport()->getMesh()->getReverseConnectivity(MED_NODAL,typ);
331       indC = _myIField->getSupport()->getMesh()->getReverseConnectivityIndex(MED_NODAL,typ);
332       // calculate volume field on mesh
333       volume = _myIField->getSupport()->getMesh()->getVolume(_myIField->getSupport());
334     }
335     break;
336   default:
337     break;
338   }
339
340   for (int i=1; i<NumberOf+1; i++){
341
342     // if reference field is on elements get reference field on nodes
343     switch(typ){
344     case MED_CELL:
345       // listElements contains elements which contains a node of element i
346       listElements.clear();
347       
348       for(int j=indC[i-1];j<indC[i];j++){
349         // c element contains node i
350         int c=revC[j-1];
351         listElements.insert(c);
352       }
353
354       // calculate field value on node i 
355       sigmaV = 0.;
356       val = 0.;
357       for(elemIt=listElements.begin();elemIt!=listElements.end();elemIt++){
358         int elem = *elemIt;
359         double vol = volume->getValueIJ(elem,1);
360         if( vol != 0. ){
361           sigmaV += 1./vol;
362           if(_myDField)
363             val += _myDField->getValueIJ(elem,1)/vol;
364           else
365             val += ((double)_myIField->getValueIJ(elem,1))/vol;
366         }
367       }
368       val /= sigmaV;
369       break;
370     case MED_FACE:
371       throw SALOME_FILTER::FILTER_Gen::FilterError("Filter doesn't run on reference field on faces");
372       break;
373     case MED_EDGE:
374       throw SALOME_FILTER::FILTER_Gen::FilterError("Filter doesn't run on reference field on edges");
375       break;
376     case MED_NODE:
377       // read reference field value
378       if(_myDField)
379         val = _myDField->getValueIJ(i,1);
380       else
381         val = (double)_myIField->getValueIJ(i,1);
382       break;
383     case MED_ALL_ENTITIES:
384       throw SALOME_FILTER::FILTER_Gen::FilterError("Filter doesn't run on reference field on all entities");
385       break;
386     }
387
388     // set criteria field value
389     if( nbthresh == 1 ){
390       if( areaFlag )
391         if( val >= fthresh ) isGVal = true;
392         else isGVal = false;
393       else
394         if( val <= fthresh ) isGVal = true;
395         else isGVal = false;
396     }
397     else{
398       min = fthresh;
399       max = sthresh;
400       if(sthresh < fthresh){ 
401         min = sthresh;
402         max = fthresh;
403       }
404       if( areaFlag )
405         if( (val <= min) || (val >= max) ) isGVal = true;
406         else isGVal = false;    
407       else
408         if( (val >= min) && (val <= max) ) isGVal = true;
409         else isGVal = false;    
410     }
411     if( isGVal )
412       _criteria->setValueIJ(i,1,1);
413     else
414       _criteria->setValueIJ(i,1,0);
415   }
416 }
417
418 void Filter_Gen_i::createEnsightInputFiles()
419 {
420   int id;
421
422   MESSAGE("Calculate boundary");
423   // generate MED boundary of geometry
424   SUPPORT *supB = _mesh->getBoundaryElements(MED_FACE);
425
426   // call ensight driver MED to generate input ensight mesh ,
427   // input ensight boundary mesh and input criteria ensight field for filtoo
428   MESSAGE("Create ensight mesh");
429   ENSIGHT_MESH_WRONLY_DRIVER myMeshDriver("/tmp/input.case",_mesh);
430   myMeshDriver.addSupport(supB);
431 //   myMeshDriver.open();
432   myMeshDriver.write();
433 //   myMeshDriver.close();
434
435   MESSAGE("Create ensight field");
436   ENSIGHT_FIELD_WRONLY_DRIVER<int> myFieldDriver("/tmp/input.case",_criteria);
437 //   myFieldDriver.open();
438   myFieldDriver.write();
439 //   myFieldDriver.close();
440 }
441
442 void Filter_Gen_i::filtering()
443 {
444   string command;
445
446   MESSAGE("call filtoo");
447   // send filtoo command
448   command = "cd /tmp;filtoo -f input -o output > /tmp/filter.log";
449   MESSAGE(command);
450   system(command.c_str());
451
452   // destroy filtoo input files
453 //   command = "cd /tmp;rm -f input.*";
454 //   MESSAGE(command);
455 //   system(command.c_str());
456  
457 }
458
459 void Filter_Gen_i::projectFieldsOnDecimateMesh() throw(SALOME_FILTER::FILTER_Gen::FilterError)
460 {
461   string command;
462
463   // read of new mesh in ensight file
464   MESH* myMesh = new MESH();
465   ENSIGHT_MESH_RDONLY_DRIVER myEnsightMeshDriver("/tmp/output.case", myMesh) ;
466   myMesh->addDriver(ENSIGHT_DRIVER,"/tmp/output.case","myMesh",MED_EN::MED_LECT);
467   myMesh->read() ;
468
469   // have to call ensight driver MED to generate output MED file from filtoo output
470   _newMed = new ::MED();
471   _newMed->addMesh(myMesh);
472
473   // destroy filtoo output files
474 //   command = "cd /tmp;rm -f output.*";
475 //   MESSAGE(command);
476 //   system(command.c_str());
477
478   // get new mesh name
479   deque<string> meshesNames = _newMed->getMeshNames();
480   int numberOfMeshes = meshesNames.size();
481   if( numberOfMeshes != 1)
482     throw SALOME_FILTER::FILTER_Gen::FilterError("Unvalid number of meshes in filtoo output");
483
484   // new mesh generated by filtoo
485   _newMesh = _newMed->getMesh(meshesNames[0]);
486
487   // create support on nodes on all new mesh
488   SUPPORT *newSup = new SUPPORT(_newMesh,"Support",MED_NODE);
489
490   // read the id of nodes of output mesh, in input mesh
491   readMapping();
492
493   // read connectivity of new mesh to get neighbour node of created node
494   _connL = _newMesh->getConnectivityLength(MED_FULL_INTERLACE,MED_NODAL,MED_CELL,MED_ALL_ELEMENTS);
495   _conn = _newMesh->getConnectivity(MED_FULL_INTERLACE,MED_NODAL,MED_CELL,MED_ALL_ELEMENTS);
496   _connI = _newMesh->getConnectivityIndex(MED_NODAL,MED_CELL);
497
498   // read number of nodes on new mesh
499   int numberOfNodes = newSup->getNumberOfElements(MED_ALL_ELEMENTS);
500   int numberOfComponents;
501
502   deque<string> fieldsNames = _med->getFieldNames();
503   int numberOfFields = fieldsNames.size();
504
505   try{
506
507     // loop on fields
508     for (int i=0; i<numberOfFields; i++){
509
510       // is the input field the reference field?
511       bool isReferenceField= false;
512       if(_myDField){
513         if( strcmp(_myDField->getName().c_str(),fieldsNames[i].c_str()) == 0)
514           isReferenceField = true;
515       }
516       else
517         if( strcmp(_myIField->getName().c_str(),fieldsNames[i].c_str()) == 0)
518           isReferenceField = true;
519
520       deque<DT_IT_> myIteration = _med->getFieldIteration (fieldsNames[i]);
521       string meshName = _med->getField(fieldsNames[i],myIteration[0].dt,myIteration[0].it)->getSupport()->getMesh()->getName();
522
523       // we process only fields on input mesh
524       if( strcmp(meshName.c_str(),_mesh->getName().c_str()) == 0){
525
526         // loop on time steps
527         int numberOfIteration = myIteration.size();
528         for(int j=0;j<numberOfIteration;j++){
529
530           // select input field
531           MEDMEM::FIELD_* field = _med->getField(fieldsNames[i],myIteration[j].dt,myIteration[j].it);
532           FIELD<double> *myDField = NULL;
533           FIELD<double> *newDField = NULL;
534           FIELD<int> *myIField = NULL;
535           FIELD<int> *newIField = NULL;
536
537           if (dynamic_cast<MEDMEM::FIELD<double>*>(field)){
538             if(!isReferenceField){
539               // read input field on input file
540               myDField = new FIELD<double>(MEDMEM::MED_DRIVER,_file,fieldsNames[i],myIteration[j].dt,myIteration[j].it);
541             }
542             else{
543               myDField = _myDField;
544             }
545             // create new output field
546             newDField = new FIELD<double>(newSup,field->getNumberOfComponents());
547             newDField->setName(myDField->getName());
548           }
549           else{
550             if(!isReferenceField)
551               // read input field on input file
552               myIField = new FIELD<int>(MEDMEM::MED_DRIVER,_file,fieldsNames[i],myIteration[j].dt,myIteration[j].it);
553             else
554               myIField = _myIField;
555             // create new output field
556             newIField = new FIELD<int>(newSup,field->getNumberOfComponents());
557             newIField->setName(myIField->getName());
558           }
559           numberOfComponents = field->getNumberOfComponents();
560           
561           // loop on nodes on new field
562           for (int k=1; k<=numberOfNodes; k++){
563             // read number of nodes on input field
564             int l = getNodeNumber(k);
565             double dval;
566             int ival;
567             
568             for(int c=1;c<=numberOfComponents;c++){
569               // read value on input field
570               if(myDField)
571                 dval = myDField->getValueIJ(l,c);
572               else
573                 ival = myIField->getValueIJ(l,c);
574               
575               // write value on new field
576               if(newDField){
577                 newDField->setValueIJ(k,c,dval);
578               }
579               else
580                 newIField->setValueIJ(k,c,ival);
581             }
582           
583           }
584           if(newDField)
585             _newMed->addField(newDField);
586           else
587             _newMed->addField(newIField);
588           
589           // Destroy input field if not reference field
590           if(!isReferenceField)
591             if(myDField){
592               delete myDField->getSupport();
593               delete myDField;
594             }
595             else{
596               delete myIField->getSupport();
597               delete myIField;
598             }
599           
600         }
601       }
602     }
603   }
604   catch(SALOME_Exception){
605     throw SALOME_FILTER::FILTER_Gen::FilterError("Unvalid decimate mlesh created by filtoo");
606   }
607 }
608
609 void Filter_Gen_i::readMapping()
610 {
611   ifstream mapFile("/tmp/output.renum");
612
613   // read number of vertices to map
614   mapFile >> _nbvmap;
615   _map = new int[_nbvmap];
616   
617   for(int i=0;i<_nbvmap;i++)
618     mapFile >> _map[i];
619
620 }
621
622 int Filter_Gen_i::getNodeNumber(int num)
623 {
624   int oldnum = _map[num-1];
625
626   // if new node get neighbour node
627   if(oldnum == 0)
628     oldnum = _map[getNeighbourVertex(num)-1];
629   
630   return oldnum;
631 }
632
633 int Filter_Gen_i::getNeighbourVertex(int num) throw(SALOME_Exception)
634 {
635   int nnum;
636   int numberOfElements = _newMesh->getNumberOfElements(MED_CELL,MED_ALL_ELEMENTS);
637
638   int index;
639   // get index of created node in connectivity array
640   for(index=0;index<_connL;index++){
641     if(_conn[index] == num){
642
643       // get index of element which contain created node
644       int i;
645       for(i=1;i<=numberOfElements;i++)
646         if(_connI[i] > index)
647           break;
648
649       // search neighbour node which are in old mesh
650       for(int j=_connI[i-1];j<_connI[i];j++){
651         nnum = _conn[j-1];
652         if( _map[nnum-1] != 0)
653           break;
654       }
655
656       // if neighbour node in old mesh: go out loop, else continue
657       if(_map[nnum-1]!=0)
658         break;
659     }
660   }
661
662   // if no neighbour node in old mesh: throw exception
663   if(_map[nnum-1]==0)
664     throw SALOME_Exception("None of the neighbour node are in old mesh!!");
665
666   return nnum;
667 }
668
669 void Filter_Gen_i::createMedOutputFile(const char *outMedFile)
670 {
671   int id;
672
673   MESSAGE("Create MED mesh: "<<outMedFile);
674   id = _newMed->addDriver(MED_DRIVER,outMedFile,MED_EN::MED_ECRI);
675   _newMed->write(id);
676 }
677
678
679 //=============================================================================
680 /*!
681  * C factory, accessible with dlsym, after dlopen
682  */
683 //=============================================================================
684
685 extern "C"
686 {
687   PortableServer::ObjectId * FILTEREngine_factory(
688                                CORBA::ORB_ptr orb,
689                                PortableServer::POA_ptr poa,
690                                PortableServer::ObjectId * contId,
691                                const char *instanceName,
692                                const char *interfaceName)
693   {
694     MESSAGE("PortableServer::ObjectId * FilterEngine_factory()");
695     SCRUTE(interfaceName);
696     Filter_Gen_i * myFilter_Gen
697       = new Filter_Gen_i(orb, poa, contId, instanceName, interfaceName);
698     return myFilter_Gen->getId() ;
699   }
700 }