source: XIOS/dev/dev_ym/XIOS_COUPLING/src/transformation/axis_algorithm_interpolate.cpp @ 1878

Last change on this file since 1878 was 1870, checked in by ymipsl, 4 years ago

Some update on XIOS_COUPLING branch...

YM

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