CEPS  24.01
Cardiac ElectroPhysiology Simulator
FileInterpolatorSAFunc.cpp
Go to the documentation of this file.
1 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2  This file is part of CEPS.
3 
4  CEPS is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  CEPS is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with CEPS (see file LICENSE at root of project).
16  If not, see <https://www.gnu.org/licenses/>.
17 
18 
19  Copyright 2019-2024 Inria, Universite de Bordeaux
20 
21  Authors, in alphabetical order:
22 
23  Pierre-Elliott BECUE, Florian CARO, Yves COUDIERE(*), Andjela DAVIDOVIC,
24  Charlie DOUANLA-LONTSI, Marc FUENTES, Mehdi JUHOOR, Michael LEGUEBE(*),
25  Pauline MIGERDITICHAN, Valentin PANNETIER(*), Nejib ZEMZEMI.
26  * : currently active authors
27 
28 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
33 
34 #include <vtkCellLocator.h>
35 #include <vtkPointLocator.h>
36 #include <vtkUnstructuredGrid.h>
37 
40  CepsReal snapTimeRef,
41  const CepsString& filesBase,
42  CepsUInt tOrder
43 ):
44  m_problem (pb),
45  m_snapTimeRef (snapTimeRef),
46  m_tOrder (tOrder),
47  m_filesBase (filesBase),
48  m_nDigitsFile (1),
49  m_loadedTMin (0.),
50  m_loadedTMax (0.),
51  m_loadedSnapIdMin (0),
52  m_loadedSnapIdMax (0),
53  m_loadedData ({}),
54  m_loadedData0D ({}),
55  m_itpWeights ({}),
56  m_ptLocatorTolerance(1.e-8)
57 {
58 
60  "Must pass a valid pointer to problem to create interpolator from data files"
61  );
62 
63  // Check presence of files, and determine the number of digits in files (max is 6...)
64  CepsBool foundFile = false;
65  CepsUInt n = 1;
66 
67  while (not foundFile and n<7)
68  {
69  CepsString fileName = ceps::getDir(m_filesBase) + "/snapshots/" +
72  foundFile = ceps::fileExists(fileName+".vtk");
73  n++;
74  }
75 
76  m_nDigitsFile = n-1;
77  CEPS_ABORT_IF(not foundFile,
78  "Could not find the data files with base name " << m_filesBase <<
79  "***.vtk\n from which interpolation should be made.\n" <<
80  "Interpolation from files is available with vtk only."
81  );
82 
83  m_ptLocatorTolerance = m_problem->getParameters()->getReal("convergence closest point tolerance", m_ptLocatorTolerance);
84 
86 
87 }
88 
91 {
92 
93  loadFilesForTime(args.t);
94 
95  CepsVector<CepsReal> itpxvals(m_loadedData.size(),0.);
96  for (CepsUInt i=0; i<m_loadedData.size(); i++)
97  {
98  if (m_itpWeights.contains(args.dofId)) // Spatial dofs only
99  {
100  for (auto [vtkId,w] : m_itpWeights[args.dofId])
101  itpxvals[i] += w*m_loadedData[i][args.unknownId][vtkId];
102  // There might be a case, for unknowns that are not defined everywhere,
103  // for which a point is located outside the subdomain of definition of the unknown, but still
104  // in the mesh. In this case, the results is Nan.
105  // Then we interpolate with the non nans points
106  if (std::isnan(itpxvals[i]) or std::isinf(itpxvals[i]))
107  {
108  CepsMap<vtkIdType,CepsReal> corrected = {};
109  CepsReal sumW = 0.e0;
110  for (auto [vtkId,w] : m_itpWeights[args.dofId])
111  {
112  if (not (std::isnan(m_loadedData[i][args.unknownId][vtkId]) or
113  (std::isinf(m_loadedData[i][args.unknownId][vtkId]))))
114  {
115  corrected[vtkId] = w;
116  sumW += w;
117  }
118  }
119  // If all nans, then nan should be interpolated, I guess... ¯\_(ツ)_/¯
120  // We correct and reinterpolate only if there is an ok point
121  if (corrected.size()!=0)
122  {
123  for (auto& [vtkId,w]: corrected)
124  w /= sumW;
125  m_itpWeights[args.dofId] = corrected;
126  for (auto [vtkId,w] : m_itpWeights[args.dofId])
127  itpxvals[i] += w*m_loadedData[i][args.unknownId][vtkId];
128  }
129  }
130  }
131  else // 0D unknowns
132  {
133  itpxvals[i] = m_loadedData0D[i][args.unknownId];
134  ceps::checkNanOrInf(itpxvals[i]," in eval OD coeff "+ceps::toString(args.unknownId));
135  }
136  }
137 
139 
140 }
141 
142 CepsEnum
144 {
146 }
147 
148 
149 CepsEnum
151 {
152  return f->getFlags();
153 }
154 
155 void
157 {
158 
159  auto reader = vtkSmartPointer<vtkUnstructuredGridReader>::New();
160  reader->SetFileName(getVtkFileName(0).c_str());
161  reader->Update();
162 
163  auto pointLocator = vtkSmartPointer<vtkPointLocator>::New();
164  auto cellLocator = vtkSmartPointer<vtkCellLocator >::New();
165  pointLocator->SetDataSet(reader->GetOutput());
166  cellLocator ->SetDataSet(reader->GetOutput());
167  pointLocator->BuildLocator();
168  cellLocator ->BuildLocator();
169 
170  CepsReal* xRef = ceps::newArray<CepsReal>(3);
171 
173  auto dofs = sd->getDistributedDofs();
174 
175  for (auto toParse: {dofs->getOwned(),dofs->getHalo()})
176  for (DegreeOfFreedom* dof:toParse)
177  if (ceps::isValidPtr(dof->getVertex())) // No 0D unknowns
178  {
179 
180  CepsReal* x = dof->getVertex()->getCoordinates().data();
181  vtkIdType refPtId = pointLocator->FindClosestPoint(x);
182  reader->GetOutput()->GetPoint(refPtId,xRef);
183 
185 
186  // Found point coincide with parsed dof position (ideal)
187  CepsReal3D xx({x[0],x[1],x[2]});
188  CepsReal3D xxRef({xRef[0],xRef[1],xRef[2]});
189 
190  // if (ceps::approxEquals(x,xRef,3,1.e-14))
191  if (areSameArray(xx,xxRef))
192  {
193  tmpW[refPtId] = 1.;
194  }
195  else // use the cell locator
196  {
197  double cP[3],dist;
198  int subID,error;
199  vtkIdType refCellID;
200  vtkGenericCell* g = vtkGenericCell::New();
201  auto refCellPtsIDs = vtkSmartPointer<vtkIdList>::New();
202  // Get the closest cell
203  cellLocator->FindClosestPoint(x,cP,g,refCellID,subID,dist);
204 
205  CepsVector<CepsReal> weights(g->GetNumberOfPoints());
206 
207  // Locate point in cell
208  error = g->EvaluatePosition(x,cP,subID,xRef,dist,weights.data());
209  CEPS_ABORT_IF(error ==-1 or (error==0 and dist>m_ptLocatorTolerance),
210  "Error while locating points of numerical solution mesh in reference mesh cells.\n"
211  " You can increase search distance with the \"convergence closest point tolerance\"\n"
212  " parameter in the input file"
213  );
214 
215  reader->GetOutput()->GetCellPoints(refCellID,refCellPtsIDs);
216 
217  // #ifdef CEPS_DEBUG_ENABLED
218  // for (vtkIdType j=0;j<g->GetNumberOfPoints();j++)
219  // ceps::checkNanOrInf(weights[j],
220  // ceps::toString(j) + "-th weight of mesh cell " + ceps::toString(refCellID) +
221  // ", when localizing dof #" + ceps::toString(dof->getGlobalIndex())
222  // );
223  // #endif
224 
225  for (vtkIdType j=0;j<g->GetNumberOfPoints();j++)
226  tmpW[refCellPtsIDs->GetId(j)] = weights[j];
227  g->Delete();
228  }
229 
230  // Register the weights for this dof
231  m_itpWeights[dof->getGlobalIndex()] = tmpW;
232 
233  }
234 
235  ceps::destroyTabular(xRef);
236 
237  return;
238 }
239 
242 {
243  std::stringstream ss;
244  ss << ceps::getDir(m_filesBase) << "/snapshots/" << ceps::getBaseName(m_filesBase)
245  << "-" << std::setfill('0') << std::setw(m_nDigitsFile) << idSnap << ".vtk";
246  return CepsString(ss.str());
247 }
248 
249 void
251 {
252  // Determine IDs min and max for t
253  CepsUInt nRefSnaps = CepsUInt(std::floor((m_problem->getEndTime()-m_problem->getStartTime())/m_snapTimeRef));
254  CepsUInt idChunk = CepsUInt(std::floor((t-m_problem->getStartTime())/(m_snapTimeRef*m_tOrder)));
255 
256  CepsUInt idMin = std::max(CepsUInt(0U),std::min(idChunk*m_tOrder,nRefSnaps));
257  CepsUInt idMax = std::max(CepsUInt(0U),std::min(idMin+m_tOrder+1,nRefSnaps+1));
258 
259  if (idMin!=m_loadedSnapIdMin or idMax!=m_loadedSnapIdMax)
260  {
261  m_loadedData .clear();
262  m_loadedData0D.clear();
263 
264  for (CepsUInt i=idMin; i<idMax; i++)
265  {
268 
269  auto reader = vtkSmartPointer<vtkUnstructuredGridReader>::New();
270  reader->SetFileName(getVtkFileName(i).c_str());
271  reader->SetReadAllScalars(1);
272  reader->SetReadAllFields(1);
273  reader->Update();
274 
275  vtkDataArray* array = nullptr;
276  for (CepsInt i=0; i<reader->GetOutput()->GetPointData()->GetNumberOfArrays(); i++)
277  {
278  array = reader->GetOutput()->GetPointData()->GetArray(i);
279  // This check is probably useless
280  if (array->GetNumberOfComponents()==1)
281  {
282  CepsString name = array->GetName();
283  Unknown* u = m_problem->getUnknown(name);
284  // Read only for unknowns of the problem
285  if (ceps::isValidPtr(u))
286  {
287  vtkIdType nbData = array->GetNumberOfTuples();
288  CepsVector<CepsReal> data(nbData);
289  for (vtkIdType ptId = 0; ptId < nbData; ++ptId)
290  array->GetTuple(ptId,&data[ptId]);
291  tmpMap[u->getIdentifier()] = data;
292  }
293  }
294  }
295  m_loadedData.push_back(tmpMap);
296 
297  // OD unknowns
298  for (CepsInt i=0; i<reader->GetOutput()->GetFieldData()->GetNumberOfArrays(); i++)
299  {
300  array = reader->GetOutput()->GetFieldData()->GetArray(i);
301  if (array->GetNumberOfComponents()==1 and array->GetNumberOfTuples()==1)
302  {
303  CepsString name = array->GetName();
304  Unknown* u = m_problem->getUnknown(name);
305  // Read only for unknowns of the problem
306  if (ceps::isValidPtr(u))
307  {
308  CepsReal data;
309  array->GetTuple(0,&data);
310  tmpMap0D[u->getIdentifier()] = data;
311  }
312  }
313  }
314  m_loadedData0D.push_back(tmpMap0D);
315 
316  }
317 
318  m_loadedSnapIdMin = idMin;
319  m_loadedSnapIdMax = idMax;
320  m_loadedTMin = idMin*m_snapTimeRef;
321  m_loadedTMax = (idMax-1)*m_snapTimeRef;
322 
323  }
324 
325  return;
326 }
CepsBool areSameArray(const CepsArray< _Type, _N > &a, const CepsArray< _Type, _N > &b, const CepsReal error=1.)
Test equality of arrays, suitable for real numbers.
Definition: CepsArray.hpp:51
@ Time
Depends on time.
@ DofIndex
Use dof index to determine position.
#define CEPS_ABORT_IF(condition, message)
Stops the execution with a message if condition is true. If testing is enabled, only throws a runtime...
std::basic_string< CepsChar > CepsString
C++ format string.
Definition: CepsTypes.hpp:128
std::map< _Key, _Tp, _Compare, _Alloc > CepsMap
C++ map.
Definition: CepsTypes.hpp:196
int CepsEnum
Enum type.
Definition: CepsTypes.hpp:216
std::vector< _Type, _Alloc > CepsVector
C++ vector.
Definition: CepsTypes.hpp:155
bool CepsBool
Booleans.
Definition: CepsTypes.hpp:124
std::make_unsigned_t< CepsInt > CepsUInt
Unsigned version on CepsInt.
Definition: CepsTypes.hpp:109
float CepsReal
Need single precision floating point.
Definition: CepsTypes.hpp:100
CepsArray3< CepsReal > CepsReal3D
Three real scalars, used like this for compatibility in polynomials.
Definition: CepsTypes.hpp:178
int32_t CepsInt
Need 32 bit integer.
Definition: CepsTypes.hpp:106
Abstract Class for all numerical method (FE, FD, FV etc)
DistributedInfos< DegreeOfFreedom * > * getDistributedDofs() const
Get the stored Degree Of Freedom repartition.
Base class for creating PDEs to solve.
AbstractDiscretization * getSpatialDiscretization() const
Link to the spatial discretization (FE, FV, etc)
InputParameters * getParameters() const
Text parameters.
Unknown * getUnknown(const CepsString &label) const
Get an unknown by its name.
virtual CepsReal getStartTime() const
Returns 0. Here for compatibility.
virtual CepsReal getEndTime() const
Returns 0. Here for compatibility.
A degree of freedom for any kind of problem The dof can be associated to a geometrical element or not...
Functor that uses data from a collection of files to return a value at position x and time t.
CepsReal m_loadedTMax
Time of Max snapshot of currently loaded files.
CepsString getVtkFileName(CepsUInt i) const
Get full file name for snapshot i.
CepsUInt m_loadedSnapIdMax
Max snapshot ID of currently loaded files Loaded data, indexed by time, unknown id (array name in vtk...
virtual CepsReal eval(CepsStandardArgs args) final
Call operator to evaluate functor.
CepsEnum getFlags() const final
flag is Attribute only
CepsUInt m_loadedSnapIdMin
Min snapshot ID of currently loaded files.
CepsReal m_ptLocatorTolerance
Distance under which closest point search is tolerated (can be set in input file)
CepsUInt m_nDigitsFile
Number of digits of file number in collection of files.
FileInterpolatorSAFunc(AbstractPdeProblem *pb, CepsReal snapTimeRef, const CepsString &filesBase, CepsUInt tOrder=1)
Constructor with map. Flag is the expected flag of the coefficient used to interpolate.
void computeInterpolationWeights()
Computes the interpolation weights using geom locators.
void loadFilesForTime(CepsReal t)
Loads the appropriate files to perform time interpolation at time t.
CepsMap< CepsDofGlobalIndex, CepsMap< vtkIdType, CepsReal > > m_itpWeights
Precomputed interpolation weights. Built using point/cell locator.
AbstractPdeProblem * m_problem
Link to problem.
CepsUInt m_tOrder
Time interpolation order.
CepsReal m_loadedTMin
Time of Min snapshot of currently loaded files.
CepsVector< CepsMap< CepsUnknownIndex, CepsVector< CepsReal > > > m_loadedData
CepsVector< CepsMap< CepsUnknownIndex, CepsReal > > m_loadedData0D
Loaded data, indexed by time, unknown id (array name in vtk file)
CepsString m_filesBase
Base names of data files.
CepsReal m_snapTimeRef
Reference output period.
CepsReal getReal(const keyType &key) const
Reads a floating point value from configuration.
A class used to defined an unknown of a PDE problem The unknown can be defined on a specific region,...
Definition: Unknown.hpp:45
CepsUnknownIndex getIdentifier() const
Get the identifier of the unknown.
Definition: Unknown.cpp:82
CepsReal interpolateLagrange(CepsReal x, const CepsVector< CepsReal > &f)
Computes the interpolate of f at point x. assumes f is given at equidistant points on [0,...
CepsString getDir(const CepsString &str)
Get a substring of s, from beginning of s to the last '/' character. Example: "/home/someone/file....
Definition: CepsString.cpp:521
CepsString toString(_Tp value)
Convert a given value to a string (input has to be compatible with std::to_string)
Definition: CepsString.hpp:409
void destroyTabular(_Type &)
Destroy[delete] any type.
Definition: CepsMemory.hpp:149
CepsBool isValidPtr(_Type *ptr)
Tells if pointer is not null.
Definition: CepsMemory.hpp:61
const _Type & max(const CepsVector< _Type, _Alloc > &vec)
Returns the maximum of the vector, const version.
Definition: CepsVector.hpp:464
const _Type & min(const CepsVector< _Type, _Alloc > &vec)
Returns the minimum of the vector, const version.
Definition: CepsVector.hpp:448
CepsEnum getFlagsOf(ArraySAFunc< _Result > *f)
get functor options
CepsBool isNullPtr(_Type *ptr)
Tells if passed pointer is null.
Definition: CepsMemory.hpp:45
void checkNanOrInf(CepsReal v, CepsString message="")
Stops if value is NaN or infty.
CepsString getBaseName(const CepsString &str)
Extracts the base of a file name, without path, nor extension. Ex: getBaseName("/path/to/myfile....
Definition: CepsString.cpp:563
CepsBool fileExists(const CepsString &fileName, const CepsString &directory)
Definition: CepsString.cpp:595
Structure used to pass arguments to SAFunc (see pde directory) The flags of the SAFunc allows extract...
Definition: CepsTypes.hpp:239
CepsReal t
time
Definition: CepsTypes.hpp:240
CepsDofGlobalIndex dofId
dof index
Definition: CepsTypes.hpp:244
CepsUnknownIndex unknownId
unknown index
Definition: CepsTypes.hpp:247