source: XIOS/dev/dev_olga/src/transformation/axis_algorithm_interpolate.cpp @ 1612

Last change on this file since 1612 was 1612, checked in by oabramkina, 5 years ago

Dev: adding exception handling.

To activate it, compilation flag -DXIOS_EXCEPTION should be added.

File size: 14.5 KB
RevLine 
[630]1/*!
2   \file axis_algorithm_interpolate.cpp
3   \author Ha NGUYEN
4   \since 23 June 2015
5   \date 02 Jul 2015
6
7   \brief Algorithm for interpolation on an axis.
8 */
9#include "axis_algorithm_interpolate.hpp"
[933]10#include "axis.hpp"
11#include "interpolate_axis.hpp"
[630]12#include <algorithm>
13#include "context.hpp"
14#include "context_client.hpp"
15#include "utils.hpp"
[827]16#include "grid.hpp"
[933]17#include "grid_transformation_factory_impl.hpp"
[827]18#include "distribution_client.hpp"
[1412]19#include "timer.hpp"
[630]20
21namespace xios {
[933]22CGenericAlgorithmTransformation* CAxisAlgorithmInterpolate::create(CGrid* gridDst, CGrid* gridSrc,
23                                                                   CTransformation<CAxis>* transformation,
24                                                                   int elementPositionInGrid,
25                                                                   std::map<int, int>& elementPositionInGridSrc2ScalarPosition,
26                                                                   std::map<int, int>& elementPositionInGridSrc2AxisPosition,
27                                                                   std::map<int, int>& elementPositionInGridSrc2DomainPosition,
28                                                                   std::map<int, int>& elementPositionInGridDst2ScalarPosition,
29                                                                   std::map<int, int>& elementPositionInGridDst2AxisPosition,
30                                                                   std::map<int, int>& elementPositionInGridDst2DomainPosition)
[1612]31TRY
[933]32{
33  std::vector<CAxis*> axisListDestP = gridDst->getAxis();
34  std::vector<CAxis*> axisListSrcP  = gridSrc->getAxis();
[630]35
[933]36  CInterpolateAxis* interpolateAxis = dynamic_cast<CInterpolateAxis*> (transformation);
37  int axisDstIndex = elementPositionInGridDst2AxisPosition[elementPositionInGrid];
38  int axisSrcIndex = elementPositionInGridSrc2AxisPosition[elementPositionInGrid];
39
40  return (new CAxisAlgorithmInterpolate(axisListDestP[axisDstIndex], axisListSrcP[axisSrcIndex], interpolateAxis));
41}
[1612]42CATCH
[933]43
44bool CAxisAlgorithmInterpolate::registerTrans()
[1612]45TRY
[933]46{
47  CGridTransformationFactory<CAxis>::registerTransformation(TRANS_INTERPOLATE_AXIS, create);
48}
[1612]49CATCH
[933]50
[630]51CAxisAlgorithmInterpolate::CAxisAlgorithmInterpolate(CAxis* axisDestination, CAxis* axisSource, CInterpolateAxis* interpAxis)
[827]52: CAxisAlgorithmTransformation(axisDestination, axisSource), coordinate_(), transPosition_()
[1612]53TRY
[630]54{
55  interpAxis->checkValid(axisSource);
56  order_ = interpAxis->order.getValue();
[827]57  if (!interpAxis->coordinate.isEmpty())
[630]58  {
[827]59    coordinate_ = interpAxis->coordinate.getValue();
60    this->idAuxInputs_.resize(1);
61    this->idAuxInputs_[0] = coordinate_;
[630]62  }
63}
[1612]64CATCH
[630]65
66/*!
67  Compute the index mapping between axis on grid source and one on grid destination
68*/
[827]69void CAxisAlgorithmInterpolate::computeIndexSourceMapping_(const std::vector<CArray<double,1>* >& dataAuxInputs)
[1612]70TRY
[630]71{
[1412]72  CTimer::get("CAxisAlgorithmInterpolate::computeIndexSourceMapping_").resume() ;
[630]73  CContext* context = CContext::getCurrent();
74  CContextClient* client=context->client;
75  int nbClient = client->clientSize;
[827]76  CArray<bool,1>& axisMask = axisSrc_->mask;
[666]77  int srcSize  = axisSrc_->n_glo.getValue();
[827]78  std::vector<CArray<double,1> > vecAxisValue;
[630]79
[827]80  // Fill in axis value from coordinate
81  fillInAxisValue(vecAxisValue, dataAuxInputs);
[896]82  std::vector<double> valueSrc(srcSize);
83  std::vector<double> recvBuff(srcSize);
84  std::vector<int> indexVec(srcSize);
[630]85
[827]86  for (int idx = 0; idx < vecAxisValue.size(); ++idx)
87  {
88    CArray<double,1>& axisValue = vecAxisValue[idx];
89    retrieveAllAxisValue(axisValue, axisMask, recvBuff, indexVec);
90    XIOSAlgorithms::sortWithIndex<double, CVectorStorage>(recvBuff, indexVec);
[896]91    for (int i = 0; i < srcSize; ++i) valueSrc[i] = recvBuff[indexVec[i]];
[912]92    computeInterpolantPoint(valueSrc, indexVec, idx);
[827]93  }
[1412]94  CTimer::get("CAxisAlgorithmInterpolate::computeIndexSourceMapping_").suspend() ;
[630]95}
[1612]96CATCH
[630]97
98/*!
99  Compute the interpolant points
100  Assume that we have all value of axis source, with these values, need to calculate weight (coeff) of Lagrange polynomial
101  \param [in] axisValue all value of axis source
[896]102  \param [in] tranPos position of axis on a domain
[630]103*/
[912]104void CAxisAlgorithmInterpolate::computeInterpolantPoint(const std::vector<double>& axisValue,
105                                                        const std::vector<int>& indexVec,
106                                                        int transPos)
[1612]107TRY
[630]108{
109  std::vector<double>::const_iterator itb = axisValue.begin(), ite = axisValue.end();
[937]110  std::vector<double>::const_iterator itLowerBound, itUpperBound, it, iteRange, itfirst, itsecond;
[630]111  const double sfmax = NumTraits<double>::sfmax();
[937]112  const double precision = NumTraits<double>::dummy_precision();
[630]113
[666]114  int ibegin = axisDest_->begin.getValue();
[630]115  CArray<double,1>& axisDestValue = axisDest_->value;
116  int numValue = axisDestValue.numElements();
117  std::map<int, std::vector<std::pair<int,double> > > interpolatingIndexValues;
118
119  for (int idx = 0; idx < numValue; ++idx)
120  {
[918]121    bool outOfRange = false;
[630]122    double destValue = axisDestValue(idx);
[918]123    if (destValue < *itb) outOfRange = true;
124
[630]125    itLowerBound = std::lower_bound(itb, ite, destValue);
126    itUpperBound = std::upper_bound(itb, ite, destValue);
127    if ((ite != itUpperBound) && (sfmax == *itUpperBound)) itUpperBound = ite;
128
[918]129    if ((ite == itLowerBound) || (ite == itUpperBound)) outOfRange = true;
[937]130
[918]131    // We don't do extrapolation FOR NOW, maybe in the future
132    if (!outOfRange)
[630]133    {
[918]134      if ((itLowerBound == itUpperBound) && (itb != itLowerBound)) --itLowerBound;
[937]135      double distanceToLower = destValue - *itLowerBound;
136      double distanceToUpper = *itUpperBound - destValue;
[630]137      int order = (order_ + 1) - 2;
[937]138      bool down = (distanceToLower < distanceToUpper) ? true : false;
[630]139      for (int k = 0; k < order; ++k)
140      {
141        if ((itb != itLowerBound) && down)
142        {
143          --itLowerBound;
[937]144          distanceToLower = destValue - *itLowerBound;
145          down = (distanceToLower < distanceToUpper) ? true : false;
[630]146          continue;
147        }
148        if ((ite != itUpperBound) && (sfmax != *itUpperBound))
149        {
150          ++itUpperBound;
[937]151          distanceToUpper = *itUpperBound - destValue;
152          down = (distanceToLower < distanceToUpper) ? true : false;
153
[630]154        }
155      }
156
[918]157      iteRange = (ite == itUpperBound) ? itUpperBound : itUpperBound + 1;
[937]158      itsecond = it = itLowerBound; ++itsecond;
159      while (it < iteRange)
[918]160      {
[1324]161        while ( (itsecond < ite) && ((*itsecond -*it) < precision) )
[937]162        { ++itsecond; ++it; }
[918]163        int index = std::distance(itb, it);
164        interpolatingIndexValues[idx+ibegin].push_back(make_pair(indexVec[index],*it));
[937]165        ++it; ++itsecond;
[918]166      }
[937]167
[630]168    }
169  }
[827]170  computeWeightedValueAndMapping(interpolatingIndexValues, transPos);
[630]171}
[1612]172CATCH
[630]173
174/*!
175  Compute weight (coeff) of Lagrange's polynomial
176  \param [in] interpolatingIndexValues the necessary axis value to calculate the coeffs
177*/
[827]178void CAxisAlgorithmInterpolate::computeWeightedValueAndMapping(const std::map<int, std::vector<std::pair<int,double> > >& interpolatingIndexValues, int transPos)
[1612]179TRY
[630]180{
[833]181  TransformationIndexMap& transMap = this->transformationMapping_[transPos];
182  TransformationWeightMap& transWeight = this->transformationWeight_[transPos];
[630]183  std::map<int, std::vector<std::pair<int,double> > >::const_iterator itb = interpolatingIndexValues.begin(), it,
184                                                                      ite = interpolatingIndexValues.end();
[666]185  int ibegin = axisDest_->begin.getValue();
[630]186  for (it = itb; it != ite; ++it)
187  {
188    int globalIndexDest = it->first;
189    double localValue = axisDest_->value(globalIndexDest - ibegin);
190    const std::vector<std::pair<int,double> >& interpVal = it->second;
191    int interpSize = interpVal.size();
[827]192    transMap[globalIndexDest].resize(interpSize);
193    transWeight[globalIndexDest].resize(interpSize);
[630]194    for (int idx = 0; idx < interpSize; ++idx)
195    {
196      int index = interpVal[idx].first;
197      double weight = 1.0;
198
199      for (int k = 0; k < interpSize; ++k)
200      {
201        if (k == idx) continue;
202        weight *= (localValue - interpVal[k].second);
203        weight /= (interpVal[idx].second - interpVal[k].second);
204      }
[827]205      transMap[globalIndexDest][idx] = index;
206      transWeight[globalIndexDest][idx] = weight;
207      if (!transPosition_.empty())
208      {
209        (this->transformationPosition_[transPos])[globalIndexDest] = transPosition_[transPos];
210      }
[630]211    }
212  }
[918]213  if (!transPosition_.empty() && this->transformationPosition_[transPos].empty())
214    (this->transformationPosition_[transPos])[0] = transPosition_[transPos];
215
[630]216}
[1612]217CATCH
[630]218
219/*!
220  Each client retrieves all values of an axis
221  \param [in/out] recvBuff buffer for receiving values (already allocated)
222  \param [in/out] indexVec mapping between values and global index of axis
223*/
[827]224void CAxisAlgorithmInterpolate::retrieveAllAxisValue(const CArray<double,1>& axisValue, const CArray<bool,1>& axisMask,
225                                                     std::vector<double>& recvBuff, std::vector<int>& indexVec)
[1612]226TRY
[630]227{
228  CContext* context = CContext::getCurrent();
229  CContextClient* client=context->client;
230  int nbClient = client->clientSize;
231
[666]232  int srcSize  = axisSrc_->n_glo.getValue();
[630]233  int numValue = axisValue.numElements();
234
235  if (srcSize == numValue)  // Only one client or axis not distributed
236  {
237    for (int idx = 0; idx < srcSize; ++idx)
238    {
239      if (axisMask(idx))
240      {
241        recvBuff[idx] = axisValue(idx);
242        indexVec[idx] = idx;
243      }
[896]244      else
245      {
246        recvBuff[idx] = NumTraits<double>::sfmax();
247        indexVec[idx] = -1;
248      }
[630]249    }
250
251  }
252  else // Axis distributed
253  {
254    double* sendValueBuff = new double [numValue];
255    int* sendIndexBuff = new int [numValue];
256    int* recvIndexBuff = new int [srcSize];
257
[666]258    int ibegin = axisSrc_->begin.getValue();
[630]259    for (int idx = 0; idx < numValue; ++idx)
260    {
261      if (axisMask(idx))
262      {
263        sendValueBuff[idx] = axisValue(idx);
264        sendIndexBuff[idx] = idx + ibegin;
265      }
266      else
267      {
268        sendValueBuff[idx] = NumTraits<double>::sfmax();
269        sendIndexBuff[idx] = -1;
270      }
271    }
272
273    int* recvCount=new int[nbClient];
274    MPI_Allgather(&numValue,1,MPI_INT,recvCount,1,MPI_INT,client->intraComm);
275
276    int* displ=new int[nbClient];
277    displ[0]=0 ;
278    for(int n=1;n<nbClient;n++) displ[n]=displ[n-1]+recvCount[n-1];
279
280    // Each client have enough global info of axis
281    MPI_Allgatherv(sendIndexBuff,numValue,MPI_INT,recvIndexBuff,recvCount,displ,MPI_INT,client->intraComm);
282    MPI_Allgatherv(sendValueBuff,numValue,MPI_DOUBLE,&(recvBuff[0]),recvCount,displ,MPI_DOUBLE,client->intraComm);
283
284    for (int idx = 0; idx < srcSize; ++idx)
285    {
286      indexVec[idx] = recvIndexBuff[idx];
287    }
288
289    delete [] displ;
290    delete [] recvCount;
291    delete [] recvIndexBuff;
292    delete [] sendIndexBuff;
293    delete [] sendValueBuff;
294  }
295}
[1612]296CATCH
[630]297
[827]298/*!
299  Fill in axis value dynamically from a field whose grid is composed of a domain and an axis
300  \param [in/out] vecAxisValue vector axis value filled in from input field
301*/
302void CAxisAlgorithmInterpolate::fillInAxisValue(std::vector<CArray<double,1> >& vecAxisValue,
303                                                const std::vector<CArray<double,1>* >& dataAuxInputs)
[1612]304TRY
[827]305{
306  if (coordinate_.empty())
307  {
308    vecAxisValue.resize(1);
309    vecAxisValue[0].resize(axisSrc_->value.numElements());
310    vecAxisValue[0] = axisSrc_->value;
311    this->transformationMapping_.resize(1);
312    this->transformationWeight_.resize(1);
313  }
314  else
315  {
316    CField* field = CField::get(coordinate_);
317    CGrid* grid = field->grid;
318
319    std::vector<CDomain*> domListP = grid->getDomains();
320    std::vector<CAxis*> axisListP = grid->getAxis();
321    if (domListP.empty() || axisListP.empty() || (1 < domListP.size()) || (1 < axisListP.size()))
322      ERROR("CAxisAlgorithmInterpolate::fillInAxisValue(std::vector<CArray<double,1> >& vecAxisValue)",
323             << "XIOS only supports dynamic interpolation with coordinate (field) associated with grid composed of a domain and an axis"
324             << "Coordinate (field) id = " <<field->getId() << std::endl
325             << "Associated grid id = " << grid->getId());
326
327    CDomain* dom = domListP[0];
328    size_t vecAxisValueSize = dom->i_index.numElements();
[913]329    size_t vecAxisValueSizeWithMask = 0;
330    for (size_t idx = 0; idx < vecAxisValueSize; ++idx)
331    {
[1311]332      if (dom->domainMask(idx)) ++vecAxisValueSizeWithMask;
[913]333    }
334
[862]335    int niGlobDom = dom->ni_glo.getValue();
[913]336    vecAxisValue.resize(vecAxisValueSizeWithMask);
[827]337    if (transPosition_.empty())
338    {
[913]339      size_t indexMask = 0;
340      transPosition_.resize(vecAxisValueSizeWithMask);
[827]341      for (size_t idx = 0; idx < vecAxisValueSize; ++idx)
342      {
[1311]343        if (dom->domainMask(idx))
[913]344        {
345          transPosition_[indexMask].resize(1);
346          transPosition_[indexMask][0] = (dom->i_index)(idx) + niGlobDom * (dom->j_index)(idx);
347          ++indexMask;
348        }
349
[827]350      }
351    }
[913]352    this->transformationMapping_.resize(vecAxisValueSizeWithMask);
353    this->transformationWeight_.resize(vecAxisValueSizeWithMask);
354    this->transformationPosition_.resize(vecAxisValueSizeWithMask);
[827]355
[831]356    const CDistributionClient::GlobalLocalDataMap& globalLocalIndexSendToServer = grid->getDistributionClient()->getGlobalLocalDataSendToServer();
357    CDistributionClient::GlobalLocalDataMap::const_iterator itIndex, iteIndex = globalLocalIndexSendToServer.end();
[827]358    size_t axisSrcSize = axisSrc_->index.numElements();
359    std::vector<int> globalDimension = grid->getGlobalDimension();
[831]360
[913]361    size_t indexMask = 0;
[827]362    for (size_t idx = 0; idx < vecAxisValueSize; ++idx)
363    {
[1311]364      if (dom->domainMask(idx))
[827]365      {
[913]366        size_t axisValueSize = 0;
367        for (size_t jdx = 0; jdx < axisSrcSize; ++jdx)
[827]368        {
[913]369          size_t globalIndex = ((dom->i_index)(idx) + (dom->j_index)(idx)*globalDimension[0]) + (axisSrc_->index)(jdx)*globalDimension[0]*globalDimension[1];
370          if (iteIndex != globalLocalIndexSendToServer.find(globalIndex))
371          {
372            ++axisValueSize;
373          }
[827]374        }
375
[913]376        vecAxisValue[indexMask].resize(axisValueSize);
377        axisValueSize = 0;
378        for (size_t jdx = 0; jdx < axisSrcSize; ++jdx)
[827]379        {
[913]380          size_t globalIndex = ((dom->i_index)(idx) + (dom->j_index)(idx)*globalDimension[0]) + (axisSrc_->index)(jdx)*globalDimension[0]*globalDimension[1];
381          itIndex = globalLocalIndexSendToServer.find(globalIndex);
382          if (iteIndex != itIndex)
383          {
384            vecAxisValue[indexMask](axisValueSize) = (*dataAuxInputs[0])(itIndex->second);
385            ++axisValueSize;
386          }
[827]387        }
[913]388        ++indexMask;
[827]389      }
390    }
391  }
[630]392}
[1612]393CATCH
[827]394
395}
Note: See TracBrowser for help on using the repository browser.