Salome HOME
99e69f805f108c87293ae5431cee2f30209caf1a
[modules/multipr.git] / src / MULTIPR / MULTIPR_Obj.cxx
1 // Project MULTIPR, IOLS WP1.2.1 - EDF/CS
2 // Partitioning/decimation module for the SALOME v3.2 platform
3
4 /**
5  * \file    MULTIPR_Obj.cxx
6  *
7  * \brief   see MULTIPR_Obj.hxx
8  *
9  * \author  Olivier LE ROUX - CS, Virtual Reality Dpt
10  * 
11  * \date    01/2007
12  */
13
14 //*****************************************************************************
15 // Includes section
16 //*****************************************************************************
17
18 #include "MULTIPR_Obj.hxx"
19 #include "MULTIPR_Exceptions.hxx"
20 #include "MULTIPR_Mesh.hxx"
21 #include "MULTIPR_MeshDis.hxx"
22 #include "MULTIPR_Utils.hxx"
23
24 #include <stdio.h>
25 #include <iostream>
26
27 using namespace std;
28
29
30 namespace multipr
31 {
32
33
34 //*****************************************************************************
35 // Class Obj implementation
36 //*****************************************************************************
37
38 Obj::Obj() 
39 {
40         mMeshDis = NULL;
41         
42         reset(); 
43 }
44
45
46 Obj::~Obj()  
47
48         reset();  
49 }
50
51
52 void Obj::reset() 
53
54         mMEDfilename     = "";
55         mMeshName        = "";
56         mState           = MULTIPR_OBJ_STATE_RESET;
57         
58         if (mMeshDis != NULL) { delete mMeshDis; mMeshDis = NULL; }
59 }
60
61
62 void Obj::create(const char* pMEDfilename)
63 {
64         if (pMEDfilename == NULL) throw multipr::NullArgumentException("file name must not be NULL", __FILE__, __LINE__);
65         
66         // reset everything before associating a new MED file to this object
67         reset();
68         
69         mMEDfilename = pMEDfilename;
70         
71         // check if file exists
72         FILE* f = fopen(pMEDfilename, "rb");
73         if (f == 0) 
74         {
75                 // file does not exist
76                 mState = MULTIPR_OBJ_STATE_ERROR;
77                 throw FileNotFoundException("file not found", __FILE__, __LINE__);
78         }
79         fclose(f);
80         
81         // test whether it is a sequential MED file or a distributed MED file
82         med_idt file = MEDouvrir(const_cast<char*>(pMEDfilename), MED_LECTURE); // open sequential MED file for reading
83         if (file > 0)
84         {
85                 // sequential MED file has been sucessfuly openened
86                 
87                 // CASE 1: sequential MED file
88                 med_int ret = MEDfermer(file);
89                 
90                 if (ret != 0) 
91                 {
92                         // error while closing sequential MED file
93                         mState = MULTIPR_OBJ_STATE_ERROR;
94                         throw multipr::IOException("i/o error while closing MED file", __FILE__, __LINE__);
95                 }
96                 
97                 mState = MULTIPR_OBJ_STATE_SEQ_INIT;
98                 cout << "Sequential MED file " << pMEDfilename << " has been successfuly opened" << endl;
99         }
100         else
101         {
102                 // CASE 2: distributed MED file?
103                 try
104                 {
105                         mMeshDis = new multipr::MeshDis();
106                         mMeshDis->readDistributedMED(pMEDfilename);
107                 
108                         mState = MULTIPR_OBJ_STATE_DIS;
109                         cout << "Distributed MED file " << pMEDfilename << " has been successfuly opened" << endl;
110                 }
111                 catch (...)
112                 {
113                         // neither a sequential MED file, nor a distributed MED file => error
114                         mState = MULTIPR_OBJ_STATE_ERROR;
115                         throw IOException("file is nor a sequential MED file, neither a distributed MED file", __FILE__, __LINE__);
116                 }
117         }
118 }
119
120
121 void Obj::setMesh(const char* pMeshName)
122 {
123         // setMesh() is only available for sequential MED file (not distributed MED file)
124         if ((mState != MULTIPR_OBJ_STATE_SEQ_INIT) &&
125             (mState != MULTIPR_OBJ_STATE_SEQ)) throw IllegalStateException("expected a sequential MED file", __FILE__, __LINE__);
126         
127         mMeshName = pMeshName;
128         
129         // change state to MULTIPR_OBJ_STATE_SEQ (in case of state=MULTIPR_OBJ_STATE_SEQ_INIT)
130         mState = MULTIPR_OBJ_STATE_SEQ;
131 }
132
133
134 vector<string> Obj::getMeshes() const
135 {
136         // test whether it is a sequential MED file or a distributed MED file
137         if ((mState == MULTIPR_OBJ_STATE_SEQ_INIT) ||
138             (mState == MULTIPR_OBJ_STATE_SEQ))
139         {
140                 // CASE 1: sequential MED file
141                 return multipr::getListMeshes(mMEDfilename.c_str());
142         }
143         else
144         {
145                 // CASE 2: distributed MED file
146                 if (mMeshDis == NULL)
147                 {
148                         throw IllegalStateException("distributed MED file should not be NULL", __FILE__, __LINE__);
149                 }
150                 
151                 return mMeshDis->getMeshes();
152         }
153 }
154
155
156 vector<string> Obj::getFields() const
157 {
158         // test whether it is a sequential MED file or a distributed MED file
159         if ((mState == MULTIPR_OBJ_STATE_SEQ_INIT) ||
160             (mState == MULTIPR_OBJ_STATE_SEQ)) 
161         {
162                 // CASE 1: sequential MED file
163                 vector<pair<string, int> > tmp = multipr::getListFields(mMEDfilename.c_str());
164                 
165                 vector<string> res;
166                 for (int i = 0 ; i < tmp.size() ; i++)
167                 {
168                         res.push_back(tmp[i].first);
169                 }
170                 
171                 return res;
172         }
173         else
174         {
175                 // CASE 2: distributed MED file
176                 if (mMeshDis == NULL) throw IllegalStateException("distributed MED file should not be NULL", __FILE__, __LINE__);
177                 
178                 return mMeshDis->getFields();
179         }
180 }
181
182
183 int Obj::getTimeStamps(const char* pFieldName) const
184 {
185         // test whether it is a sequential MED file or a distributed MED file
186         if ((mState == MULTIPR_OBJ_STATE_SEQ_INIT) ||
187             (mState == MULTIPR_OBJ_STATE_SEQ)) 
188         {
189                 // CASE 1: sequential MED file
190                 vector<pair<string, int> > tmp = multipr::getListFields(mMEDfilename.c_str());
191         
192                 for (int i = 0 ; i < tmp.size() ; i++)
193                 {
194                         if (strcmp(tmp[i].first.c_str(), pFieldName) == 0)
195                         {
196                                 return tmp[i].second;
197                         }
198                 }
199                 
200                 // pFieldName not found in the list of fields
201                 return 0;
202         }
203         else
204         {
205                 // CASE 2: distributed MED file
206                 if (mMeshDis == NULL) throw IllegalStateException("distributed MED file should not be NULL", __FILE__, __LINE__);
207                 
208                 return mMeshDis->getTimeStamps(pFieldName);
209         }
210 }
211
212
213 vector<string> Obj::getParts() const
214 {
215         // getParts() is only available for distributed MED file (not sequential MED file)
216         if ((mState != MULTIPR_OBJ_STATE_DIS) &&
217             (mState != MULTIPR_OBJ_STATE_DIS_MEM)) throw IllegalStateException("expected a distributed MED file", __FILE__, __LINE__);
218         
219         return getListParts();
220 }
221
222
223 string Obj::getPartInfo(const char* pPartName) const
224 {
225         // getParts() is only available for distributed MED file (not sequential MED file)
226         if ((mState != MULTIPR_OBJ_STATE_DIS) &&
227             (mState != MULTIPR_OBJ_STATE_DIS_MEM)) throw IllegalStateException("expected a distributed MED file", __FILE__, __LINE__);
228         
229         if (mMeshDis == NULL) throw IllegalStateException("distributed MED file should not be NULL", __FILE__, __LINE__);
230         
231         return mMeshDis->getPartInfo(pPartName);
232         
233 }
234
235
236 vector<string> Obj::partitionneDomaine()
237 {
238         if (mState == MULTIPR_OBJ_STATE_SEQ_INIT) throw IllegalStateException("use setMesh() before", __FILE__, __LINE__);
239         
240         // partitionneDomaine() is only available for sequential MED file (not distributed MED file)
241         if (mState != MULTIPR_OBJ_STATE_SEQ) throw IllegalStateException("unexpected operation", __FILE__, __LINE__);
242         
243         //-------------------------------------------------------------
244         // Read the sequential mesh
245         //-------------------------------------------------------------
246         cout << "Read sequential MED file: " << mMEDfilename << ": please wait... " << endl;
247         
248         Mesh mesh;
249         mesh.readSequentialMED(mMEDfilename.c_str(), mMeshName.c_str());
250         cout << mesh << endl;
251         
252         //-------------------------------------------------------------
253         // Build distributed mesh from groups
254         //-------------------------------------------------------------
255         cout << "Build distributed mesh: please wait... " << endl;
256         try
257         {
258                 mMeshDis = mesh.splitGroupsOfElements();
259         }
260         catch (RuntimeException& e)
261         {
262                 delete mMeshDis;
263                 mMeshDis = NULL;
264                 throw e;
265         }
266         
267         mState = MULTIPR_OBJ_STATE_DIS_MEM;
268         
269         return getListParts();
270 }
271
272
273 vector<string> Obj::partitionneGrain(
274         const char* pPartName, 
275         int         pNbParts, 
276         int         pPartitionner)
277 {
278         if (mMeshDis == NULL) throw IllegalStateException("expected a distributed MED file", __FILE__, __LINE__);
279         if (pPartName == NULL) throw NullArgumentException("", __FILE__, __LINE__);
280         if (pNbParts < 2) throw IllegalArgumentException("", __FILE__, __LINE__);
281         if ((pPartitionner != 0) && (pPartitionner != 1)) throw IllegalArgumentException("partitionner should be 0=METIS or 1=SCOTCH", __FILE__, __LINE__);
282
283         // partitionneGrain() is only available for distributed MED file (not sequential MED file)
284         if ((mState != MULTIPR_OBJ_STATE_DIS_MEM) &&
285             (mState != MULTIPR_OBJ_STATE_DIS)) throw IllegalStateException("unexpected operation", __FILE__, __LINE__);
286         
287         // if distributed MED file is currently in memory, then write to disk before performing partitionneGrain()
288         // (because MEDSPLIITER starts from a file)
289         if (mState == MULTIPR_OBJ_STATE_DIS_MEM)
290         {
291                 //-----------------------------------------------------
292                 // Write distributed mesh
293                 //-----------------------------------------------------
294                 cout << "Write distributed mesh: please wait... " << endl;
295                 string strPrefix = removeExtension(mMEDfilename.c_str(), ".med");
296                 mMeshDis->writeDistributedMED(strPrefix.c_str());
297                 
298                 mMEDfilename = mMeshDis->getFilename();
299                 
300                 delete mMeshDis;
301                 
302                 //---------------------------------------------------------------------
303                 // Read the distributed mesh
304                 //--------------------------------------------------------------------- 
305                 int ret = MEDformatConforme(mMEDfilename.c_str());
306                 if (ret == 0) throw IOException("waiting for a distributed MED file (not a sequential one)", __FILE__, __LINE__);
307         
308                 mMeshDis = new MeshDis();
309                 mMeshDis->readDistributedMED(mMEDfilename.c_str());
310                 
311                 mState = MULTIPR_OBJ_STATE_DIS;
312         }
313
314         //---------------------------------------------------------------------
315         // Split the given part (pGroupName)
316         //---------------------------------------------------------------------
317         mMeshDis->splitPart(pPartName, pNbParts, pPartitionner);
318         cout << mMeshDis << endl;
319
320         //---------------------------------------------------------------------
321         // Write new distributed mesh
322         //---------------------------------------------------------------------
323         string strPrefix = multipr::removeExtension(mMEDfilename.c_str(), ".med");
324         mMeshDis->writeDistributedMED(strPrefix.c_str());
325         
326         //---------------------------------------------------------------------
327         // Read the distributed mesh
328         //---------------------------------------------------------------------
329         delete mMeshDis;
330         mMeshDis = new MeshDis();
331         //cout << "read dis MED file: filename=" << mMEDfilename << endl;
332         mMeshDis->readDistributedMED(mMEDfilename.c_str());
333         
334         return getListParts();
335 }
336
337
338 vector<string> Obj::decimePartition(
339         const char* pPartName,
340         const char* pFieldName,
341         int         pFieldIt,
342         const char* pFilterName,
343         double      pTmed,
344         double      pTlow,
345         double      pRadius,
346         int         pBoxing)
347 {
348         
349         // decimePartition() is only available for distributed MED file (not sequential MED file)
350         if ((mState != MULTIPR_OBJ_STATE_DIS_MEM) &&
351             (mState != MULTIPR_OBJ_STATE_DIS)) throw IllegalStateException("unexpected operation", __FILE__, __LINE__);
352             
353         if (mMeshDis == NULL) throw IllegalStateException("expected a distributed MED file", __FILE__, __LINE__);
354         
355         //---------------------------------------------------------------------
356         // Decimate
357         //---------------------------------------------------------------------
358         mMeshDis->decimatePart(
359                 pPartName, 
360                 pFieldName,
361                 pFieldIt,
362                 pFilterName,
363                 pTmed,
364                 pTlow,
365                 pRadius,
366                 pBoxing);
367                 
368         mState = MULTIPR_OBJ_STATE_DIS_MEM;
369         
370         return getListParts();
371 }
372
373
374 vector<string> Obj::getListParts() const
375 {
376         if (mMeshDis == NULL) throw IllegalStateException("not a distributed mesh", __FILE__, __LINE__);
377         
378         vector<string> names;
379         
380         int numParts = mMeshDis->getNumParts();
381         for (int i = 0 ; i < numParts ; i++)
382         {
383                 names.push_back( mMeshDis->getPart(i)->getPartName() );
384         }
385         
386         return names;
387 }
388
389
390 void Obj::save()
391 {
392         // only save file if it is a distributed MED file currently in memory
393         if (mState == MULTIPR_OBJ_STATE_DIS_MEM)
394         {
395                 //-------------------------------------------------------------
396                 // Write new distributed mesh
397                 //-------------------------------------------------------------
398                 string strPrefix = multipr::removeExtension(mMEDfilename.c_str(), ".med");
399                 mMeshDis->writeDistributedMED(strPrefix.c_str());               
400                 mMEDfilename = mMeshDis->getFilename();
401                 
402                 cout << "Write MED master file: " << mMEDfilename << ": OK" << endl;
403                 
404                 //-------------------------------------------------------------
405                 // Read the distributed mesh
406                 //-------------------------------------------------------------
407                 delete mMeshDis;
408                 mMeshDis = new MeshDis();
409                 mMeshDis->readDistributedMED(mMEDfilename.c_str());
410                 
411                 mState = MULTIPR_OBJ_STATE_DIS;
412         }
413 }
414
415
416 ostream& operator<<(ostream& pOs, Obj& pO)
417 {
418         pOs << "Obj:" << endl;
419         pOs << "    Name:" << pO.mMEDfilename << endl;
420         
421         return pOs;
422 }
423
424
425 } // namespace multipr
426
427 // EOF