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