Salome HOME
Fix ZJFilter to deal with int64 family array
[tools/paravisaddons_common.git] / src / ZJFilter / plugin / ZJFilterModule / vtkZJFilter.cxx
1 // Copyright (C) 2021  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 // Author : Anthony Geay (EDF R&D)
20
21 #include "vtkZJFilter.h"
22
23 #include <vtkAdjacentVertexIterator.h>
24 #include <vtkAlgorithmOutput.h>
25 #include <vtkCallbackCommand.h>
26 #include <vtkCell.h>
27 #include <vtkCellData.h>
28 #include <vtkCellType.h>
29 #include <vtkCharArray.h>
30 #include <vtkCompositeDataToUnstructuredGridFilter.h>
31 #include <vtkDataArraySelection.h>
32 #include <vtkAOSDataArrayTemplate.h>
33 #include <vtkDataObjectTreeIterator.h>
34 #include <vtkDataSet.h>
35 #include <vtkDataSetAttributes.h>
36 #include <vtkDemandDrivenPipeline.h>
37 #include <vtkDoubleArray.h>
38 #include <vtkExecutive.h>
39 #include <vtkFloatArray.h>
40 #include <vtkInformation.h>
41 #include <vtkInformationDataObjectKey.h>
42 #include <vtkInformationDataObjectMetaDataKey.h>
43 #include <vtkInformationStringKey.h>
44 #include <vtkInformationVector.h>
45 #include <vtkLongArray.h>
46 #include <vtkMultiBlockDataSet.h>
47 #include <vtkMutableDirectedGraph.h>
48 #include <vtkObjectFactory.h>
49 #include <vtkPointData.h>
50 #include <vtkStreamingDemandDrivenPipeline.h>
51 #include <vtkStringArray.h>
52 #include <vtkThreshold.h>
53 #include <vtkUnstructuredGrid.h>
54
55 #include "InterpKernelException.hxx"
56 #include "MEDCouplingRefCountObject.hxx"
57
58 #include <cstdio>
59 #include <deque>
60 #include <map>
61 #include <sstream>
62
63 vtkStandardNewMacro(vtkZJFilter);
64
65 ///////////////////
66
67 vtkInformationDataObjectMetaDataKey* GetMEDReaderMetaDataIfAny()
68 {
69   static const char ZE_KEY[] = "vtkMEDReader::META_DATA";
70   MEDCoupling::GlobalDict* gd(MEDCoupling::GlobalDict::GetInstance());
71   if (!gd->hasKey(ZE_KEY))
72     return 0;
73   std::string ptSt(gd->value(ZE_KEY));
74   void* pt(0);
75   std::istringstream iss(ptSt);
76   iss >> pt;
77   return reinterpret_cast<vtkInformationDataObjectMetaDataKey*>(pt);
78 }
79
80 bool IsInformationOK(vtkInformation* info)
81 {
82   vtkInformationDataObjectMetaDataKey* key(GetMEDReaderMetaDataIfAny());
83   if (!key)
84     return false;
85   // Check the information contain meta data key
86   if (!info->Has(key))
87     return false;
88   // Recover Meta Data
89   vtkMutableDirectedGraph* sil(vtkMutableDirectedGraph::SafeDownCast(info->Get(key)));
90   if (!sil)
91     return false;
92   int idNames(0);
93   vtkAbstractArray* verticesNames(sil->GetVertexData()->GetAbstractArray("Names", idNames));
94   vtkStringArray* verticesNames2(vtkStringArray::SafeDownCast(verticesNames));
95   if (!verticesNames2)
96     return false;
97   for (int i = 0; i < verticesNames2->GetNumberOfValues(); i++)
98   {
99     vtkStdString& st(verticesNames2->GetValue(i));
100     if (st == "MeshesFamsGrps")
101       return true;
102   }
103   return false;
104 }
105
106 class Grp
107 {
108 public:
109   Grp(const std::string& name)
110     : _name(name)
111   {
112   }
113   void setFamilies(const std::vector<std::string>& fams) { _fams = fams; }
114   std::string getName() const { return _name; }
115   std::vector<std::string> getFamilies() const { return _fams; }
116
117 private:
118   std::string _name;
119   std::vector<std::string> _fams;
120 };
121
122 class Fam
123 {
124 public:
125   Fam(const std::string& name)
126   {
127     constexpr char ZE_SEP[] = "@@][@@";
128     std::size_t pos(name.find(ZE_SEP));
129     std::string name0(name.substr(0, pos)), name1(name.substr(pos + strlen(ZE_SEP)));
130     std::istringstream iss(name1);
131     iss >> _id;
132     _name = name0;
133   }
134   std::string getName() const { return _name; }
135   int getID() const { return _id; }
136
137 private:
138   std::string _name;
139   int _id;
140 };
141
142 void ExtractInfo(vtkInformationVector* inputVector, vtkUnstructuredGrid*& usgIn)
143 {
144   vtkInformation* inputInfo(inputVector->GetInformationObject(0));
145   vtkDataSet* input(0);
146   vtkDataSet* input0(vtkDataSet::SafeDownCast(inputInfo->Get(vtkDataObject::DATA_OBJECT())));
147   vtkMultiBlockDataSet* input1(
148     vtkMultiBlockDataSet::SafeDownCast(inputInfo->Get(vtkDataObject::DATA_OBJECT())));
149   if (input0)
150     input = input0;
151   else
152   {
153     if (!input1)
154       throw INTERP_KERNEL::Exception(
155         "Input dataSet must be a DataSet or single elt multi block dataset expected !");
156     if (input1->GetNumberOfBlocks() != 1)
157       throw INTERP_KERNEL::Exception(
158         "Input dataSet is a multiblock dataset with not exactly one block ! Use MergeBlocks or "
159         "ExtractBlocks filter before calling this filter !");
160     vtkDataObject* input2(input1->GetBlock(0));
161     if (!input2)
162       throw INTERP_KERNEL::Exception("Input dataSet is a multiblock dataset with exactly one block "
163                                      "but this single element is NULL !");
164     vtkDataSet* input2c(vtkDataSet::SafeDownCast(input2));
165     if (!input2c)
166       throw INTERP_KERNEL::Exception(
167         "Input dataSet is a multiblock dataset with exactly one block but this single element is "
168         "not a dataset ! Use MergeBlocks or ExtractBlocks filter before calling this filter !");
169     input = input2c;
170   }
171   if (!input)
172     throw INTERP_KERNEL::Exception("Input data set is NULL !");
173   usgIn = vtkUnstructuredGrid::SafeDownCast(input);
174   if (!usgIn)
175     throw INTERP_KERNEL::Exception("Input data set is not an unstructured mesh ! This filter works "
176                                    "only on unstructured meshes !");
177 }
178
179 void LoadFamGrpMapInfo(vtkMutableDirectedGraph* sil, std::string& meshName,
180   std::vector<Grp>& groups, std::vector<Fam>& fams)
181 {
182   if (!sil)
183     throw INTERP_KERNEL::Exception("LoadFamGrpMapInfo : internal error !");
184   int idNames(0);
185   vtkAbstractArray* verticesNames(sil->GetVertexData()->GetAbstractArray("Names", idNames));
186   vtkStringArray* verticesNames2(vtkStringArray::SafeDownCast(verticesNames));
187   vtkIdType id0;
188   bool found(false);
189   for (int i = 0; i < verticesNames2->GetNumberOfValues(); i++)
190   {
191     vtkStdString& st(verticesNames2->GetValue(i));
192     if (st == "MeshesFamsGrps")
193     {
194       id0 = i;
195       found = true;
196     }
197   }
198   if (!found)
199     throw INTERP_KERNEL::Exception(
200       "There is an internal error ! The tree on server side has not the expected look !");
201   vtkAdjacentVertexIterator* it0(vtkAdjacentVertexIterator::New());
202   sil->GetAdjacentVertices(id0, it0);
203   int kk(0), ll(0);
204   while (it0->HasNext())
205   {
206     vtkIdType id1(it0->Next());
207     std::string mName((const char*)verticesNames2->GetValue(id1));
208     meshName = mName;
209     vtkAdjacentVertexIterator* it1(vtkAdjacentVertexIterator::New());
210     sil->GetAdjacentVertices(id1, it1);
211     vtkIdType idZeGrps(it1->Next()); // zeGroups
212     vtkAdjacentVertexIterator* itGrps(vtkAdjacentVertexIterator::New());
213     sil->GetAdjacentVertices(idZeGrps, itGrps);
214     while (itGrps->HasNext())
215     {
216       vtkIdType idg(itGrps->Next());
217       Grp grp((const char*)verticesNames2->GetValue(idg));
218       vtkAdjacentVertexIterator* itGrps2(vtkAdjacentVertexIterator::New());
219       sil->GetAdjacentVertices(idg, itGrps2);
220       std::vector<std::string> famsOnGroup;
221       while (itGrps2->HasNext())
222       {
223         vtkIdType idgf(itGrps2->Next());
224         famsOnGroup.push_back(std::string((const char*)verticesNames2->GetValue(idgf)));
225       }
226       grp.setFamilies(famsOnGroup);
227       itGrps2->Delete();
228       groups.push_back(grp);
229     }
230     itGrps->Delete();
231     vtkIdType idZeFams(it1->Next()); // zeFams
232     it1->Delete();
233     vtkAdjacentVertexIterator* itFams(vtkAdjacentVertexIterator::New());
234     sil->GetAdjacentVertices(idZeFams, itFams);
235     while (itFams->HasNext())
236     {
237       vtkIdType idf(itFams->Next());
238       Fam fam((const char*)verticesNames2->GetValue(idf));
239       fams.push_back(fam);
240     }
241     itFams->Delete();
242   }
243   it0->Delete();
244 }
245
246 std::vector<std::string> FindConds(const std::vector<Grp>& grps)
247 {
248   constexpr char PAT[] = "COND_";
249   constexpr std::size_t SZ_PAT(sizeof(PAT) - 1);
250   std::vector<std::string> ret;
251   for (std::vector<Grp>::const_iterator it = grps.begin(); it != grps.end(); it++)
252   {
253     std::string name((*it).getName());
254     std::string part(name.substr(0, SZ_PAT));
255     if (part == PAT)
256       ret.push_back(name.substr(SZ_PAT, std::string::npos));
257   }
258   return ret;
259 }
260
261 constexpr char EPORT_PAT[] = "EPORT_";
262
263 std::vector<std::string> FindEports(
264   const std::string& condEntry, const std::vector<Grp>& grps, std::vector<std::string>& eportsZip)
265 {
266   std::vector<std::string> ret;
267   std::string commonPart(std::string(EPORT_PAT) + condEntry);
268   std::size_t commonPart_sz(commonPart.length());
269   for (std::vector<Grp>::const_iterator it = grps.begin(); it != grps.end(); it++)
270   {
271     std::string name((*it).getName());
272     std::string part(name.substr(0, commonPart_sz));
273     if (part == commonPart)
274     {
275       ret.push_back(name);
276       eportsZip.push_back(name.substr(commonPart_sz, std::string::npos));
277     }
278   }
279   return ret;
280 }
281
282 std::string BigestCommonPart(const std::string& s1, const std::string& s2)
283 {
284   std::size_t ls1(s1.length()), ls2(s2.length()), lb(0), lt(0);
285   std::string b, t;
286   if (ls1 >= ls2)
287   {
288     b = s1;
289     t = s2;
290     lb = ls1;
291     lt = ls2;
292   }
293   else
294   {
295     b = s2;
296     t = s1;
297     lb = ls2;
298     lt = ls1;
299   }
300   for (std::size_t l0 = lt; l0 > 0; l0--)
301   {
302     for (std::size_t l1 = 0; l1 < lt - l0 + 1; l1++)
303     {
304       std::string cand(t.substr(l1, l0));
305       if (b.find(cand) != std::string::npos)
306         return cand;
307     }
308   }
309   return std::string();
310 }
311
312 std::vector<int> DeduceIdsFrom(const std::vector<std::string>& eportsZip)
313 {
314   if (eportsZip.empty())
315     return std::vector<int>();
316   std::string ref(eportsZip[0]);
317   std::size_t sz(eportsZip.size());
318   for (std::size_t i = 1; i < sz; i++)
319     ref = BigestCommonPart(ref, eportsZip[i]);
320   std::vector<int> ret(sz);
321   for (std::size_t i = 0; i < sz; i++)
322   {
323     std::size_t pos(eportsZip[i].find(ref));
324     if (pos == std::string::npos)
325       throw INTERP_KERNEL::Exception("DeduceIdsFrom : internal error !");
326     std::string res(
327       eportsZip[i].substr(0, pos) + eportsZip[i].substr(pos + ref.length(), std::string::npos));
328     std::istringstream iss(res);
329     int val(0);
330     iss >> val;
331     ret[i] = val;
332   }
333   return ret;
334 }
335
336 std::set<int> FamiliesIdsFromGrp(
337   const std::vector<Grp>& grps, const std::vector<Fam>& fams, const std::string& grp)
338 {
339   bool found(false);
340   std::vector<std::string> locFams;
341   for (std::vector<Grp>::const_iterator it = grps.begin(); it != grps.end(); it++)
342   {
343     if ((*it).getName() == grp)
344     {
345       locFams = (*it).getFamilies();
346       found = true;
347       break;
348     }
349   }
350   if (!found)
351     throw INTERP_KERNEL::Exception("FamiliesIdsFromGrp : internal error !");
352   std::set<int> ret;
353   for (std::vector<Fam>::const_iterator it = fams.begin(); it != fams.end(); it++)
354   {
355     if (std::find(locFams.begin(), locFams.end(), (*it).getName()) != locFams.end())
356       ret.insert((*it).getID());
357   }
358   return ret;
359 }
360
361 vtkDataSet* FilterFamilies(vtkZJFilter* zeBoss, vtkDataSet* input, const std::set<int>& idsToKeep)
362 {
363   bool catchAll, catchSmth;
364   vtkNew<vtkThreshold> thres;
365   thres->AddObserver(vtkCommand::ProgressEvent, zeBoss->InternalProgressObserver);
366   constexpr int VTK_DATA_ARRAY_DELETE = vtkAOSDataArrayTemplate<double>::VTK_DATA_ARRAY_DELETE;
367   constexpr char ZE_SELECTION_ARR_NAME[] = "@@ZeSelection@@";
368   constexpr char arrNameOfFamilyField[] = "FamilyIdCell";
369   constexpr char associationForThreshold[] = "vtkDataObject::FIELD_ASSOCIATION_CELLS";
370   vtkDataSet* output(input->NewInstance());
371   output->ShallowCopy(input);
372   thres->SetInputData(output);
373   vtkDataSetAttributes *dscIn(input->GetCellData()), *dscIn2(input->GetPointData());
374   vtkDataSetAttributes *dscOut(output->GetCellData()), *dscOut2(output->GetPointData());
375   //
376   constexpr double vMin(1.), vMax(2.);
377   thres->ThresholdBetween(vMin, vMax);
378   // OK for the output
379   //
380   vtkDataArray* da(input->GetCellData()->GetScalars(arrNameOfFamilyField));
381   if (!da)
382     return 0;
383   std::string daName(da->GetName());
384   vtkLongArray* dai(vtkLongArray::SafeDownCast(da));
385   if (daName != arrNameOfFamilyField || !dai)
386     return 0;
387   //
388   int nbOfTuples(dai->GetNumberOfTuples());
389   vtkCharArray* zeSelection(vtkCharArray::New());
390   zeSelection->SetName(ZE_SELECTION_ARR_NAME);
391   zeSelection->SetNumberOfComponents(1);
392   char* pt(new char[nbOfTuples]);
393   zeSelection->SetArray(pt, nbOfTuples, 0, VTK_DATA_ARRAY_DELETE);
394   const long* inPtr(dai->GetPointer(0));
395   std::fill(pt, pt + nbOfTuples, 0);
396   catchAll = true;
397   catchSmth = false;
398   std::vector<bool> pt2(nbOfTuples, false);
399   for (std::set<int>::const_iterator it = idsToKeep.begin(); it != idsToKeep.end(); it++)
400   {
401     bool catchFid(false);
402     for (int i = 0; i < nbOfTuples; i++)
403       if (inPtr[i] == *it)
404       {
405         pt2[i] = true;
406         catchFid = true;
407       }
408     if (!catchFid)
409       catchAll = false;
410     else
411       catchSmth = true;
412   }
413   for (int ii = 0; ii < nbOfTuples; ii++)
414     if (pt2[ii])
415       pt[ii] = 2;
416   int idx(output->GetCellData()->AddArray(zeSelection));
417   output->GetCellData()->SetActiveAttribute(idx, vtkDataSetAttributes::SCALARS);
418   output->GetCellData()->CopyScalarsOff();
419   zeSelection->Delete();
420   //
421   thres->SetInputArrayToProcess(idx, 0, 0, associationForThreshold, ZE_SELECTION_ARR_NAME);
422   thres->Update();
423   vtkUnstructuredGrid* zeComputedOutput(thres->GetOutput());
424   zeComputedOutput->GetCellData()->RemoveArray(idx);
425   output->Delete();
426   zeComputedOutput->Register(0);
427   thres->RemoveObserver(zeBoss->InternalProgressObserver);
428   return zeComputedOutput;
429 }
430
431 ////////////////////
432
433 vtkZJFilter::vtkZJFilter()
434   : InternalProgressObserver(0)
435 {
436   this->InternalProgressObserver = vtkCallbackCommand::New();
437   this->InternalProgressObserver->SetCallback(&vtkZJFilter::InternalProgressCallbackFunction);
438   this->InternalProgressObserver->SetClientData(this);
439 }
440
441 vtkZJFilter::~vtkZJFilter()
442 {
443   this->InternalProgressObserver->Delete();
444 }
445
446 void vtkZJFilter::InternalProgressCallbackFunction(
447   vtkObject* arg, unsigned long, void* clientdata, void*)
448 {
449   reinterpret_cast<vtkZJFilter*>(clientdata)
450     ->InternalProgressCallback(static_cast<vtkAlgorithm*>(arg));
451 }
452
453 void vtkZJFilter::InternalProgressCallback(vtkAlgorithm* algorithm)
454 {
455   /*this->UpdateProgress(algorithm->GetProgress()); // To intercept progression of Threshold filters
456   if (this->AbortExecute)
457     {
458       algorithm->SetAbortExecute(1);
459       }*/
460 }
461
462 int vtkZJFilter::RequestInformation(
463   vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector)
464 {
465   // std::cerr << "########################################## vtkZJFilter::RequestInformation
466   // ##########################################" << std::endl;
467   try
468   {
469     vtkUnstructuredGrid* usgIn = nullptr;
470     ExtractInfo(inputVector[0], usgIn);
471   }
472   catch (INTERP_KERNEL::Exception& e)
473   {
474     std::ostringstream oss;
475     oss << "Exception has been thrown in vtkZJFilter::RequestInformation : " << e.what()
476         << std::endl;
477     if (this->HasObserver("ErrorEvent"))
478     {
479       this->InvokeEvent("ErrorEvent", const_cast<char*>(oss.str().c_str()));
480     }
481     else
482     {
483       vtkOutputWindowDisplayErrorText(const_cast<char*>(oss.str().c_str()));
484     }
485     vtkObject::BreakOnError();
486     return 0;
487   }
488   return 1;
489 }
490
491 int vtkZJFilter::RequestData(
492   vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector)
493 {
494   // std::cerr << "########################################## vtkZJFilter::RequestData
495   // ##########################################" << std::endl;
496   try
497   {
498     vtkInformation *inputInfo(inputVector[0]->GetInformationObject(0));
499     vtkInformation *outInfo(outputVector->GetInformationObject(0));
500     vtkUnstructuredGrid* usgIn(nullptr);
501     ExtractInfo(inputVector[0], usgIn);
502     std::string meshName;
503     std::vector<Grp> groups;
504     std::vector<Fam> fams;
505     if (IsInformationOK(inputInfo))
506     {
507       vtkMutableDirectedGraph* famGrpGraph(
508         vtkMutableDirectedGraph::SafeDownCast(inputInfo->Get(GetMEDReaderMetaDataIfAny())));
509       LoadFamGrpMapInfo(famGrpGraph, meshName, groups, fams);
510     }
511     std::vector<std::string> conds(FindConds(groups));
512     vtkUnstructuredGrid* output(
513       vtkUnstructuredGrid::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT())));
514     vtkNew<vtkMultiBlockDataSet> mb2;
515     std::size_t iblock(0);
516     for (std::vector<std::string>::const_iterator it = conds.begin(); it != conds.end();
517          it++, iblock++)
518     {
519       std::vector<std::string> eports2;
520       std::vector<std::string> eports(FindEports(*it, groups, eports2));
521       std::vector<int> ids(DeduceIdsFrom(eports2));
522       vtkNew<vtkMultiBlockDataSet> mb;
523       std::size_t sz(eports.size());
524       for (std::size_t i = 0; i < sz; i++)
525       {
526         std::set<int> zeIds(FamiliesIdsFromGrp(groups, fams, eports[i]));
527         //
528         vtkSmartPointer<vtkDataSet> ds(FilterFamilies(this, usgIn, zeIds));
529         {
530           vtkNew<vtkLongArray> arr;
531           arr->SetName((*it).c_str());
532           arr->SetNumberOfComponents(1);
533           int nbTuples(ds->GetNumberOfCells());
534           arr->SetNumberOfTuples(nbTuples);
535           long* pt(arr->GetPointer(0));
536           std::fill(pt, pt + nbTuples, ids[i]);
537           ds->GetCellData()->AddArray(arr);
538         }
539         this->UpdateProgress(double(i) / double(sz));
540         mb->SetBlock(i, ds);
541       }
542       vtkNew<vtkCompositeDataToUnstructuredGridFilter> cd;
543       cd->SetInputData(mb);
544       cd->SetMergePoints(0);
545       cd->Update();
546       mb2->SetBlock(iblock, cd->GetOutput());
547     }
548     {
549       vtkNew<vtkCompositeDataToUnstructuredGridFilter> cd2;
550       cd2->SetInputData(mb2);
551       cd2->SetMergePoints(0);
552       cd2->Update();
553       output->ShallowCopy(cd2->GetOutput());
554     }
555   }
556   catch (INTERP_KERNEL::Exception& e)
557   {
558     std::ostringstream oss;
559     oss << "Exception has been thrown in vtkZJFilter::RequestInformation : " << e.what()
560         << std::endl;
561     if (this->HasObserver("ErrorEvent"))
562       this->InvokeEvent("ErrorEvent", const_cast<char*>(oss.str().c_str()));
563     else
564       vtkOutputWindowDisplayErrorText(const_cast<char*>(oss.str().c_str()));
565     vtkObject::BreakOnError();
566     return 0;
567   }
568   return 1;
569 }
570
571 void vtkZJFilter::PrintSelf(ostream& os, vtkIndent indent)
572 {
573   this->Superclass::PrintSelf(os, indent);
574 }