Salome HOME
Update copyrights 2014.
[tools/medcoupling.git] / src / ParaMEDMEM / InterpolationMatrix.cxx
1 // Copyright (C) 2007-2014  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
20 #include "ParaMESH.hxx"
21 #include "ParaFIELD.hxx"
22 #include "ProcessorGroup.hxx"
23 #include "MxN_Mapping.hxx"
24 #include "InterpolationMatrix.hxx"
25 #include "TranslationRotationMatrix.hxx"
26 #include "Interpolation.hxx"
27 #include "Interpolation1D.txx"
28 #include "Interpolation2DCurve.hxx"
29 #include "Interpolation2D.txx"
30 #include "Interpolation3DSurf.hxx"
31 #include "Interpolation3D.txx"
32 #include "Interpolation3D2D.txx"
33 #include "Interpolation2D1D.txx"
34 #include "MEDCouplingUMesh.hxx"
35 #include "MEDCouplingNormalizedUnstructuredMesh.txx"
36 #include "InterpolationOptions.hxx"
37 #include "NormalizedUnstructuredMesh.hxx"
38 #include "ElementLocator.hxx"
39
40 #include <algorithm>
41
42 // class InterpolationMatrix
43 // This class enables the storage of an interpolation matrix Wij mapping 
44 // source field Sj to target field Ti via Ti=Vi^(-1).Wij.Sj.
45 // The matrix is built and stored on the processors belonging to the source
46 // group. 
47
48 using namespace std;
49
50 namespace ParaMEDMEM
51 {
52
53   //   ====================================================================
54   //   Creates an empty matrix structure linking two distributed supports.
55   //   The method must be called by all processors belonging to source
56   //   and target groups.
57   //   param source_support local support
58   //   param source_group processor group containing the local processors
59   //   param target_group processor group containing the distant processors
60   //   param method interpolation method
61   //   ====================================================================
62
63   InterpolationMatrix::InterpolationMatrix(const ParaMEDMEM::ParaFIELD *source_field, 
64                                            const ProcessorGroup& source_group,
65                                            const ProcessorGroup& target_group,
66                                            const DECOptions& dec_options,
67                                            const INTERP_KERNEL::InterpolationOptions& interp_options):
68     INTERP_KERNEL::InterpolationOptions(interp_options),
69     DECOptions(dec_options),
70     _source_field(source_field),
71     _source_support(source_field->getSupport()->getCellMesh()),
72     _mapping(source_group, target_group, dec_options),
73     _source_group(source_group),
74     _target_group(target_group)
75   {
76     int nbelems = source_field->getField()->getNumberOfTuples();
77     _row_offsets.resize(nbelems+1);
78     _coeffs.resize(nbelems);
79     _target_volume.resize(nbelems);
80   }
81
82   InterpolationMatrix::~InterpolationMatrix()
83   {
84   }
85
86
87   //   ======================================================================
88   //   \brief Adds the contribution of a distant subdomain to the*
89   //   interpolation matrix.
90   //   The method adds contribution to the interpolation matrix.
91   //   For each row of the matrix, elements are addded as
92   //   a (column, coeff) pair in the _coeffs array. This column number refers
93   //   to an element on the target side via the _col_offsets array.
94   //   It is made of a series of (iproc, ielem) pairs. 
95   //   The number of elements per row is stored in the row_offsets array.
96
97   //   param distant_support local representation of the distant subdomain
98   //   param iproc_distant id of the distant subdomain (in the distant group)
99   //   param distant_elems mapping between the local representation of
100   //   the subdomain and the actual elem ids on the distant subdomain
101   //   ======================================================================
102
103   void InterpolationMatrix::addContribution ( MEDCouplingPointSet& distant_support,
104                                               int iproc_distant,
105                                               const int* distant_elems,
106                                               const std::string& srcMeth,
107                                               const std::string& targetMeth)
108   {
109     std::string interpMethod(targetMeth);
110     interpMethod+=srcMeth;
111     //creating the interpolator structure
112     vector<map<int,double> > surfaces;
113     //computation of the intersection volumes between source and target elements
114     MEDCouplingUMesh *distant_supportC=dynamic_cast<MEDCouplingUMesh *>(&distant_support);
115     MEDCouplingUMesh *source_supportC=dynamic_cast<MEDCouplingUMesh *>(_source_support);
116     if ( distant_support.getMeshDimension() == -1 )
117       {
118         if(source_supportC->getMeshDimension()==2 && source_supportC->getSpaceDimension()==2)
119           {
120             MEDCouplingNormalizedUnstructuredMesh<2,2> source_mesh_wrapper(source_supportC);
121             INTERP_KERNEL::Interpolation2D interpolation(*this);
122             interpolation.fromIntegralUniform(source_mesh_wrapper,surfaces,srcMeth);
123           }
124         else if(source_supportC->getMeshDimension()==3 && source_supportC->getSpaceDimension()==3)
125           {
126             MEDCouplingNormalizedUnstructuredMesh<3,3> source_mesh_wrapper(source_supportC);
127             INTERP_KERNEL::Interpolation3D interpolation(*this);
128             interpolation.fromIntegralUniform(source_mesh_wrapper,surfaces,srcMeth);
129           }
130         else if(source_supportC->getMeshDimension()==2 && source_supportC->getSpaceDimension()==3)
131           {
132             MEDCouplingNormalizedUnstructuredMesh<3,2> source_mesh_wrapper(source_supportC);
133             INTERP_KERNEL::Interpolation3DSurf interpolation(*this);
134             interpolation.fromIntegralUniform(source_mesh_wrapper,surfaces,srcMeth);
135           }
136         else
137           throw INTERP_KERNEL::Exception("No para interpolation available for the given mesh and space dimension of source mesh to -1D targetMesh");
138       }
139     else if ( source_supportC->getMeshDimension() == -1 )
140       {
141         if(distant_supportC->getMeshDimension()==2 && distant_supportC->getSpaceDimension()==2)
142           {
143             MEDCouplingNormalizedUnstructuredMesh<2,2> distant_mesh_wrapper(distant_supportC);
144             INTERP_KERNEL::Interpolation2D interpolation(*this);
145             interpolation.toIntegralUniform(distant_mesh_wrapper,surfaces,srcMeth);
146           }
147         else if(distant_supportC->getMeshDimension()==3 && distant_supportC->getSpaceDimension()==3)
148           {
149             MEDCouplingNormalizedUnstructuredMesh<3,3> distant_mesh_wrapper(distant_supportC);
150             INTERP_KERNEL::Interpolation3D interpolation(*this);
151             interpolation.toIntegralUniform(distant_mesh_wrapper,surfaces,srcMeth);
152           }
153         else if(distant_supportC->getMeshDimension()==2 && distant_supportC->getSpaceDimension()==3)
154           {
155             MEDCouplingNormalizedUnstructuredMesh<3,2> distant_mesh_wrapper(distant_supportC);
156             INTERP_KERNEL::Interpolation3DSurf interpolation(*this);
157             interpolation.toIntegralUniform(distant_mesh_wrapper,surfaces,srcMeth);
158           }
159         else
160           throw INTERP_KERNEL::Exception("No para interpolation available for the given mesh and space dimension of distant mesh to -1D sourceMesh");
161       }
162     else if ( distant_support.getMeshDimension() == 2
163               && _source_support->getMeshDimension() == 3
164               && distant_support.getSpaceDimension() == 3 && _source_support->getSpaceDimension() == 3)
165       {
166         MEDCouplingNormalizedUnstructuredMesh<3,3> target_wrapper(distant_supportC);
167         MEDCouplingNormalizedUnstructuredMesh<3,3> source_wrapper(source_supportC);
168         INTERP_KERNEL::Interpolation3D2D interpolator (*this);
169         interpolator.interpolateMeshes(target_wrapper,source_wrapper,surfaces,interpMethod);
170         target_wrapper.releaseTempArrays();
171         source_wrapper.releaseTempArrays();
172       }
173     else if ( distant_support.getMeshDimension() == 1
174               && _source_support->getMeshDimension() == 2
175               && distant_support.getSpaceDimension() == 2 && _source_support->getSpaceDimension() == 2)
176       {
177         MEDCouplingNormalizedUnstructuredMesh<2,2> target_wrapper(distant_supportC);
178         MEDCouplingNormalizedUnstructuredMesh<2,2> source_wrapper(source_supportC);
179         INTERP_KERNEL::Interpolation2D1D interpolator (*this);
180         interpolator.interpolateMeshes(target_wrapper,source_wrapper,surfaces,interpMethod);
181         target_wrapper.releaseTempArrays();
182         source_wrapper.releaseTempArrays();
183       }
184     else if (distant_support.getMeshDimension() != _source_support->getMeshDimension())
185       {
186         throw INTERP_KERNEL::Exception("local and distant meshes do not have the same space and mesh dimensions");
187       }
188     else if( distant_support.getMeshDimension() == 1
189              && distant_support.getSpaceDimension() == 1 )
190       {
191         MEDCouplingNormalizedUnstructuredMesh<1,1> target_wrapper(distant_supportC);
192         MEDCouplingNormalizedUnstructuredMesh<1,1> source_wrapper(source_supportC);
193
194         INTERP_KERNEL::Interpolation1D interpolation(*this);
195         interpolation.interpolateMeshes(target_wrapper,source_wrapper,surfaces,interpMethod);
196         target_wrapper.releaseTempArrays();
197         source_wrapper.releaseTempArrays();
198       }
199     else if( distant_support.getMeshDimension() == 1
200              && distant_support.getSpaceDimension() == 2 )
201       {
202         MEDCouplingNormalizedUnstructuredMesh<2,1> target_wrapper(distant_supportC);
203         MEDCouplingNormalizedUnstructuredMesh<2,1> source_wrapper(source_supportC);
204
205         INTERP_KERNEL::Interpolation2DCurve interpolation(*this);
206         interpolation.interpolateMeshes(target_wrapper,source_wrapper,surfaces,interpMethod);
207         target_wrapper.releaseTempArrays();
208         source_wrapper.releaseTempArrays();
209       }
210     else if ( distant_support.getMeshDimension() == 2
211               && distant_support.getSpaceDimension() == 3 )
212       {
213         MEDCouplingNormalizedUnstructuredMesh<3,2> target_wrapper(distant_supportC);
214         MEDCouplingNormalizedUnstructuredMesh<3,2> source_wrapper(source_supportC);
215
216         INTERP_KERNEL::Interpolation3DSurf interpolator (*this);
217         interpolator.interpolateMeshes(target_wrapper,source_wrapper,surfaces,interpMethod);
218         target_wrapper.releaseTempArrays();
219         source_wrapper.releaseTempArrays();
220       }
221     else if ( distant_support.getMeshDimension() == 2
222               && distant_support.getSpaceDimension() == 2)
223       {
224         MEDCouplingNormalizedUnstructuredMesh<2,2> target_wrapper(distant_supportC);
225         MEDCouplingNormalizedUnstructuredMesh<2,2> source_wrapper(source_supportC);
226
227         INTERP_KERNEL::Interpolation2D interpolator (*this);
228         interpolator.interpolateMeshes(target_wrapper,source_wrapper,surfaces,interpMethod);
229         target_wrapper.releaseTempArrays();
230         source_wrapper.releaseTempArrays();
231       }
232     else if ( distant_support.getMeshDimension() == 3
233               && distant_support.getSpaceDimension() == 3 )
234       {
235         MEDCouplingNormalizedUnstructuredMesh<3,3> target_wrapper(distant_supportC);
236         MEDCouplingNormalizedUnstructuredMesh<3,3> source_wrapper(source_supportC);
237
238         INTERP_KERNEL::Interpolation3D interpolator (*this);
239         interpolator.interpolateMeshes(target_wrapper,source_wrapper,surfaces,interpMethod);
240         target_wrapper.releaseTempArrays();
241         source_wrapper.releaseTempArrays();
242       }
243     else
244       {
245         throw INTERP_KERNEL::Exception("no interpolator exists for these mesh and space dimensions ");
246       }
247     bool needTargetSurf=isSurfaceComputationNeeded(targetMeth);
248
249     MEDCouplingFieldDouble *target_triangle_surf=0;
250     if(needTargetSurf)
251       target_triangle_surf = distant_support.getMeasureField(getMeasureAbsStatus());
252     fillDSFromVM(iproc_distant,distant_elems,surfaces,target_triangle_surf);
253
254     if(needTargetSurf)
255       target_triangle_surf->decrRef();
256   }
257
258   void InterpolationMatrix::fillDSFromVM(int iproc_distant, const int* distant_elems, const std::vector< std::map<int,double> >& values, MEDCouplingFieldDouble *surf)
259   {
260     //loop over the elements to build the interpolation
261     //matrix structures
262     int source_size=values.size();
263     for (int ielem=0; ielem < source_size; ielem++) 
264       {
265         _row_offsets[ielem+1] += values[ielem].size();
266         for(map<int,double>::const_iterator iter=values[ielem].begin();iter!=values[ielem].end();iter++)
267           {
268             int localId;
269             if(distant_elems)
270               localId=distant_elems[iter->first];
271             else
272               localId=iter->first;
273             //locating the (iproc, itriangle) pair in the list of columns
274             map<pair<int,int>,int >::iterator iter2 = _col_offsets.find(make_pair(iproc_distant,localId));
275             int col_id;
276
277             if (iter2 == _col_offsets.end())
278               {
279                 //(iproc, itriangle) is not registered in the list
280                 //of distant elements
281                 col_id =_col_offsets.size();
282                 _col_offsets.insert(make_pair(make_pair(iproc_distant,localId),col_id));
283                 _mapping.addElementFromSource(iproc_distant,localId);
284               }
285             else 
286               {
287                 col_id = iter2->second;
288               }
289             //the non zero coefficient is stored 
290             //ielem is the row,
291             //col_id is the number of the column
292             //iter->second is the value of the coefficient
293             if(surf)
294               {
295                 double surface = surf->getIJ(iter->first,0);
296                 _target_volume[ielem].push_back(surface);
297               }
298             _coeffs[ielem].push_back(make_pair(col_id,iter->second));
299           }
300       }
301   }
302
303   void InterpolationMatrix::serializeMe(std::vector< std::vector< std::map<int,double> > >& data1, std::vector<int>& data2) const
304   {
305     data1.clear();
306     data2.clear();
307     const std::vector<std::pair<int,int> >& sendingIds=_mapping.getSendingIds();
308     std::set<int> procsS;
309     for(std::vector<std::pair<int,int> >::const_iterator iter1=sendingIds.begin();iter1!=sendingIds.end();iter1++)
310       procsS.insert((*iter1).first);
311     data1.resize(procsS.size());
312     data2.resize(procsS.size());
313     std::copy(procsS.begin(),procsS.end(),data2.begin());
314     std::map<int,int> fastProcAcc;
315     int id=0;
316     for(std::set<int>::const_iterator iter2=procsS.begin();iter2!=procsS.end();iter2++,id++)
317       fastProcAcc[*iter2]=id;
318     int nbOfSrcElt=_coeffs.size();
319     for(std::vector< std::vector< std::map<int,double> > >::iterator iter3=data1.begin();iter3!=data1.end();iter3++)
320       (*iter3).resize(nbOfSrcElt);
321     id=0;
322     for(std::vector< std::vector< std::pair<int,double> > >::const_iterator iter4=_coeffs.begin();iter4!=_coeffs.end();iter4++,id++)
323       {
324         for(std::vector< std::pair<int,double> >::const_iterator iter5=(*iter4).begin();iter5!=(*iter4).end();iter5++)
325           {
326             const std::pair<int,int>& elt=sendingIds[(*iter5).first];
327             data1[fastProcAcc[elt.first]][id][elt.second]=(*iter5).second;
328           }
329       }
330   }
331
332   void InterpolationMatrix::initialize()
333   {
334     int lgth=_coeffs.size();
335     _row_offsets.clear(); _row_offsets.resize(lgth+1);
336     _coeffs.clear(); _coeffs.resize(lgth);
337     _target_volume.clear(); _target_volume.resize(lgth);
338     _col_offsets.clear();
339     _mapping.initialize();
340   }
341
342   void InterpolationMatrix::finishContributionW(ElementLocator& elementLocator)
343   {
344     NatureOfField nature=elementLocator.getLocalNature();
345     switch(nature)
346       {
347       case ConservativeVolumic:
348         computeConservVolDenoW(elementLocator);
349         break;
350       case Integral:
351         {
352           if(!elementLocator.isM1DCorr())
353             computeIntegralDenoW(elementLocator);
354           else
355             computeGlobConstraintDenoW(elementLocator);
356           break;
357         }
358       case IntegralGlobConstraint:
359         computeGlobConstraintDenoW(elementLocator);
360         break;
361       case RevIntegral:
362         {
363           if(!elementLocator.isM1DCorr())
364             computeRevIntegralDenoW(elementLocator);
365           else
366             computeConservVolDenoW(elementLocator);
367           break;
368         }
369       default:
370         throw INTERP_KERNEL::Exception("Not recognized nature of field. Change nature of Field.");
371         break;
372       }
373   }
374
375   void InterpolationMatrix::finishContributionL(ElementLocator& elementLocator)
376   {
377     NatureOfField nature=elementLocator.getLocalNature();
378     switch(nature)
379       {
380       case ConservativeVolumic:
381         computeConservVolDenoL(elementLocator);
382         break;
383       case Integral:
384         {
385           if(!elementLocator.isM1DCorr())
386             computeIntegralDenoL(elementLocator);
387           else
388             computeConservVolDenoL(elementLocator);
389           break;
390         }
391       case IntegralGlobConstraint:
392         //this is not a bug doing like ConservativeVolumic
393         computeConservVolDenoL(elementLocator);
394         break;
395       case RevIntegral:
396         {
397           if(!elementLocator.isM1DCorr())
398             computeRevIntegralDenoL(elementLocator);
399           else
400             computeConservVolDenoL(elementLocator);
401           break;
402         }
403       default:
404         throw INTERP_KERNEL::Exception("Not recognized nature of field. Change nature of Field.");
405         break;
406       }
407   }
408   
409   void InterpolationMatrix::computeConservVolDenoW(ElementLocator& elementLocator)
410   {
411     computeGlobalColSum(_deno_reverse_multiply);
412     computeGlobalRowSum(elementLocator,_deno_multiply,_deno_reverse_multiply);
413   }
414   
415   void InterpolationMatrix::computeConservVolDenoL(ElementLocator& elementLocator)
416   {
417     int pol1=elementLocator.sendPolicyToWorkingSideL();
418     if(pol1==ElementLocator::NO_POST_TREATMENT_POLICY)
419       {
420         elementLocator.recvFromWorkingSideL();
421         elementLocator.sendToWorkingSideL();
422       }
423     else if(ElementLocator::CUMULATIVE_POLICY)
424       {
425         //ask for lazy side to deduce ids eventually missing on working side and to send it back.
426         elementLocator.recvLocalIdsFromWorkingSideL();
427         elementLocator.sendCandidatesGlobalIdsToWorkingSideL();
428         elementLocator.recvCandidatesForAddElementsL();
429         elementLocator.sendAddElementsToWorkingSideL();
430         //Working side has updated its eventually missing ids updates its global ids with lazy side procs contribution
431         elementLocator.recvLocalIdsFromWorkingSideL();
432         elementLocator.sendGlobalIdsToWorkingSideL();
433         //like no post treatment
434         elementLocator.recvFromWorkingSideL();
435         elementLocator.sendToWorkingSideL();
436       }
437     else
438       throw INTERP_KERNEL::Exception("Not managed policy detected on lazy side : not implemented !");
439   }
440
441   void InterpolationMatrix::computeIntegralDenoW(ElementLocator& elementLocator)
442   {
443     MEDCouplingFieldDouble *source_triangle_surf = _source_support->getMeasureField(getMeasureAbsStatus());
444     _deno_multiply.resize(_coeffs.size());
445     vector<vector<double> >::iterator iter6=_deno_multiply.begin();
446     const double *values=source_triangle_surf->getArray()->getConstPointer();
447     for(vector<vector<pair<int,double> > >::const_iterator iter4=_coeffs.begin();iter4!=_coeffs.end();iter4++,iter6++,values++)
448       {
449         (*iter6).resize((*iter4).size());
450         std::fill((*iter6).begin(),(*iter6).end(),*values);
451       }
452     source_triangle_surf->decrRef();
453     _deno_reverse_multiply=_target_volume;
454   }
455
456   void InterpolationMatrix::computeRevIntegralDenoW(ElementLocator& elementLocator)
457   {
458     _deno_multiply=_target_volume;
459     MEDCouplingFieldDouble *source_triangle_surf = _source_support->getMeasureField(getMeasureAbsStatus());
460     _deno_reverse_multiply.resize(_coeffs.size());
461     vector<vector<double> >::iterator iter6=_deno_reverse_multiply.begin();
462     const double *values=source_triangle_surf->getArray()->getConstPointer();
463     for(vector<vector<pair<int,double> > >::const_iterator iter4=_coeffs.begin();iter4!=_coeffs.end();iter4++,iter6++,values++)
464       {
465         (*iter6).resize((*iter4).size());
466         std::fill((*iter6).begin(),(*iter6).end(),*values);
467       }
468     source_triangle_surf->decrRef();
469   }
470   
471   /*!
472    * Nothing to do because surface computation is on working side.
473    */
474   void InterpolationMatrix::computeIntegralDenoL(ElementLocator& elementLocator)
475   {
476   }
477
478   /*!
479    * Nothing to do because surface computation is on working side.
480    */
481   void InterpolationMatrix::computeRevIntegralDenoL(ElementLocator& elementLocator)
482   {
483   }
484
485
486   void InterpolationMatrix::computeGlobConstraintDenoW(ElementLocator& elementLocator)
487   {
488     computeGlobalColSum(_deno_multiply);
489     computeGlobalRowSum(elementLocator,_deno_reverse_multiply,_deno_multiply);
490   }
491
492   void InterpolationMatrix::computeGlobalRowSum(ElementLocator& elementLocator, std::vector<std::vector<double> >& denoStrorage, std::vector<std::vector<double> >& denoStrorageInv)
493   {
494     //stores id in distant procs sorted by lazy procs connected with
495     vector< vector<int> > rowsPartialSumI;
496     //stores for each lazy procs connected with, if global info is available and if it's the case the policy
497     vector<int> policyPartial;
498     //stores the corresponding values.
499     vector< vector<double> > rowsPartialSumD;
500     elementLocator.recvPolicyFromLazySideW(policyPartial);
501     int pol1=mergePolicies(policyPartial);
502     if(pol1==ElementLocator::NO_POST_TREATMENT_POLICY)
503       {
504         computeLocalRowSum(elementLocator.getDistantProcIds(),rowsPartialSumI,rowsPartialSumD);
505         elementLocator.sendSumToLazySideW(rowsPartialSumI,rowsPartialSumD);
506         elementLocator.recvSumFromLazySideW(rowsPartialSumD);
507       }
508     else if(pol1==ElementLocator::CUMULATIVE_POLICY)
509       {
510         //updateWithNewAdditionnalElements(addingElements);
511         //stores for each lazy procs connected with, the ids in global mode if it exists (regarding policyPartial). This array has exactly the size of  rowsPartialSumI,
512         //if policyPartial has CUMALATIVE_POLICY in each.
513         vector< vector<int> > globalIdsPartial;
514         computeLocalRowSum(elementLocator.getDistantProcIds(),rowsPartialSumI,rowsPartialSumD);
515         elementLocator.sendLocalIdsToLazyProcsW(rowsPartialSumI);
516         elementLocator.recvCandidatesGlobalIdsFromLazyProcsW(globalIdsPartial);
517         std::vector< std::vector<int> > addingElements;
518         findAdditionnalElements(elementLocator,addingElements,rowsPartialSumI,globalIdsPartial);
519         addGhostElements(elementLocator.getDistantProcIds(),addingElements);
520         rowsPartialSumI.clear();
521         globalIdsPartial.clear();
522         computeLocalRowSum(elementLocator.getDistantProcIds(),rowsPartialSumI,rowsPartialSumD);
523         elementLocator.sendLocalIdsToLazyProcsW(rowsPartialSumI);
524         elementLocator.recvGlobalIdsFromLazyProcsW(rowsPartialSumI,globalIdsPartial);
525         //
526         elementLocator.sendSumToLazySideW(rowsPartialSumI,rowsPartialSumD);
527         elementLocator.recvSumFromLazySideW(rowsPartialSumD);
528         mergeRowSum3(globalIdsPartial,rowsPartialSumD);
529         mergeCoeffs(elementLocator.getDistantProcIds(),rowsPartialSumI,globalIdsPartial,denoStrorageInv);
530       }
531     else
532       throw INTERP_KERNEL::Exception("Not managed policy detected : not implemented !");
533     divideByGlobalRowSum(elementLocator.getDistantProcIds(),rowsPartialSumI,rowsPartialSumD,denoStrorage);
534   }
535
536   /*!
537    * @param distantProcs in parameter that indicates which lazy procs are concerned.
538    * @param resPerProcI out parameter that must be cleared before calling this method. The size of 1st dimension is equal to the size of 'distantProcs'.
539    *                    It contains the element ids (2nd dimension) of the corresponding lazy proc.
540    * @param  resPerProcD out parameter with the same format than 'resPerProcI'. It contains corresponding sum values.
541    */
542   void InterpolationMatrix::computeLocalRowSum(const std::vector<int>& distantProcs, std::vector<std::vector<int> >& resPerProcI,
543                                                std::vector<std::vector<double> >& resPerProcD) const
544   {
545     resPerProcI.resize(distantProcs.size());
546     resPerProcD.resize(distantProcs.size());
547     std::vector<double> res(_col_offsets.size());
548     for(vector<vector<pair<int,double> > >::const_iterator iter=_coeffs.begin();iter!=_coeffs.end();iter++)
549       for(vector<pair<int,double> >::const_iterator iter3=(*iter).begin();iter3!=(*iter).end();iter3++)
550         res[(*iter3).first]+=(*iter3).second;
551     set<int> procsSet;
552     int id=-1;
553     const vector<std::pair<int,int> >& mapping=_mapping.getSendingIds();
554     for(vector<std::pair<int,int> >::const_iterator iter2=mapping.begin();iter2!=mapping.end();iter2++)
555       {
556         std::pair<set<int>::iterator,bool> isIns=procsSet.insert((*iter2).first);
557         if(isIns.second)
558           id=std::find(distantProcs.begin(),distantProcs.end(),(*iter2).first)-distantProcs.begin();
559         resPerProcI[id].push_back((*iter2).second);
560         resPerProcD[id].push_back(res[iter2-mapping.begin()]);
561       }
562   }
563
564   /*!
565    * This method is only usable when CUMULATIVE_POLICY detected. This method finds elements ids (typically nodes) lazy side that
566    * are not present in columns of 'this' and that should regarding cumulative merge of elements regarding their global ids.
567    */
568   void InterpolationMatrix::findAdditionnalElements(ElementLocator& elementLocator, std::vector<std::vector<int> >& elementsToAdd,
569                                                     const std::vector<std::vector<int> >& resPerProcI, const std::vector<std::vector<int> >& globalIdsPartial)
570   {
571     std::set<int> globalIds;
572     int nbLazyProcs=globalIdsPartial.size();
573     for(int i=0;i<nbLazyProcs;i++)
574       globalIds.insert(globalIdsPartial[i].begin(),globalIdsPartial[i].end());
575     std::vector<int> tmp(globalIds.size());
576     std::copy(globalIds.begin(),globalIds.end(),tmp.begin());
577     globalIds.clear();
578     elementLocator.sendCandidatesForAddElementsW(tmp);
579     elementLocator.recvAddElementsFromLazyProcsW(elementsToAdd);
580   }
581
582   void InterpolationMatrix::addGhostElements(const std::vector<int>& distantProcs, const std::vector<std::vector<int> >& elementsToAdd)
583   {
584     std::vector< std::vector< std::map<int,double> > > data1;
585     std::vector<int> data2;
586     serializeMe(data1,data2);
587     initialize();
588     int nbOfDistProcs=distantProcs.size();
589     for(int i=0;i<nbOfDistProcs;i++)
590       {
591         int procId=distantProcs[i];
592         const std::vector<int>& eltsForThisProc=elementsToAdd[i];
593         if(!eltsForThisProc.empty())
594           {
595             std::vector<int>::iterator iter1=std::find(data2.begin(),data2.end(),procId);
596             std::map<int,double> *toFeed=0;
597             if(iter1!=data2.end())
598               {//to test
599                 int rank=iter1-data2.begin();
600                 toFeed=&(data1[rank].back());
601               }
602             else
603               {
604                 iter1=std::lower_bound(data2.begin(),data2.end(),procId);
605                 int rank=iter1-data2.begin();
606                 data2.insert(iter1,procId);
607                 std::vector< std::map<int,double> > tmp(data1.front().size());
608                 data1.insert(data1.begin()+rank,tmp);
609                 toFeed=&(data1[rank].back());
610               }
611             for(std::vector<int>::const_iterator iter2=eltsForThisProc.begin();iter2!=eltsForThisProc.end();iter2++)
612               (*toFeed)[*iter2]=0.;
613           }
614       }
615     //
616     nbOfDistProcs=data2.size();
617     for(int j=0;j<nbOfDistProcs;j++)
618       fillDSFromVM(data2[j],0,data1[j],0);
619   }
620
621   int InterpolationMatrix::mergePolicies(const std::vector<int>& policyPartial)
622   {
623     if(policyPartial.empty())
624       return ElementLocator::NO_POST_TREATMENT_POLICY;
625     int ref=policyPartial[0];
626      std::vector<int>::const_iterator iter1=std::find_if(policyPartial.begin(),policyPartial.end(),std::bind2nd(std::not_equal_to<int>(),ref));
627     if(iter1!=policyPartial.end())
628       {
629         std::ostringstream msg; msg << "Incompatible policies between lazy procs each other : proc # " << iter1-policyPartial.begin();
630         throw INTERP_KERNEL::Exception(msg.str().c_str());
631       }
632     return ref;
633   }
634
635   /*!
636    * This method introduce global ids aspects in computed 'rowsPartialSumD'.
637    * As precondition rowsPartialSumD.size()==policyPartial.size()==globalIdsPartial.size(). Foreach i in [0;rowsPartialSumD.size() ) rowsPartialSumD[i].size()==globalIdsPartial[i].size()
638    * @param rowsPartialSumD : in parameter, Partial row sum computed for each lazy procs connected with.
639    * @param rowsPartialSumI : in parameter, Corresponding local ids for each lazy procs connected with.
640    * @param globalIdsPartial : in parameter, the global numbering, of elements connected with.
641    * @param globalIdsLazySideInteraction : out parameter, constituted from all global ids of lazy procs connected with.
642    * @para sumCorresponding : out parameter, relative to 'globalIdsLazySideInteraction'
643    */
644   void InterpolationMatrix::mergeRowSum(const std::vector< std::vector<double> >& rowsPartialSumD, const std::vector< std::vector<int> >& globalIdsPartial,
645                                         std::vector<int>& globalIdsLazySideInteraction, std::vector<double>& sumCorresponding)
646   {
647     std::map<int,double> sumToReturn;
648     int nbLazyProcs=rowsPartialSumD.size();
649     for(int i=0;i<nbLazyProcs;i++)
650       {
651         const std::vector<double>& rowSumOfP=rowsPartialSumD[i];
652         const std::vector<int>& globalIdsOfP=globalIdsPartial[i];
653         std::vector<double>::const_iterator iter1=rowSumOfP.begin();
654         std::vector<int>::const_iterator iter2=globalIdsOfP.begin();
655         for(;iter1!=rowSumOfP.end();iter1++,iter2++)
656           sumToReturn[*iter2]+=*iter1;
657       }
658     //
659     int lgth=sumToReturn.size();
660     globalIdsLazySideInteraction.resize(lgth);
661     sumCorresponding.resize(lgth);
662     std::vector<int>::iterator iter3=globalIdsLazySideInteraction.begin();
663     std::vector<double>::iterator iter4=sumCorresponding.begin();
664     for(std::map<int,double>::const_iterator iter5=sumToReturn.begin();iter5!=sumToReturn.end();iter5++,iter3++,iter4++)
665       {
666         *iter3=(*iter5).first;
667         *iter4=(*iter5).second;
668       }
669   }
670
671   /*!
672    * This method simply reorganize the result contained in 'sumCorresponding' computed by lazy side into 'rowsPartialSumD' with help of 'globalIdsPartial' and 'globalIdsLazySideInteraction'
673    *
674    * @param globalIdsPartial : in parameter, global ids sorted by lazy procs
675    * @param rowsPartialSumD : in/out parameter, with exactly the same size as 'globalIdsPartial'
676    * @param globalIdsLazySideInteraction : in parameter that represents ALL the global ids of every lazy procs in interaction
677    * @param sumCorresponding : in parameter with same size as 'globalIdsLazySideInteraction' that stores the corresponding sum of 'globalIdsLazySideInteraction'
678    */
679   void InterpolationMatrix::mergeRowSum2(const std::vector< std::vector<int> >& globalIdsPartial, std::vector< std::vector<double> >& rowsPartialSumD,
680                                          const std::vector<int>& globalIdsLazySideInteraction, const std::vector<double>& sumCorresponding)
681   {
682     std::map<int,double> acc;
683     std::vector<int>::const_iterator iter1=globalIdsLazySideInteraction.begin();
684     std::vector<double>::const_iterator iter2=sumCorresponding.begin();
685     for(;iter1!=globalIdsLazySideInteraction.end();iter1++,iter2++)
686       acc[*iter1]=*iter2;
687     //
688     int nbLazyProcs=globalIdsPartial.size();
689     for(int i=0;i<nbLazyProcs;i++)
690       {
691         const std::vector<int>& tmp1=globalIdsPartial[i];
692         std::vector<double>& tmp2=rowsPartialSumD[i];
693         std::vector<int>::const_iterator iter3=tmp1.begin();
694         std::vector<double>::iterator iter4=tmp2.begin();
695         for(;iter3!=tmp1.end();iter3++,iter4++)
696           *iter4=acc[*iter3];
697       }
698   }
699   
700   void InterpolationMatrix::mergeRowSum3(const std::vector< std::vector<int> >& globalIdsPartial, std::vector< std::vector<double> >& rowsPartialSumD)
701   {
702     std::map<int,double> sum;
703     std::vector< std::vector<int> >::const_iterator iter1=globalIdsPartial.begin();
704     std::vector< std::vector<double> >::iterator iter2=rowsPartialSumD.begin();
705     for(;iter1!=globalIdsPartial.end();iter1++,iter2++)
706       {
707         std::vector<int>::const_iterator iter3=(*iter1).begin();
708         std::vector<double>::const_iterator iter4=(*iter2).begin();
709         for(;iter3!=(*iter1).end();iter3++,iter4++)
710           sum[*iter3]+=*iter4;
711       }
712     iter2=rowsPartialSumD.begin();
713     for(iter1=globalIdsPartial.begin();iter1!=globalIdsPartial.end();iter1++,iter2++)
714       {
715         std::vector<int>::const_iterator iter3=(*iter1).begin();
716         std::vector<double>::iterator iter4=(*iter2).begin();
717         for(;iter3!=(*iter1).end();iter3++,iter4++)
718           *iter4=sum[*iter3];
719       }
720   }
721
722   /*!
723    * This method updates this->_coeffs attribute in order to take into account hidden (because having the same global number) similar nodes in _coeffs array.
724    * If in this->_coeffs two distant element id have the same global id their values will be replaced for each by the sum of the two.
725    * @param procsInInteraction input parameter : specifies the procId in absolute of distant lazy procs in interaction with
726    * @param rowsPartialSumI input parameter : local ids of distant lazy procs elements in interaction with
727    * @param globalIdsPartial input parameter : global ids of distant lazy procs elements in interaction with
728    */
729   void InterpolationMatrix::mergeCoeffs(const std::vector<int>& procsInInteraction, const std::vector< std::vector<int> >& rowsPartialSumI,
730                                         const std::vector<std::vector<int> >& globalIdsPartial, std::vector<std::vector<double> >& denoStrorageInv)
731   {
732     //preparing fast access structures
733     std::map<int,int> procT;
734     int localProcId=0;
735     for(std::vector<int>::const_iterator iter1=procsInInteraction.begin();iter1!=procsInInteraction.end();iter1++,localProcId++)
736       procT[*iter1]=localProcId;
737     int size=procsInInteraction.size();
738     std::vector<std::map<int,int> > localToGlobal(size);
739     for(int i=0;i<size;i++)
740       {
741         std::map<int,int>& myLocalToGlobal=localToGlobal[i];
742         const std::vector<int>& locals=rowsPartialSumI[i];
743         const std::vector<int>& globals=globalIdsPartial[i];
744         std::vector<int>::const_iterator iter3=locals.begin();
745         std::vector<int>::const_iterator iter4=globals.begin();
746         for(;iter3!=locals.end();iter3++,iter4++)
747           myLocalToGlobal[*iter3]=*iter4;
748       }
749     //
750     const vector<std::pair<int,int> >& mapping=_mapping.getSendingIds();
751     std::map<int,double> globalIdVal;
752     //accumulate for same global id on lazy part.
753     for(vector<vector<pair<int,double> > >::iterator iter1=_coeffs.begin();iter1!=_coeffs.end();iter1++)
754       for(vector<pair<int,double> >::iterator iter2=(*iter1).begin();iter2!=(*iter1).end();iter2++)
755         {
756           const std::pair<int,int>& distantLocalLazyId=mapping[(*iter2).first];
757           int localLazyProcId=procT[distantLocalLazyId.first];
758           int globalDistantLazyId=localToGlobal[localLazyProcId][distantLocalLazyId.second];
759           globalIdVal[globalDistantLazyId]+=(*iter2).second;
760         }
761     //perform merge
762     std::vector<std::vector<double> >::iterator iter3=denoStrorageInv.begin();
763     for(vector<vector<pair<int,double> > >::iterator iter1=_coeffs.begin();iter1!=_coeffs.end();iter1++,iter3++)
764       {
765         double val=(*iter3).back();
766         (*iter3).resize((*iter1).size());
767         std::vector<double>::iterator iter4=(*iter3).begin();
768         for(vector<pair<int,double> >::iterator iter2=(*iter1).begin();iter2!=(*iter1).end();iter2++,iter4++)
769           {
770             const std::pair<int,int>& distantLocalLazyId=mapping[(*iter2).first];
771             int localLazyProcId=procT[distantLocalLazyId.first];
772             int globalDistantLazyId=localToGlobal[localLazyProcId][distantLocalLazyId.second];
773             double newVal=globalIdVal[globalDistantLazyId];
774             if((*iter2).second!=0.)
775               (*iter4)=val*newVal/(*iter2).second;
776             else
777               (*iter4)=std::numeric_limits<double>::max();
778             (*iter2).second=newVal;
779           }
780       }
781   }
782
783   void InterpolationMatrix::divideByGlobalRowSum(const std::vector<int>& distantProcs, const std::vector<std::vector<int> >& resPerProcI,
784                                                  const std::vector<std::vector<double> >& resPerProcD, std::vector<std::vector<double> >& deno)
785   {
786     map<int,double> fastSums;
787     int procId=0;
788     for(vector<int>::const_iterator iter1=distantProcs.begin();iter1!=distantProcs.end();iter1++,procId++)
789       {
790         const std::vector<int>& currentProcI=resPerProcI[procId];
791         const std::vector<double>& currentProcD=resPerProcD[procId];
792         vector<double>::const_iterator iter3=currentProcD.begin();
793         for(vector<int>::const_iterator iter2=currentProcI.begin();iter2!=currentProcI.end();iter2++,iter3++)
794           fastSums[_col_offsets[std::make_pair(*iter1,*iter2)]]=*iter3;
795       }
796     deno.resize(_coeffs.size());
797     vector<vector<double> >::iterator iter6=deno.begin();
798     for(vector<vector<pair<int,double> > >::const_iterator iter4=_coeffs.begin();iter4!=_coeffs.end();iter4++,iter6++)
799       {
800         (*iter6).resize((*iter4).size());
801         vector<double>::iterator iter7=(*iter6).begin();
802         for(vector<pair<int,double> >::const_iterator iter5=(*iter4).begin();iter5!=(*iter4).end();iter5++,iter7++)
803           *iter7=fastSums[(*iter5).first];
804       }
805   }
806
807   void InterpolationMatrix::computeGlobalColSum(std::vector<std::vector<double> >& denoStrorage)
808   {
809     denoStrorage.resize(_coeffs.size());
810     vector<vector<double> >::iterator iter2=denoStrorage.begin();
811     for(vector<vector<pair<int,double> > >::const_iterator iter1=_coeffs.begin();iter1!=_coeffs.end();iter1++,iter2++)
812       {
813         (*iter2).resize((*iter1).size());
814         double sumOfCurrentRow=0.;
815         for(vector<pair<int,double> >::const_iterator iter3=(*iter1).begin();iter3!=(*iter1).end();iter3++)
816           sumOfCurrentRow+=(*iter3).second;
817         std::fill((*iter2).begin(),(*iter2).end(),sumOfCurrentRow);
818       }
819   }
820
821   void InterpolationMatrix::resizeGlobalColSum(std::vector<std::vector<double> >& denoStrorage)
822   {
823     vector<vector<double> >::iterator iter2=denoStrorage.begin();
824     for(vector<vector<pair<int,double> > >::const_iterator iter1=_coeffs.begin();iter1!=_coeffs.end();iter1++,iter2++)
825       {
826         double val=(*iter2).back();
827         (*iter2).resize((*iter1).size());
828         std::fill((*iter2).begin(),(*iter2).end(),val);
829       }
830   }
831
832   // ==================================================================
833   // The call to this method updates the arrays on the target side
834   //   so that they know which amount of data from which processor they 
835   //   should expect. 
836   //   That call makes actual interpolations via multiply method 
837   //   available.
838   // ==================================================================
839
840   void InterpolationMatrix::prepare()
841   {
842     int nbelems = _source_field->getField()->getNumberOfTuples();
843     for (int ielem=0; ielem < nbelems; ielem++)
844       {
845         _row_offsets[ielem+1]+=_row_offsets[ielem];
846       }
847     _mapping.prepareSendRecv();
848   }
849
850
851   //   =======================================================================
852   //   brief performs t=Ws, where t is the target field, s is the source field
853
854   //   The call to this method must be called both on the working side 
855   //   and on the idle side. On the working side, the vector  T=VT^(-1).(W.S)
856   //   is computed and sent. On the idle side, no computation is done, but the 
857   //   result from the working side is received and the field is updated.
858
859   //   param field source field on processors involved on the source side,
860   //   target field on processors on the target side
861   //   =======================================================================
862
863   void InterpolationMatrix::multiply(MEDCouplingFieldDouble& field) const
864   {
865     int nbcomp = field.getArray()->getNumberOfComponents();
866     vector<double> target_value(_col_offsets.size()* nbcomp,0.0);
867
868     //computing the matrix multiply on source side
869     if (_source_group.containsMyRank())
870       {
871         int nbrows = _coeffs.size();
872
873         // performing W.S
874         // W is the intersection matrix
875         // S is the source vector
876
877         for (int irow=0; irow<nbrows; irow++)
878           {
879             for (int icomp=0; icomp< nbcomp; icomp++)
880               {
881                 double coeff_row = field.getIJ(irow,icomp);
882                 for (int icol=_row_offsets[irow]; icol< _row_offsets[irow+1];icol++)
883                   {
884                     int colid= _coeffs[irow][icol-_row_offsets[irow]].first;
885                     double value = _coeffs[irow][icol-_row_offsets[irow]].second;
886                     double deno = _deno_multiply[irow][icol-_row_offsets[irow]];
887                     target_value[colid*nbcomp+icomp]+=value*coeff_row/deno;
888                   }
889               }
890           }
891       }
892
893     if (_target_group.containsMyRank())
894       {
895         int nbelems = field.getArray()->getNumberOfTuples() ;
896         double* value = const_cast<double*> (field.getArray()->getPointer());
897         for (int i=0; i<nbelems*nbcomp; i++)
898           {
899             value[i]=0.0;
900           }
901       }
902
903     //on source side : sending  T=VT^(-1).(W.S)
904     //on target side :: receiving T and storing it in field
905     _mapping.sendRecv(&target_value[0],field);
906   }
907   
908
909   // =========================================================================
910   // brief performs s=WTt, where t is the target field, s is the source field,
911   // WT is the transpose matrix from W
912
913   //   The call to this method must be called both on the working side 
914   //   and on the idle side. On the working side, the target vector T is
915   //   received and the vector  S=VS^(-1).(WT.T) is computed to update
916   //   the field. 
917   //   On the idle side, no computation is done, but the field is sent.
918
919   //   param field source field on processors involved on the source side,
920   //   target field on processors on the target side
921   // =========================================================================
922
923   void InterpolationMatrix::transposeMultiply(MEDCouplingFieldDouble& field) const
924   {
925     int nbcomp = field.getArray()->getNumberOfComponents();
926     vector<double> source_value(_col_offsets.size()* nbcomp,0.0);
927     _mapping.reverseSendRecv(&source_value[0],field);
928
929     //treatment of the transpose matrix multiply on the source side
930     if (_source_group.containsMyRank())
931       {
932         int nbrows    = _coeffs.size();
933         double *array = field.getArray()->getPointer() ;
934
935         // Initialization
936         std::fill(array, array+nbrows*nbcomp, 0.0) ;
937
938         //performing WT.T
939         //WT is W transpose
940         //T is the target vector
941         for (int irow = 0; irow < nbrows; irow++)
942           {
943             for (int icol = _row_offsets[irow]; icol < _row_offsets[irow+1]; icol++)
944               {
945                 int colid    = _coeffs[irow][icol-_row_offsets[irow]].first;
946                 double value = _coeffs[irow][icol-_row_offsets[irow]].second;
947                 double deno = _deno_reverse_multiply[irow][icol-_row_offsets[irow]];
948                 for (int icomp=0; icomp<nbcomp; icomp++)
949                   {
950                     double coeff_row = source_value[colid*nbcomp+icomp];
951                     array[irow*nbcomp+icomp] += value*coeff_row/deno;
952                   }
953               }
954           }
955       }
956   }
957
958   bool InterpolationMatrix::isSurfaceComputationNeeded(const std::string& method) const
959   {
960     return method=="P0";
961   }
962 }