Salome HOME
f813ad5d314336dabb5029fae5a7a2a61c21b4f1
[tools/solverlab.git] / CoreFlows / Models / src / StationaryDiffusionEquation.cxx
1 #include "StationaryDiffusionEquation.hxx"
2 #include "DiffusionEquation.hxx"
3 #include "Node.hxx"
4 #include "SparseMatrixPetsc.hxx"
5 #include "math.h"
6 #include <algorithm> 
7 #include <fstream>
8 #include <sstream>
9
10 using namespace std;
11
12 StationaryDiffusionEquation::StationaryDiffusionEquation(int dim, bool FECalculation, double lambda,MPI_Comm comm){
13         /* Initialisation of PETSC */
14         //check if PETSC is already initialised
15         PetscBool petscInitialized;
16         PetscInitialized(&petscInitialized);
17         if(!petscInitialized)
18         {//check if MPI is already initialised
19                 int mpiInitialized;
20                 MPI_Initialized(&mpiInitialized);
21                 if(mpiInitialized)
22                         PETSC_COMM_WORLD = comm;
23                 PetscInitialize(NULL,NULL,0,0);//Note this is ok if MPI has been been initialised independently from PETSC
24         }
25         MPI_Comm_rank(PETSC_COMM_WORLD,&_mpi_rank);
26         MPI_Comm_size(PETSC_COMM_WORLD,&_mpi_size);
27         PetscPrintf(PETSC_COMM_WORLD,"Simulation on %d processors\n",_mpi_size);//Prints to standard out, only from the first processor in the communicator. Calls from other processes are ignored. 
28         PetscSynchronizedPrintf(PETSC_COMM_WORLD,"Processor [%d] ready for action\n",_mpi_rank);//Prints synchronized output from several processors. Output of the first processor is followed by that of the second, etc. 
29         PetscSynchronizedFlush(PETSC_COMM_WORLD,PETSC_STDOUT);
30
31     if(lambda < 0.)
32     {
33         std::cout<<"Conductivity="<<lambda<<endl;
34         throw CdmathException("Error : conductivity parameter lambda cannot  be negative");
35     }
36     if(dim<=0)
37     {
38         std::cout<<"Space dimension="<<dim<<endl;
39         throw CdmathException("Error : parameter dim cannot  be negative");
40     }
41
42     _FECalculation=FECalculation;
43     _onlyNeumannBC=false;    
44     
45         _Ndim=dim;
46         _nVar=1;//scalar prolem
47         _dt_src=0;
48         _diffusionMatrixSet=false;
49         _initializedMemory=false;
50
51     //Mesh data
52     _neibMaxNbCells=0;    
53     _meshSet=false;
54     _neibMaxNbNodes=0;    
55
56     //Boundary conditions
57     _boundaryNodeIds=std::vector< int >(0);
58     _dirichletNodeIds=std::vector< int >(0);
59     _NboundaryNodes=0;
60     _NdirichletNodes=0;
61     _NunknownNodes=0;
62     _dirichletValuesSet=false;   
63     _neumannValuesSet=false;   
64     
65     //Linear solver data
66         _precision=1.e-6;
67         _precision_Newton=_precision;
68         _MaxIterLinearSolver=0;//During several newton iterations, stores the max petssc interations
69         _maxPetscIts=50;
70         _maxNewtonIts=50;
71         _NEWTON_its=0;
72         int _PetscIts=0;//the number of iterations of the linear solver
73         _ksptype = (char*)&KSPGMRES;
74         if( _mpi_size>1)
75                 _pctype = (char*)&PCNONE;
76         else
77                 _pctype = (char*)&PCLU;
78
79         _conditionNumber=false;
80         _erreur_rel= 0;
81
82     //parameters for monitoring simulation
83         _verbose = false;
84         _system = false;
85         _runLogFile=new ofstream;
86
87         //result save parameters
88         _fileName = "StationaryDiffusionProblem";
89         char result[ PATH_MAX ];//extracting current directory
90         getcwd(result, PATH_MAX );
91         _path=string( result );
92         _saveFormat=VTK;
93     _computationCompletedSuccessfully=false;
94     
95     //heat transfer parameters
96         _conductivity=lambda;
97         _fluidTemperatureFieldSet=false;
98         _fluidTemperature=0;
99         _heatPowerFieldSet=false;
100         _heatTransfertCoeff=0;
101         _heatSource=0;
102
103     /* Default diffusion tensor is diagonal */
104         _DiffusionTensor=Matrix(_Ndim);
105         for(int idim=0;idim<_Ndim;idim++)
106                 _DiffusionTensor(idim,idim)=_conductivity;
107 }
108
109 void StationaryDiffusionEquation::initialize()
110 {
111         if(_mpi_rank==0)
112         {
113                 _runLogFile->open((_fileName+".log").c_str(), ios::out | ios::trunc);;//for creation of a log file to save the history of the simulation
114         
115                 if(!_meshSet)
116                         throw CdmathException("StationaryDiffusionEquation::initialize() set mesh first");
117                 else
118             {
119                         cout<<"!!!! Initialisation of the computation of the temperature diffusion in a solid using ";
120                 *_runLogFile<<"!!!!! Initialisation of the computation of the temperature diffusion in a solid using ";
121                 if(!_FECalculation)
122                 {
123                     cout<< "Finite volumes method"<<endl<<endl;
124                     *_runLogFile<< "Finite volumes method"<<endl<<endl;
125                 }
126                 else
127                 {
128                     cout<< "Finite elements method"<<endl<<endl;
129                     *_runLogFile<< "Finite elements method"<<endl<<endl;
130                 }
131             }
132             
133                 /**************** Field creation *********************/
134         
135                 if(!_heatPowerFieldSet){
136                         _heatPowerField=Field("Heat power",_VV.getTypeOfField(),_mesh,1);
137                         for(int i =0; i<_VV.getNumberOfElements(); i++)
138                                 _heatPowerField(i) = _heatSource;
139                 _heatPowerFieldSet=true;
140             }
141                 if(!_fluidTemperatureFieldSet){
142                         _fluidTemperatureField=Field("Fluid temperature",_VV.getTypeOfField(),_mesh,1);
143                         for(int i =0; i<_VV.getNumberOfElements(); i++)
144                                 _fluidTemperatureField(i) = _fluidTemperature;
145                 _fluidTemperatureFieldSet=true;
146                 }
147         
148             /* Détection des noeuds frontière avec une condition limite de Dirichlet */
149             if(_FECalculation)
150             {
151                 if(_NboundaryNodes==_Nnodes)
152                     cout<<"!!!!! Warning : all nodes are boundary nodes !!!!!"<<endl<<endl;
153         
154                 for(int i=0; i<_NboundaryNodes; i++)
155                 {
156                     std::map<int,double>::iterator it=_dirichletBoundaryValues.find(_boundaryNodeIds[i]);
157                     if( it != _dirichletBoundaryValues.end() )
158                         _dirichletNodeIds.push_back(_boundaryNodeIds[i]);
159                     else if( _mesh.getNode(_boundaryNodeIds[i]).getGroupNames().size()==0 )
160                     {
161                         cout<<"!!! No boundary group set for boundary node" << _boundaryNodeIds[i]<< endl;
162                         *_runLogFile<< "!!! No boundary group set for boundary node" << _boundaryNodeIds[i]<<endl;
163                         _runLogFile->close();
164                         throw CdmathException("Missing boundary group");
165                     }
166                     else if(_limitField[_mesh.getNode(_boundaryNodeIds[i]).getGroupName()].bcType==NoneBCStationaryDiffusion)
167                     {
168                         cout<<"!!! No boundary condition set for boundary node " << _boundaryNodeIds[i]<< endl;
169                         cout<<"!!! Accepted boundary conditions are DirichletStationaryDiffusion "<< DirichletStationaryDiffusion <<" and NeumannStationaryDiffusion "<< NeumannStationaryDiffusion << endl;
170                         *_runLogFile<< "!!! No boundary condition set for boundary node " << _boundaryNodeIds[i]<<endl;
171                         *_runLogFile<< "!!! Accepted boundary conditions are DirichletStationaryDiffusion "<< DirichletStationaryDiffusion <<" and NeumannStationaryDiffusion "<< NeumannStationaryDiffusion <<endl;
172                         _runLogFile->close();
173                         throw CdmathException("Missing boundary condition");
174                     }
175                     else if(_limitField[_mesh.getNode(_boundaryNodeIds[i]).getGroupName()].bcType==DirichletStationaryDiffusion)
176                         _dirichletNodeIds.push_back(_boundaryNodeIds[i]);
177                     else if(_limitField[_mesh.getNode(_boundaryNodeIds[i]).getGroupName()].bcType!=NeumannStationaryDiffusion)
178                     {
179                         cout<<"!!! Wrong boundary condition "<< _limitField[_mesh.getNode(_boundaryNodeIds[i]).getGroupName()].bcType<< " set for boundary node " << _boundaryNodeIds[i]<< endl;
180                         cout<<"!!! Accepted boundary conditions are DirichletStationaryDiffusion "<< DirichletStationaryDiffusion <<" and NeumannStationaryDiffusion "<< NeumannStationaryDiffusion << endl;
181                         *_runLogFile<< "!!! Wrong boundary condition "<< _limitField[_mesh.getNode(_boundaryNodeIds[i]).getGroupName()].bcType<< " set for boundary node " << _boundaryNodeIds[i]<<endl;
182                         *_runLogFile<< "!!! Accepted boundary conditions are DirichletStationaryDiffusion "<< DirichletStationaryDiffusion <<" and NeumannStationaryDiffusion "<< NeumannStationaryDiffusion <<endl;
183                         _runLogFile->close();
184                         throw CdmathException("Wrong boundary condition");
185                     }
186                 }       
187                 _NdirichletNodes=_dirichletNodeIds.size();
188                 _NunknownNodes=_Nnodes - _NdirichletNodes;
189                 cout<<"Number of unknown nodes " << _NunknownNodes <<", Number of boundary nodes " << _NboundaryNodes<< ", Number of Dirichlet boundary nodes " << _NdirichletNodes <<endl<<endl;
190                         *_runLogFile<<"Number of unknown nodes " << _NunknownNodes <<", Number of boundary nodes " << _NboundaryNodes<< ", Number of Dirichlet boundary nodes " << _NdirichletNodes <<endl<<endl;
191             }
192         }
193         
194     if(!_FECalculation)
195                 _globalNbUnknowns = _Nmailles*_nVar;
196     else{
197         MPI_Bcast(&_NunknownNodes, 1, MPI_INT, 0, PETSC_COMM_WORLD);
198                 _globalNbUnknowns = _NunknownNodes*_nVar;
199         }
200         
201         /* Vectors creations */
202         VecCreate(PETSC_COMM_WORLD, &_Tk);//main unknown
203     VecSetSizes(_Tk,PETSC_DECIDE,_globalNbUnknowns);
204         VecSetFromOptions(_Tk);
205         VecGetLocalSize(_Tk, &_localNbUnknowns);
206         
207         VecDuplicate(_Tk, &_Tkm1);
208         VecDuplicate(_Tk, &_deltaT);
209         VecDuplicate(_Tk, &_b);//RHS of the linear system: _b=Tn/dt + _b0 + puisance volumique + couplage thermique avec le fluide
210
211         /* Matrix creation */
212         MatCreateAIJ(PETSC_COMM_WORLD, _localNbUnknowns, _localNbUnknowns, _globalNbUnknowns, _globalNbUnknowns, _d_nnz, PETSC_NULL, _o_nnz, PETSC_NULL, &_A);
213         
214         /* Local sequential vector creation */
215         if(_mpi_size>1 && _mpi_rank == 0)
216                 VecCreateSeq(PETSC_COMM_SELF,_globalNbUnknowns,&_Tk_seq);//For saving results on proc 0
217         if(_mpi_size==0)
218                 _Tk_seq=_Tk;
219         VecScatterCreateToZero(_Tk,&_scat,&_Tk_seq);
220
221         //Linear solver
222         KSPCreate(PETSC_COMM_WORLD, &_ksp);
223         KSPSetType(_ksp, _ksptype);
224         // if(_ksptype == KSPGMRES) KSPGMRESSetRestart(_ksp,10000);
225         KSPSetTolerances(_ksp,_precision,_precision,PETSC_DEFAULT,_maxPetscIts);
226         KSPGetPC(_ksp, &_pc);
227         PCSetType(_pc, _pctype);
228
229     //Checking whether all boundary conditions are Neumann boundary condition
230     //if(_FECalculation) _onlyNeumannBC = _NdirichletNodes==0;
231     if(!_neumannValuesSet)//Boundary conditions set via LimitField structure
232     {
233         map<string, LimitFieldStationaryDiffusion>::iterator it = _limitField.begin();
234         while(it != _limitField.end() and (it->second).bcType == NeumannStationaryDiffusion)
235             it++;
236         _onlyNeumannBC = (it == _limitField.end() && _limitField.size()>0);//what if _limitField.size()==0 ???
237     }
238     else
239         if(_FECalculation)
240             _onlyNeumannBC = _neumannBoundaryValues.size()==_NboundaryNodes;
241         else
242             _onlyNeumannBC = _neumannBoundaryValues.size()==_mesh.getBoundaryFaceIds().size();
243
244     //If only Neumann BC, then matrix is singular and solution should be sought in space of mean zero vectors
245     if(_onlyNeumannBC)
246     {
247         std::cout<<"### Warning : all boundary conditions are Neumann. System matrix is not invertible since constant vectors are in the kernel."<<std::endl;
248         std::cout<<"### Check the compatibility condition between the right hand side and the boundary data. For homogeneous Neumann BCs, the right hand side must have integral equal to zero."<<std::endl;
249         std::cout<<"### The system matrix being singular, we seek a zero sum solution, and exact (LU and CHOLESKY) and incomplete factorisations (ILU and ICC) may fail."<<std::endl<<endl;
250         *_runLogFile<<"### Warning : all boundary condition are Neumann. System matrix is not invertible since constant vectors are in the kernel."<<std::endl;
251         *_runLogFile<<"### The system matrix being singular, we seek a zero sum solution, and exact (LU and CHOLESKY) and incomplete factorisations (ILU and ICC) may fail."<<std::endl<<endl;
252         *_runLogFile<<"### Check the compatibility condition between the right hand side and the boundary data. For homogeneous Neumann BCs, the right hand side must have integral equal to zero."<<std::endl;
253
254                 MatNullSpace nullsp;
255                 MatNullSpaceCreate(PETSC_COMM_WORLD, PETSC_TRUE, 0, PETSC_NULL, &nullsp);
256                 MatSetNullSpace(_A, nullsp);
257                 MatSetTransposeNullSpace(_A, nullsp);
258                 MatNullSpaceDestroy(&nullsp);
259                 //PCFactorSetShiftType(_pc,MAT_SHIFT_NONZERO);
260                 //PCFactorSetShiftAmount(_pc,1e-10);
261     }
262         _initializedMemory=true;
263 }
264
265 double StationaryDiffusionEquation::computeTimeStep(bool & stop){
266         if(!_diffusionMatrixSet)//The diffusion matrix is computed once and for all time steps
267                 computeDiffusionMatrix(stop);
268
269         _dt_src=computeRHS(stop);
270         stop=false;
271         return _dt_src;
272 }
273
274 double StationaryDiffusionEquation::computeDiffusionMatrix(bool & stop)
275 {
276     double result;
277     
278         MatZeroEntries(_A);
279         VecZeroEntries(_b);
280
281     if(_FECalculation)
282         result=computeDiffusionMatrixFE(stop);
283     else
284         result=computeDiffusionMatrixFV(stop);
285
286     MatAssemblyBegin(_A, MAT_FINAL_ASSEMBLY);
287         MatAssemblyEnd(  _A, MAT_FINAL_ASSEMBLY);
288
289     //Contribution from the solid/fluid heat exchange with assumption of constant heat transfer coefficient
290     //update value here if variable  heat transfer coefficient
291     if(_heatTransfertCoeff>_precision)
292         MatShift(_A,_heatTransfertCoeff);//Contribution from the liquit/solid heat transfer
293         
294     if(_verbose or _system)
295         MatView(_A,PETSC_VIEWER_STDOUT_WORLD);
296
297     return  result;
298 }
299
300 double StationaryDiffusionEquation::computeDiffusionMatrixFE(bool & stop){
301         if(_mpi_rank == 0)
302                 {
303                 Cell Cj;
304                 string nameOfGroup;
305                 double coeff;
306             
307             Matrix M(_Ndim+1,_Ndim+1);//cell geometry matrix
308             std::vector< Vector > GradShapeFuncs(_Ndim+1);//shape functions of cell nodes
309             std::vector< int > nodeIds(_Ndim+1);//cell node Ids
310             std::vector< Node > nodes(_Ndim+1);//cell nodes
311             int i_int, j_int; //index of nodes j and k considered as unknown nodes
312             bool dirichletCell_treated;
313             
314             std::vector< vector< double > > values(_Ndim+1,vector< double >(_Ndim+1,0));//values of shape functions on cell node
315             for (int idim=0; idim<_Ndim+1;idim++)
316                 values[idim][idim]=1;
317         
318             /* parameters for boundary treatment */
319             vector< double > valuesBorder(_Ndim+1);
320             Vector GradShapeFuncBorder(_Ndim+1);
321             
322                 for (int j=0; j<_Nmailles;j++)
323             {
324                         Cj = _mesh.getCell(j);
325         
326                 for (int idim=0; idim<_Ndim+1;idim++){
327                     nodeIds[idim]=Cj.getNodeId(idim);
328                     nodes[idim]=_mesh.getNode(nodeIds[idim]);
329                     for (int jdim=0; jdim<_Ndim;jdim++)
330                         M(idim,jdim)=nodes[idim].getPoint()[jdim];
331                     M(idim,_Ndim)=1;
332                 }
333                 for (int idim=0; idim<_Ndim+1;idim++)
334                     GradShapeFuncs[idim]=DiffusionEquation::gradientNodal(M,values[idim])/DiffusionEquation::fact(_Ndim);
335         
336                 /* Loop on the edges of the cell */
337                 for (int idim=0; idim<_Ndim+1;idim++)
338                 {
339                     if(find(_dirichletNodeIds.begin(),_dirichletNodeIds.end(),nodeIds[idim])==_dirichletNodeIds.end())//!_mesh.isBorderNode(nodeIds[idim])
340                     {//First node of the edge is not Dirichlet node
341                         i_int=DiffusionEquation::unknownNodeIndex(nodeIds[idim], _dirichletNodeIds);//assumes Dirichlet boundary node numbering is strictly increasing
342                         dirichletCell_treated=false;
343                         for (int jdim=0; jdim<_Ndim+1;jdim++)
344                         {
345                             if(find(_dirichletNodeIds.begin(),_dirichletNodeIds.end(),nodeIds[jdim])==_dirichletNodeIds.end())//!_mesh.isBorderNode(nodeIds[jdim])
346                             {//Second node of the edge is not Dirichlet node
347                                 j_int= DiffusionEquation::unknownNodeIndex(nodeIds[jdim], _dirichletNodeIds);//assumes Dirichlet boundary node numbering is strictly increasing
348                                 MatSetValue(_A,i_int,j_int,(_DiffusionTensor*GradShapeFuncs[idim])*GradShapeFuncs[jdim]/Cj.getMeasure(), ADD_VALUES);
349                             }
350                             else if (!dirichletCell_treated)
351                             {//Second node of the edge is a Dirichlet node
352                                 dirichletCell_treated=true;
353                                 for (int kdim=0; kdim<_Ndim+1;kdim++)
354                                 {
355                                                                 std::map<int,double>::iterator it=_dirichletBoundaryValues.find(nodeIds[kdim]);
356                                                                 if( it != _dirichletBoundaryValues.end() )
357                                     {
358                                         if( _dirichletValuesSet )
359                                             valuesBorder[kdim]=_dirichletBoundaryValues[it->second];
360                                         else    
361                                             valuesBorder[kdim]=_limitField[_mesh.getNode(nodeIds[kdim]).getGroupName()].T;
362                                     }
363                                     else
364                                         valuesBorder[kdim]=0;                            
365                                 }
366                                 GradShapeFuncBorder=DiffusionEquation::gradientNodal(M,valuesBorder)/DiffusionEquation::fact(_Ndim);
367                                 coeff =-1.*(_DiffusionTensor*GradShapeFuncBorder)*GradShapeFuncs[idim]/Cj.getMeasure();
368                                 VecSetValue(_b,i_int,coeff, ADD_VALUES);                        
369                             }
370                         }
371                     }
372                 }            
373                 }
374             
375             //Calcul de la contribution de la condition limite de Neumann au second membre
376             if( _NdirichletNodes !=_NboundaryNodes)
377             {
378                 vector< int > boundaryFaces = _mesh.getBoundaryFaceIds();
379                 int NboundaryFaces=boundaryFaces.size();
380                 for(int i = 0; i< NboundaryFaces ; i++)//On parcourt les faces du bord
381                 {
382                     Face Fi = _mesh.getFace(boundaryFaces[i]);
383                     for(int j = 0 ; j<_Ndim ; j++)//On parcourt les noeuds de la face
384                     {
385                         if(find(_dirichletNodeIds.begin(),_dirichletNodeIds.end(),Fi.getNodeId(j))==_dirichletNodeIds.end())//node j is a Neumann BC node (not a Dirichlet BC node)
386                         {
387                             j_int=DiffusionEquation::unknownNodeIndex(Fi.getNodeId(j), _dirichletNodeIds);//indice du noeud j en tant que noeud inconnu
388                             if( _neumannValuesSet )
389                                 coeff =Fi.getMeasure()/_Ndim*_neumannBoundaryValues[Fi.getNodeId(j)];
390                             else
391                                 coeff =Fi.getMeasure()/_Ndim*_limitField[_mesh.getNode(Fi.getNodeId(j)).getGroupName()].normalFlux;
392                             VecSetValue(_b, j_int, coeff, ADD_VALUES);
393                         }
394                     }
395                 }
396             }
397         }
398
399         if(_onlyNeumannBC)      //Check that the matrix is symmetric
400         {
401                 PetscBool isSymetric;
402                 MatIsSymmetric(_A,_precision,&isSymetric);
403                 if(!isSymetric)
404                 {
405                         cout<<"Singular matrix is not symmetric, tolerance= "<< _precision<<endl;
406                         throw CdmathException("Singular matrix should be symmetric with kernel composed of constant vectors");
407                 }
408         }
409
410         _diffusionMatrixSet=true;
411     stop=false ;
412
413         return INFINITY;
414 }
415
416 double StationaryDiffusionEquation::computeDiffusionMatrixFV(bool & stop){
417         if(_mpi_rank == 0)
418         {
419                 long nbFaces = _mesh.getNumberOfFaces();
420                 Face Fj;
421                 Cell Cell1,Cell2;
422                 string nameOfGroup;
423                 double inv_dxi, inv_dxj;
424                 double barycenterDistance;
425                 Vector normale(_Ndim);
426                 double dn;
427                 PetscInt idm, idn;
428                 std::vector< int > idCells;
429         
430                 for (int j=0; j<nbFaces;j++){
431                         Fj = _mesh.getFace(j);
432         
433                         // compute the normal vector corresponding to face j : from idCells[0] to idCells[1]
434                         idCells = Fj.getCellsId();
435                         Cell1 = _mesh.getCell(idCells[0]);
436                         idm = idCells[0];
437                 for(int l=0; l<Cell1.getNumberOfFaces(); l++){
438                     if (j == Cell1.getFacesId()[l]){
439                         for (int idim = 0; idim < _Ndim; ++idim)
440                             normale[idim] = Cell1.getNormalVector(l,idim);
441                         break;
442                     }
443                 }
444         
445                         //Compute velocity at the face Fj
446                         dn=(_DiffusionTensor*normale)*normale;
447         
448                         // compute 1/dxi = volume of Ci/area of Fj
449                 inv_dxi = Fj.getMeasure()/Cell1.getMeasure();
450         
451                         // If Fj is on the boundary
452                         if (Fj.getNumberOfCells()==1) {
453                                 if(_verbose )
454                                 {
455                                         cout << "face numero " << j << " cellule frontiere " << idCells[0] << " ; vecteur normal=(";
456                                         for(int p=0; p<_Ndim; p++)
457                                                 cout << normale[p] << ",";
458                                         cout << ") "<<endl;
459                                 }
460         
461                     std::map<int,double>::iterator it=_dirichletBoundaryValues.find(j);
462                     if( it != _dirichletBoundaryValues.end() )
463                     {
464                         barycenterDistance=Cell1.getBarryCenter().distance(Fj.getBarryCenter());
465                         MatSetValue(_A,idm,idm,dn*inv_dxi/barycenterDistance                                     , ADD_VALUES);
466                         VecSetValue(_b,idm,    dn*inv_dxi/barycenterDistance*it->second, ADD_VALUES);
467                     }
468                     else
469                     {
470                         nameOfGroup = Fj.getGroupName();
471             
472                         if (_limitField[nameOfGroup].bcType==NeumannStationaryDiffusion){
473                             VecSetValue(_b,idm,    -dn*inv_dxi*_limitField[nameOfGroup].normalFlux, ADD_VALUES);
474                         }
475                         else if(_limitField[nameOfGroup].bcType==DirichletStationaryDiffusion){
476                             barycenterDistance=Cell1.getBarryCenter().distance(Fj.getBarryCenter());
477                             MatSetValue(_A,idm,idm,dn*inv_dxi/barycenterDistance                           , ADD_VALUES);
478                             VecSetValue(_b,idm,    dn*inv_dxi/barycenterDistance*_limitField[nameOfGroup].T, ADD_VALUES);
479                         }
480                         else {
481                             stop=true ;
482                             cout<<"!!!!!!!!!!!!!!! Error StationaryDiffusionEquation::computeDiffusionMatrixFV !!!!!!!!!!"<<endl;
483                             cout<<"!!!!!! No boundary condition set for boundary named "<<nameOfGroup<< "!!!!!!!!!! _limitField[nameOfGroup].bcType= "<<_limitField[nameOfGroup].bcType<<endl;
484                             cout<<"Accepted boundary conditions are NeumannStationaryDiffusion "<<NeumannStationaryDiffusion<< " and DirichletStationaryDiffusion "<<DirichletStationaryDiffusion<<endl;
485                             *_runLogFile<<"!!!!!! Boundary condition not set for boundary named "<<nameOfGroup<< "!!!!!!!!!! _limitField[nameOfGroup].bcType= "<<_limitField[nameOfGroup].bcType<<endl;
486                             _runLogFile->close();
487                             throw CdmathException("Boundary condition not set");
488                         }
489                     }
490                                 // if Fj is inside the domain
491                         } else  if (Fj.getNumberOfCells()==2 ){
492                                 if(_verbose )
493                                 {
494                                         cout << "face numero " << j << " cellule gauche " << idCells[0] << " cellule droite " << idCells[1];
495                                         cout << " ; vecteur normal=(";
496                                         for(int p=0; p<_Ndim; p++)
497                                                 cout << normale[p] << ",";
498                                         cout << ") "<<endl;
499                                 }
500                                 Cell2 = _mesh.getCell(idCells[1]);
501                                 idn = idCells[1];
502                                 if (_Ndim > 1)
503                                         inv_dxj = Fj.getMeasure()/Cell2.getMeasure();
504                                 else
505                                         inv_dxj = 1/Cell2.getMeasure();
506                                 
507                                 barycenterDistance=Cell1.getBarryCenter().distance(Cell2.getBarryCenter());
508         
509                                 MatSetValue(_A,idm,idm, dn*inv_dxi/barycenterDistance, ADD_VALUES);
510                                 MatSetValue(_A,idm,idn,-dn*inv_dxi/barycenterDistance, ADD_VALUES);
511                                 MatSetValue(_A,idn,idn, dn*inv_dxj/barycenterDistance, ADD_VALUES);
512                                 MatSetValue(_A,idn,idm,-dn*inv_dxj/barycenterDistance, ADD_VALUES);
513                         }
514                         else
515                 {
516                     *_runLogFile<<"StationaryDiffusionEquation::computeDiffusionMatrixFV(): incompatible number of cells around a face"<<endl;
517                                 throw CdmathException("StationaryDiffusionEquation::computeDiffusionMatrixFV(): incompatible number of cells around a face");
518                 }
519                 }
520         }
521     
522         if(_onlyNeumannBC)      //Check that the matrix is symmetric
523         {
524                 PetscBool isSymetric;
525                 MatIsSymmetric(_A,_precision,&isSymetric);
526                 if(!isSymetric)
527                 {
528                         cout<<"Singular matrix is not symmetric, tolerance= "<< _precision<<endl;
529                         throw CdmathException("Singular matrix should be symmetric with kernel composed of constant vectors");
530                 }
531         }
532
533         _diffusionMatrixSet=true;
534     stop=false ;
535         
536     return INFINITY;
537 }
538
539 double StationaryDiffusionEquation::computeRHS(bool & stop)//Contribution of the PDE RHS to the linear systemm RHS (boundary conditions do contribute to the system RHS via the function computeDiffusionMatrix
540 {
541
542         if(_mpi_rank == 0)
543         {
544             if(!_FECalculation)
545                 for (int i=0; i<_Nmailles;i++)
546                     VecSetValue(_b,i, _heatTransfertCoeff*_fluidTemperatureField(i) + _heatPowerField(i) ,ADD_VALUES);
547             else
548                 {
549                     Cell Ci;
550                     std::vector< int > nodesId;
551                     for (int i=0; i<_Nmailles;i++)
552                     {
553                         Ci=_mesh.getCell(i);
554                         nodesId=Ci.getNodesId();
555                         for (int j=0; j<nodesId.size();j++)
556                             if(!_mesh.isBorderNode(nodesId[j])) 
557                             {
558                                 double coeff = _heatTransfertCoeff*_fluidTemperatureField(nodesId[j]) + _heatPowerField(nodesId[j]);
559                                 VecSetValue(_b,DiffusionEquation::unknownNodeIndex(nodesId[j], _dirichletNodeIds), coeff*Ci.getMeasure()/(_Ndim+1),ADD_VALUES);
560                             }
561                     }
562                 }
563         }
564         VecAssemblyBegin(_b);
565         VecAssemblyEnd(_b);
566
567     if(_verbose or _system)
568         VecView(_b,PETSC_VIEWER_STDOUT_WORLD);
569
570     stop=false ;
571         return INFINITY;
572 }
573
574 bool StationaryDiffusionEquation::iterateNewtonStep(bool &converged)
575 {
576         bool stop;
577
578     //Only implicit scheme considered
579
580 #if PETSC_VERSION_GREATER_3_5
581     KSPSetOperators(_ksp, _A, _A);
582 #else
583     KSPSetOperators(_ksp, _A, _A,SAME_NONZERO_PATTERN);
584 #endif
585
586     if(_conditionNumber)
587         KSPSetComputeEigenvalues(_ksp,PETSC_TRUE);
588     KSPSolve(_ksp, _b, _Tk);
589
590         KSPConvergedReason reason;
591         KSPGetConvergedReason(_ksp,&reason);
592     KSPGetIterationNumber(_ksp, &_PetscIts);
593     double residu;
594     KSPGetResidualNorm(_ksp,&residu);
595         if (reason!=2 and reason!=3)
596     {
597         PetscPrintf(PETSC_COMM_WORLD,"!!!!!!!!!!!!! Erreur système linéaire : pas de convergence de Petsc.");
598         PetscPrintf(PETSC_COMM_WORLD,"!!!!!!!!!!!!! Itérations maximales %d atteintes, résidu = %1.2f, précision demandée= %1.2f",_maxPetscIts,residu,_precision);
599         PetscPrintf(PETSC_COMM_WORLD,"Solver used %s, preconditioner %s, Final number of iteration = %d",_ksptype,_pctype,_PetscIts);
600                 *_runLogFile<<"!!!!!!!!!!!!! Erreur système linéaire : pas de convergence de Petsc."<<endl;
601         *_runLogFile<<"!!!!!!!!!!!!! Itérations maximales "<<_maxPetscIts<<" atteintes, résidu="<<residu<<", précision demandée= "<<_precision<<endl;
602         *_runLogFile<<"Solver used "<<  _ksptype<<", preconditioner "<<_pctype<<", Final number of iteration= "<<_PetscIts<<endl;
603                 _runLogFile->close();
604         converged = false;
605         stop = true;
606     }
607     else{
608         if( _MaxIterLinearSolver < _PetscIts)
609             _MaxIterLinearSolver = _PetscIts;
610         PetscPrintf(PETSC_COMM_WORLD,"## Système linéaire résolu en %d itérations par le solveur %s et le preconditioneur %s, précision demandée = %1.2f",_PetscIts,_ksptype,_pctype,_precision);
611                 *_runLogFile<<"## Système linéaire résolu en "<<_PetscIts<<" itérations par le solveur "<<  _ksptype<<" et le preconditioneur "<<_pctype<<", précision demandée= "<<_precision<<endl<<endl;
612         VecCopy(_Tk, _deltaT);//ici on a deltaT=Tk
613         VecAXPY(_deltaT,  -1, _Tkm1);//On obtient deltaT=Tk-Tkm1
614
615         VecAssemblyBegin(_Tk);
616         VecAssemblyEnd(  _Tk);
617         VecAssemblyBegin(_deltaT);
618         VecAssemblyEnd(  _deltaT);
619
620                 if(_verbose)
621                         PetscPrintf(PETSC_COMM_WORLD,"Début calcul de l'erreur maximale");
622
623                 VecNorm(_deltaT,NORM_INFINITY,&_erreur_rel);
624
625                 if(_verbose)
626                         PetscPrintf(PETSC_COMM_WORLD,"Fin calcul de la variation relative, erreur maximale : %1.2f", _erreur_rel );
627         stop=false;
628         converged = (_erreur_rel <= _precision) ;//converged=convergence des iterations de Newton
629     }
630
631         VecCopy(_Tk, _Tkm1);
632
633         return stop;
634 }
635
636 void StationaryDiffusionEquation::setMesh(const Mesh &M)
637 {
638         if(_mpi_rank==0)
639         {
640                 if(_Ndim != M.getSpaceDimension() or _Ndim!=M.getMeshDimension())//for the moment we must have space dim=mesh dim
641                 {
642                 cout<< "Problem : dimension defined is "<<_Ndim<< " but mesh dimension= "<<M.getMeshDimension()<<", and space dimension is "<<M.getSpaceDimension()<<endl;
643                         *_runLogFile<< "Problem : dim = "<<_Ndim<< " but mesh dim= "<<M.getMeshDimension()<<", mesh space dim= "<<M.getSpaceDimension()<<endl;
644                         *_runLogFile<<"StationaryDiffusionEquation::setMesh: mesh has incorrect dimension"<<endl;
645                         _runLogFile->close();
646                         throw CdmathException("StationaryDiffusionEquation::setMesh: mesh has incorrect  dimension");
647                 }
648         
649                 _mesh=M;
650                 _Nmailles = _mesh.getNumberOfCells();
651                 _Nnodes =   _mesh.getNumberOfNodes();
652             
653             cout<<"Mesh has "<< _Nmailles << " cells and " << _Nnodes << " nodes"<<endl<<endl;;
654                 *_runLogFile<<"Mesh has "<< _Nmailles << " cells and " << _Nnodes << " nodes"<<endl<<endl;
655             
656                 // find  maximum nb of neibourghs
657             if(!_FECalculation)
658             {
659                 _VV=Field ("Temperature", CELLS, _mesh, 1);
660                 _neibMaxNbCells=_mesh.getMaxNbNeighbours(CELLS);
661             }
662             else
663             {
664                 if(_Ndim==1 )//The 1D cdmath mesh is necessarily made of segments
665                                 cout<<"1D Finite element method on segments"<<endl;
666                 else if(_Ndim==2)
667                 {
668                                 if( _mesh.isTriangular() )//Mesh dim=2
669                                         cout<<"2D Finite element method on triangles"<<endl;
670                                 else if (_mesh.getMeshDimension()==1)//Mesh dim=1
671                                         cout<<"1D Finite element method on a 2D network : space dimension is "<<_Ndim<< ", mesh dimension is "<<_mesh.getMeshDimension()<<endl;                 
672                                 else
673                                 {
674                                         cout<<"Error Finite element with Space dimension "<<_Ndim<< ", and mesh dimension  "<<_mesh.getMeshDimension()<< ", mesh should be either triangular either 1D network"<<endl;
675                                         *_runLogFile<<"StationaryDiffusionEquation::setMesh: mesh has incorrect dimension"<<endl;
676                                         _runLogFile->close();
677                                         throw CdmathException("StationaryDiffusionEquation::setMesh: mesh has incorrect cell types");
678                                 }
679                 }
680                 else if(_Ndim==3)
681                 {
682                                 if( _mesh.isTetrahedral() )//Mesh dim=3
683                                         cout<<"3D Finite element method on tetrahedra"<<endl;
684                                 else if (_mesh.getMeshDimension()==2 and _mesh.isTriangular())//Mesh dim=2
685                                         cout<<"2D Finite element method on a 3D surface : space dimension is "<<_Ndim<< ", mesh dimension is "<<_mesh.getMeshDimension()<<endl;                 
686                                 else if (_mesh.getMeshDimension()==1)//Mesh dim=1
687                                         cout<<"1D Finite element method on a 3D network : space dimension is "<<_Ndim<< ", mesh dimension is "<<_mesh.getMeshDimension()<<endl;                 
688                                 else
689                                 {
690                                         cout<<"Error Finite element with Space dimension "<<_Ndim<< ", and mesh dimension  "<<_mesh.getMeshDimension()<< ", mesh should be either tetrahedral, either a triangularised surface or 1D network"<<endl;
691                                         *_runLogFile<<"StationaryDiffusionEquation::setMesh: mesh has incorrect dimension"<<endl;
692                                         _runLogFile->close();
693                                         throw CdmathException("StationaryDiffusionEquation::setMesh: mesh has incorrect cell types");
694                                 }
695                 }
696         
697                         _VV=Field ("Temperature", NODES, _mesh, 1);
698         
699                 _neibMaxNbNodes=_mesh.getMaxNbNeighbours(NODES);
700                 _boundaryNodeIds = _mesh.getBoundaryNodeIds();
701                 _NboundaryNodes=_boundaryNodeIds.size();
702             }
703         }
704         
705         /* MPI distribution parameters */
706         int nbVoisinsMax;//Mettre en attribut ?
707         if(!_FECalculation){
708                 MPI_Bcast(&_Nmailles      , 1, MPI_INT, 0, PETSC_COMM_WORLD);
709                 MPI_Bcast(&_neibMaxNbCells, 1, MPI_INT, 0, PETSC_COMM_WORLD);
710                 nbVoisinsMax = _neibMaxNbCells;
711         }
712         else{
713                 MPI_Bcast(&_Nnodes        , 1, MPI_INT, 0, PETSC_COMM_WORLD);
714                 MPI_Bcast(&_neibMaxNbNodes, 1, MPI_INT, 0, PETSC_COMM_WORLD);
715                 nbVoisinsMax = _neibMaxNbNodes;
716         }
717     _d_nnz = (nbVoisinsMax+1)*_nVar;
718     _o_nnz =  nbVoisinsMax   *_nVar;
719
720         _meshSet=true;
721 }
722
723 void StationaryDiffusionEquation::setLinearSolver(linearSolver kspType, preconditioner pcType)
724 {
725         //_maxPetscIts=maxIterationsPetsc;
726         // set linear solver algorithm
727         if (kspType==GMRES)
728                 _ksptype = (char*)&KSPGMRES;
729         else if (kspType==CG)
730                 _ksptype = (char*)&KSPCG;
731         else if (kspType==BCGS)
732                 _ksptype = (char*)&KSPBCGS;
733         else {
734                 cout << "!!! Error : only 'GMRES', 'CG' or 'BCGS' is acceptable as a linear solver !!!" << endl;
735                 *_runLogFile << "!!! Error : only 'GMRES', 'CG' or 'BCGS' is acceptable as a linear solver !!!" << endl;
736                 _runLogFile->close();
737                 throw CdmathException("!!! Error : only 'GMRES', 'CG' or 'BCGS' algorithm is acceptable !!!");
738         }
739         // set preconditioner
740         if (pcType == NONE)
741                 _pctype = (char*)&PCNONE;
742         else if (pcType ==LU)
743                 _pctype = (char*)&PCLU;
744         else if (pcType == ILU)
745                 _pctype = (char*)&PCILU;
746         else if (pcType ==CHOLESKY)
747                 _pctype = (char*)&PCCHOLESKY;
748         else if (pcType == ICC)
749                 _pctype = (char*)&PCICC;
750         else {
751                 cout << "!!! Error : only 'NOPC', 'LU', 'ILU', 'CHOLESKY' or 'ICC' preconditioners are acceptable !!!" << endl;
752                 *_runLogFile << "!!! Error : only 'NOPC' or 'LU' or 'ILU' preconditioners are acceptable !!!" << endl;
753                 _runLogFile->close();
754                 throw CdmathException("!!! Error : only 'NOPC' or 'LU' or 'ILU' preconditioners are acceptable !!!" );
755         }
756 }
757
758 bool StationaryDiffusionEquation::solveStationaryProblem()
759 {
760         if(!_initializedMemory)
761         {
762                 *_runLogFile<< "ProblemCoreFlows::run() call initialize() first"<< _fileName<<endl;
763                 _runLogFile->close();
764                 throw CdmathException("ProblemCoreFlows::run() call initialize() first");
765         }
766         bool stop=false; // Does the Problem want to stop (error) ?
767         bool converged=false; // has the newton scheme converged (end) ?
768
769         PetscPrintf(PETSC_COMM_WORLD,"!!! Running test case %s using ",_fileName);
770         *_runLogFile<< "!!! Running test case "<< _fileName<< " using ";
771
772     if(!_FECalculation)
773     {
774         PetscPrintf(PETSC_COMM_WORLD,"Finite volumes method\n\n");
775                 *_runLogFile<< "Finite volumes method"<<endl<<endl;
776         }
777     else
778         {
779         PetscPrintf(PETSC_COMM_WORLD,"Finite elements method\n\n");
780                 *_runLogFile<< "Finite elements method"<< endl<<endl;
781         }
782
783     computeDiffusionMatrix( stop);//For the moment the conductivity does not depend on the temperature (linear LHS)
784     if (stop){
785         PetscPrintf(PETSC_COMM_WORLD,"Error : failed computing diffusion matrix, stopping calculation\n");
786         *_runLogFile << "Error : failed computing diffusion matrix, stopping calculation"<< endl;
787                 _runLogFile->close();
788        throw CdmathException("Failed computing diffusion matrix");
789     }
790     computeRHS(stop);//For the moment the heat power does not depend on the unknown temperature (linear RHS)
791     if (stop){
792         PetscPrintf(PETSC_COMM_WORLD,"Error : failed computing right hand side, stopping calculation\n");
793         *_runLogFile << "Error : failed computing right hand side, stopping calculation"<< endl;
794         throw CdmathException("Failed computing right hand side");
795     }
796     stop = iterateNewtonStep(converged);
797     if (stop){
798         PetscPrintf(PETSC_COMM_WORLD,"Error : failed solving linear system, stopping calculation\n");
799         *_runLogFile << "Error : failed linear system, stopping calculation"<< endl;
800                 _runLogFile->close();
801         throw CdmathException("Failed solving linear system");
802     }
803     
804     _computationCompletedSuccessfully=true;
805     save();
806
807         // Newton iteration loop for non linear problems
808     /*
809         while(!stop and !converged and _NEWTON_its<_maxNewtonIts)
810         {
811         computeDiffusionMatrix( stop);//case when the conductivity depends on the temperature (nonlinear LHS)
812         computeRHS(stop);//case the heat power depends on the unknown temperature (nonlinear RHS)
813         stop = iterateNewtonStep(converged);
814         _NEWTON_its++;
815         }
816     if (stop){
817         cout << "Error : failed solving Newton iteration "<<_NEWTON_its<<", stopping calculation"<< endl;
818         *_runLogFile << "Error : failed solving Newton iteration "<<_NEWTON_its<<", stopping calculation"<< endl;
819         throw CdmathException("Failed solving a Newton iteration");
820     }
821     else if(_NEWTON_its==_maxNewtonIts){
822         cout << "Error : no convergence of Newton scheme. Maximum Newton iterations "<<_maxNewtonIts<<" reached, stopping calculation"<< endl;
823         *_runLogFile << "Error : no convergence of Newton scheme. Maximum Newton iterations "<<_maxNewtonIts<<" reached, stopping calculation"<< endl;
824         throw CdmathException("No convergence of Newton scheme");
825     }
826     else{
827         cout << "Convergence of Newton scheme at iteration "<<_NEWTON_its<<", end of calculation"<< endl;
828         *_runLogFile << "Convergence of Newton scheme at iteration "<<_NEWTON_its<<", end of calculation"<< endl;
829         save();
830     }
831     */
832     
833     *_runLogFile<< "!!!!!! Computation successful !!!!!!"<< endl;
834         _runLogFile->close();
835
836         return !stop;
837 }
838
839 void StationaryDiffusionEquation::save(){
840     PetscPrintf(PETSC_COMM_WORLD,"Saving numerical results\n\n");
841     *_runLogFile<< "Saving numerical results"<< endl<<endl;
842
843         string resultFile(_path+"/StationaryDiffusionEquation");//Results
844
845         resultFile+="_";
846         resultFile+=_fileName;
847
848         // create mesh and component info
849     string suppress ="rm -rf "+resultFile+"_*";
850     system(suppress.c_str());//Nettoyage des précédents calculs identiques
851     
852         if(_mpi_size>1){
853                 VecScatterBegin(_scat,_Tk,_Tk_seq,INSERT_VALUES,SCATTER_FORWARD);
854                 VecScatterEnd(  _scat,_Tk,_Tk_seq,INSERT_VALUES,SCATTER_FORWARD);
855         }
856
857     if(_verbose or _system)
858         VecView(_Tk,PETSC_VIEWER_STDOUT_WORLD);
859
860         if(_mpi_rank==0){
861             double Ti; 
862             if(!_FECalculation)
863                 for(int i=0; i<_Nmailles; i++)
864                     {
865                                         if(_mpi_size>1)
866                                                 VecGetValues(_Tk_seq, 1, &i, &Ti);
867                                         else
868                                                 VecGetValues(_Tk    , 1, &i, &Ti);
869                         _VV(i)=Ti;
870                     }
871             else
872             {
873                 int globalIndex;
874                 for(int i=0; i<_NunknownNodes; i++)
875                 {
876                                 if(_mpi_size>1)
877                                         VecGetValues(_Tk_seq, 1, &i, &Ti);
878                                 else
879                                         VecGetValues(_Tk    , 1, &i, &Ti);
880                     globalIndex = DiffusionEquation::globalNodeIndex(i, _dirichletNodeIds);
881                     _VV(globalIndex)=Ti;
882                 }
883         
884                 Node Ni;
885                 string nameOfGroup;
886                 for(int i=0; i<_NdirichletNodes; i++)
887                 {
888                     Ni=_mesh.getNode(_dirichletNodeIds[i]);
889                     nameOfGroup = Ni.getGroupName();
890                     _VV(_dirichletNodeIds[i])=_limitField[nameOfGroup].T;
891                 }
892             }
893         
894             _VV.setInfoOnComponent(0,"Temperature_(K)");
895             switch(_saveFormat)
896             {
897                 case VTK :
898                     _VV.writeVTK(resultFile);
899                     break;
900                 case MED :
901                     _VV.writeMED(resultFile);
902                     break;
903                 case CSV :
904                     _VV.writeCSV(resultFile);
905                     break;
906             }
907         }
908 }
909
910 void StationaryDiffusionEquation::terminate()
911 {
912         VecDestroy(&_Tk);
913         VecDestroy(&_Tkm1);
914         VecDestroy(&_deltaT);
915         VecDestroy(&_b);
916         MatDestroy(&_A);
917         if(_mpi_size>1 && _mpi_rank == 0)
918                 VecDestroy(&_Tk_seq);
919
920         PetscBool petscInitialized;
921         PetscInitialized(&petscInitialized);
922         if(petscInitialized)
923                 PetscFinalize();
924
925         delete _runLogFile;
926 }
927 void 
928 StationaryDiffusionEquation::setDirichletValues(map< int, double> dirichletBoundaryValues)
929 {
930     _dirichletValuesSet=true;
931     _dirichletBoundaryValues=dirichletBoundaryValues;
932 }
933
934 void 
935 StationaryDiffusionEquation::setNeumannValues(map< int, double> neumannBoundaryValues)
936 {
937     _neumannValuesSet=true;
938     _neumannBoundaryValues=neumannBoundaryValues;
939 }
940
941 double 
942 StationaryDiffusionEquation::getConditionNumber(bool isSingular, double tol) const
943 {
944   SparseMatrixPetsc A = SparseMatrixPetsc(_A);
945   return A.getConditionNumber( isSingular, tol);
946 }
947 std::vector< double > 
948 StationaryDiffusionEquation::getEigenvalues(int nev, EPSWhich which, double tol) const
949 {
950   SparseMatrixPetsc A = SparseMatrixPetsc(_A);
951   
952   if(_FECalculation)//We need to scale the FE matrix, otherwise the eigenvalues go to zero as the mesh is refined
953   {
954       Vector nodal_volumes(_NunknownNodes);
955       int j_int;
956       for(int i = 0; i< _Nmailles ; i++)//On parcourt les cellules du maillage
957       {
958         Cell Ci = _mesh.getCell(i);
959         for(int j = 0 ; j<_Ndim+1 ; j++)//On parcourt les noeuds de la cellule
960         {
961             if(find(_dirichletNodeIds.begin(),_dirichletNodeIds.end(),Ci.getNodeId(j))==_dirichletNodeIds.end())//node j is an unknown node (not a Dirichlet node)
962                         {
963                 j_int=DiffusionEquation::unknownNodeIndex(Ci.getNodeId(j), _dirichletNodeIds);//indice du noeud j en tant que noeud inconnu
964                 nodal_volumes[j_int]+=Ci.getMeasure()/(_Ndim+1);
965             }
966         }
967        }
968       for( j_int = 0; j_int< _NunknownNodes ; j_int++)
969         nodal_volumes[j_int]=1/nodal_volumes[j_int];
970       A.leftDiagonalScale(nodal_volumes);
971   }
972
973   return A.getEigenvalues( nev, which, tol);
974 }
975 std::vector< Vector > 
976 StationaryDiffusionEquation::getEigenvectors(int nev, EPSWhich which, double tol) const
977 {
978   SparseMatrixPetsc A = SparseMatrixPetsc(_A);
979   return A.getEigenvectors( nev, which, tol);
980 }
981 Field 
982 StationaryDiffusionEquation::getEigenvectorsField(int nev, EPSWhich which, double tol) const
983 {
984   SparseMatrixPetsc A = SparseMatrixPetsc(_A);
985   MEDCoupling::DataArrayDouble * d = A.getEigenvectorsDataArrayDouble( nev, which, tol);
986   Field my_eigenfield;
987   
988     my_eigenfield = Field("Eigenvectors field", _VV.getTypeOfField(), _mesh, nev);
989
990   my_eigenfield.setFieldByDataArrayDouble(d);
991   
992   return my_eigenfield;
993 }
994
995 Field&
996 StationaryDiffusionEquation::getOutputTemperatureField()
997 {
998     if(!_computationCompletedSuccessfully)
999         throw("Computation not performed yet or failed. No temperature field available");
1000     else
1001         return _VV;
1002 }
1003
1004 Field& 
1005 StationaryDiffusionEquation::getRodTemperatureField()
1006 {
1007    return getOutputTemperatureField();
1008 }
1009
1010 vector<string> 
1011 StationaryDiffusionEquation::getInputFieldsNames()
1012 {
1013         vector<string> result(2);
1014         
1015         result[0]="FluidTemperature";
1016         result[1]="HeatPower";
1017         
1018         return result;
1019 }
1020 vector<string> 
1021 StationaryDiffusionEquation::getOutputFieldsNames()
1022 {
1023         vector<string> result(1);
1024         
1025         result[0]="RodTemperature";
1026         
1027         return result;
1028 }
1029
1030 Field& 
1031 StationaryDiffusionEquation::getOutputField(const string& nameField )
1032 {
1033         if(nameField=="RodTemperature" || nameField=="RODTEMPERATURE" || nameField=="TEMPERATURECOMBUSTIBLE" || nameField=="TemperatureCombustible" )
1034                 return getRodTemperatureField();
1035     else
1036     {
1037         cout<<"Error : Field name "<< nameField << " does not exist, call getOutputFieldsNames first" << endl;
1038         throw CdmathException("DiffusionEquation::getOutputField error : Unknown Field name");
1039     }
1040 }
1041
1042 void
1043 StationaryDiffusionEquation::setInputField(const string& nameField, Field& inputField )
1044 {
1045         if(nameField=="FluidTemperature" || nameField=="FLUIDTEMPERATURE" || nameField=="TemperatureFluide" || nameField=="TEMPERATUREFLUIDE")
1046                 return setFluidTemperatureField( inputField) ;
1047         else if(nameField=="HeatPower" || nameField=="HEATPOWER" || nameField=="PuissanceThermique" || nameField=="PUISSANCETHERMIQUE" )
1048                 return setHeatPowerField( inputField );
1049         else
1050     {
1051         cout<<"Error : Field name "<< nameField << " is not an input field name, call getInputFieldsNames first" << endl;
1052         throw CdmathException("StationaryDiffusionEquation::setInputField error : Unknown Field name");
1053     }
1054 }