1 //============================================================================
2 // Name : Problème CoreFlows
5 // Copyright : CEA Saclay 2014
6 // Description : Classe générique des problèmes de Thermohydraulique
7 // Il s'agit d'une classe virtuelle pure (non instanciable qui regroupe
8 // les fonctionalités communes à tous les codes thermohydraulique.
9 // Le but est d'avoir une interface commune rendant
10 // plus lisibles et plus evolutifs les codes dévelopés avec CDMATH
11 //============================================================================
13 #include "ProblemCoreFlows.hxx"
14 #include "SparseMatrixPetsc.hxx"
21 ProblemCoreFlows::ProblemCoreFlows()
23 PetscBool petscInitialized;
24 PetscInitialized(&petscInitialized);
26 PetscInitialize(NULL,NULL,0,0);
34 _precision_Newton=_precision;
40 _fileName = "myCoreFlowsProblem";
42 _initialDataSet=false;
43 _initializedMemory=false;
44 _restartWithNewTimeScheme=false;
45 _restartWithNewFileName=false;
47 _wellBalancedCorrection=false;
50 _MaxIterLinearSolver=0;//During several newton iterations, stores the max petssc interations
53 int _PetscIts=0;//the number of iterations of the linear solver
54 _ksptype = (char*)&KSPGMRES;
55 _pctype = (char*)&PCLU;
56 _nonLinearSolver = Newton_SOLVERLAB;
57 _heatPowerFieldSet=false;
58 _heatTransfertCoeff=0;
59 _rodTemperatureFieldSet=false;
63 _conditionNumber=false;
65 _runLogFile=new ofstream;
67 //extracting current directory
68 char result[ PATH_MAX ];
69 getcwd(result, PATH_MAX );
70 _path=string( result );
74 TimeScheme ProblemCoreFlows::getTimeScheme()
79 void ProblemCoreFlows::setTimeScheme(TimeScheme timeScheme)
81 if( _nbTimeStep>0 && timeScheme!=_timeScheme)//This is a change of time scheme during a simulation
82 _restartWithNewTimeScheme=true;
83 _timeScheme = timeScheme;
86 bool ProblemCoreFlows::isStationary() const
91 double ProblemCoreFlows::presentTime() const
95 void ProblemCoreFlows::setTimeMax(double timeMax){
98 void ProblemCoreFlows::setPresentTime (double time)
102 void ProblemCoreFlows::setMaxNbOfTimeStep(int maxNbOfTimeStep){
103 _maxNbOfTimeStep = maxNbOfTimeStep;
105 void ProblemCoreFlows::setCFL(double cfl)
109 void ProblemCoreFlows::setPrecision(double precision)
111 _precision=precision;
113 void ProblemCoreFlows::setInitialField(const Field &VV)
116 if(_Ndim != VV.getSpaceDimension()){
117 *_runLogFile<<"ProblemCoreFlows::setInitialField: mesh has incorrect space dimension"<<endl;
118 _runLogFile->close();
119 throw CdmathException("ProblemCoreFlows::setInitialField: mesh has incorrect space dimension");
121 if(_nVar!=VV.getNumberOfComponents())
123 *_runLogFile<<"ProblemCoreFlows::setInitialField: Initial field has incorrect number of components"<<endl;
124 _runLogFile->close();
125 throw CdmathException("ProblemCoreFlows::setInitialField: Initial field has incorrect number of components");
131 _Nmailles = _mesh.getNumberOfCells();
132 _Nnodes = _mesh.getNumberOfNodes();
133 _Nfaces = _mesh.getNumberOfFaces();
134 _perimeters=Field("Perimeters", CELLS, _mesh,1);
136 // find _minl and maximum nb of neibourghs
138 int nbNeib,indexFace;
143 cout<<"Computing cell perimeters and mesh minimal diameter"<<endl;
145 if(VV.getTypeOfField()==NODES)
147 _minl = _mesh.getMaxNbNeighbours(NODES);
148 _neibMaxNbNodes=_mesh.getMaxNbNeighbours(NODES);
151 for (int i=0; i<_mesh.getNumberOfCells(); i++){
152 Ci = _mesh.getCell(i);
153 //Detect mesh with junction
155 for(int j=0; j<Ci.getNumberOfFaces(); j++){
156 Fk=_mesh.getFace(Ci.getFacesId()[j]);
157 nbNeib+=Fk.getNumberOfCells()-1;
159 if(nbNeib>_neibMaxNb)
164 for (int k=0 ; k<Ci.getNumberOfFaces() ; k++){
165 indexFace=Ci.getFacesId()[k];
166 Fk = _mesh.getFace(indexFace);
167 _minl = min(_minl,Ci.getMeasure()/Fk.getMeasure());
168 _perimeters(i)+=Fk.getMeasure();
171 _minl = min(_minl,Ci.getMeasure());
172 _perimeters(i)=Ci.getNumberOfFaces();
175 _initialDataSet=true;
178 cout<<_perimeters<<endl;
180 void ProblemCoreFlows::setInitialField(string fileName, string fieldName, int timeStepNumber)
182 Field VV(fileName,CELLS,fieldName,timeStepNumber,0);
185 void ProblemCoreFlows::setInitialFieldConstant(string fileName, const vector<double> Vconstant)
188 Field VV("SOLVERLAB results", CELLS, M, Vconstant.size());
190 for (int j = 0; j < M.getNumberOfCells(); j++) {
191 for (int i=0; i< VV.getNumberOfComponents(); i++)
192 VV(j,i) = Vconstant[i];
197 void ProblemCoreFlows:: setInitialFieldConstant(const Mesh& M, const Vector Vconstant)
199 Field VV("SOLVERLAB results", CELLS, M, Vconstant.getNumberOfRows());
201 for (int j = 0; j < M.getNumberOfCells(); j++) {
202 for (int i=0; i< VV.getNumberOfComponents(); i++)
203 VV(j,i) = Vconstant(i);
207 void ProblemCoreFlows:: setInitialFieldConstant(const Mesh& M, const vector<double> Vconstant)
209 Field VV("SOLVERLAB results", CELLS, M, Vconstant.size());
211 for (int j = 0; j < M.getNumberOfCells(); j++) {
212 for (int i=0; i< VV.getNumberOfComponents(); i++)
213 VV(j,i) = Vconstant[i];
217 void ProblemCoreFlows::setInitialFieldConstant( int nDim, const vector<double> Vconstant, double xmin, double xmax, int nx, string leftSide, string rightSide,
218 double ymin, double ymax, int ny, string backSide, string frontSide,
219 double zmin, double zmax, int nz, string bottomSide, string topSide)
223 //cout<<"coucou1 xmin="<<xmin<<", xmax= "<<xmax<< ", nx= "<<nx<<endl;
224 M=Mesh(xmin,xmax,nx);
225 //cout<<"coucou2"<<endl;
228 M=Mesh(xmin,xmax,nx,ymin,ymax,ny);
230 M=Mesh(xmin,xmax,nx,ymin,ymax,ny,zmin,zmax,nz);
232 cout<<"ProblemCoreFlows::setInitialFieldConstant: Space dimension nDim should be between 1 and 3"<<endl;
233 *_runLogFile<<"ProblemCoreFlows::setInitialFieldConstant: Space dimension nDim should be between 1 and 3"<<endl;
234 _runLogFile->close();
235 throw CdmathException("Space dimension nDim should be between 1 and 3");
238 M.setGroupAtPlan(xmax,0,_precision,rightSide);
239 M.setGroupAtPlan(xmin,0,_precision,leftSide);
241 M.setGroupAtPlan(ymax,1,_precision,frontSide);
242 M.setGroupAtPlan(ymin,1,_precision,backSide);
245 M.setGroupAtPlan(zmax,2,_precision,topSide);
246 M.setGroupAtPlan(zmin,2,_precision,bottomSide);
249 setInitialFieldConstant(M, Vconstant);
251 void ProblemCoreFlows::setInitialFieldStepFunction(const Mesh M, const Vector VV_Left, const Vector VV_Right, double disc_pos, int direction)
253 if (VV_Right.getNumberOfRows()!=VV_Left.getNumberOfRows())
255 *_runLogFile<<"ProblemCoreFlows::setStepFunctionInitialField: Vectors VV_Left and VV_Right have different sizes"<<endl;
256 _runLogFile->close();
257 throw CdmathException( "ProblemCoreFlows::setStepFunctionInitialField: Vectors VV_Left and VV_Right have different sizes");
259 Field VV("SOLVERLAB results", CELLS, M, VV_Left.getNumberOfRows());
261 double component_value;
263 for (int j = 0; j < M.getNumberOfCells(); j++) {
265 component_value=M.getCell(j).x();
266 else if(direction==1)
267 component_value=M.getCell(j).y();
268 else if(direction==2)
269 component_value=M.getCell(j).z();
271 _runLogFile->close();
272 throw CdmathException( "ProblemCoreFlows::setStepFunctionInitialField: direction should be an integer between 0 and 2");
275 for (int i=0; i< VV.getNumberOfComponents(); i++)
276 if (component_value< disc_pos )
277 VV(j,i) = VV_Left[i];
279 VV(j,i) = VV_Right[i];
283 void ProblemCoreFlows::setInitialFieldStepFunction( int nDim, const vector<double> VV_Left, vector<double> VV_Right, double xstep,
284 double xmin, double xmax, int nx, string leftSide, string rightSide,
285 double ymin, double ymax, int ny, string backSide, string frontSide,
286 double zmin, double zmax, int nz, string bottomSide, string topSide)
290 M=Mesh(xmin,xmax,nx);
292 M=Mesh(xmin,xmax,nx,ymin,ymax,ny);
294 M=Mesh(xmin,xmax,nx,ymin,ymax,ny,zmin,zmax,nz);
297 _runLogFile->close();
298 throw CdmathException("Space dimension nDim should be between 1 and 3");
301 M.setGroupAtPlan(xmax,0,_precision,rightSide);
302 M.setGroupAtPlan(xmin,0,_precision,leftSide);
304 M.setGroupAtPlan(ymax,1,_precision,frontSide);
305 M.setGroupAtPlan(ymin,1,_precision,backSide);
308 M.setGroupAtPlan(zmax,2,_precision,topSide);
309 M.setGroupAtPlan(zmin,2,_precision,bottomSide);
311 Vector V_Left(VV_Left.size()), V_Right(VV_Right.size());
312 for(int i=0;i<VV_Left.size(); i++){
313 V_Left(i)=VV_Left[i];
314 V_Right(i)=VV_Right[i];
316 setInitialFieldStepFunction(M, V_Left, V_Right, xstep);
319 void ProblemCoreFlows::setInitialFieldSphericalStepFunction(const Mesh M, const Vector Vin, const Vector Vout, double radius, const Vector Center)
321 if((Center.size()!=M.getSpaceDimension()) || (Vout.size() != Vin.size()) )
323 cout<< "Vout.size()= "<<Vout.size() << ", Vin.size()= "<<Vin.size()<<", Center.size()="<<Center.size()<<", M.getSpaceDim= "<< M.getSpaceDimension()<<endl;
324 throw CdmathException("ProblemCoreFlows::setInitialFieldSphericalStepFunction : Vector size error");
326 int nVar=Vout.size();
327 int spaceDim=M.getSpaceDimension();
328 Field VV("Primitive variables for spherical step function", CELLS, M, nVar);
330 Vector currentPoint(spaceDim);
331 for(int i=0;i<M.getNumberOfCells();i++)
333 currentPoint(0)=M.getCell(i).x();
336 currentPoint(1)=M.getCell(i).y();
338 currentPoint(2)=M.getCell(i).z();
340 if((currentPoint-Center).norm()<radius)
341 for(int j=0;j<nVar;j++)
344 for(int j=0;j<nVar;j++)
350 double ProblemCoreFlows::getTime()
354 unsigned ProblemCoreFlows::getNbTimeStep()
358 double ProblemCoreFlows::getCFL()
362 double ProblemCoreFlows::getPrecision()
366 Mesh ProblemCoreFlows::getMesh()
371 void ProblemCoreFlows::setLinearSolver(linearSolver kspType, preconditioner pcType)
373 //_maxPetscIts=maxIterationsPetsc;
374 // set linear solver algorithm
376 _ksptype = (char*)&KSPGMRES;
377 else if (kspType==CG)
378 _ksptype = (char*)&KSPCG;
379 else if (kspType==BCGS)
380 _ksptype = (char*)&KSPBCGS;
382 cout << "!!! Error : only 'GMRES', 'CG' or 'BCGS' is acceptable as a linear solver !!!" << endl;
383 *_runLogFile << "!!! Error : only 'GMRES', 'CG' or 'BCGS' is acceptable as a linear solver !!!" << endl;
384 _runLogFile->close();
385 throw CdmathException("!!! Error : only 'GMRES', 'CG' or 'BCGS' algorithm is acceptable !!!");
387 // set preconditioner
389 _pctype = (char*)&PCNONE;
390 else if (pcType ==LU)
391 _pctype = (char*)&PCLU;
392 else if (pcType == ILU)
393 _pctype = (char*)&PCILU;
394 else if (pcType ==CHOLESKY)
395 _pctype = (char*)&PCCHOLESKY;
396 else if (pcType == ICC)
397 _pctype = (char*)&PCICC;
399 cout << "!!! Error : only 'NONE', 'LU', 'ILU', 'CHOLESKY' or 'ICC' preconditioners are acceptable !!!" << endl;
400 *_runLogFile << "!!! Error : only 'NONE' or 'LU' or 'ILU' preconditioners are acceptable !!!" << endl;
401 _runLogFile->close();
402 throw CdmathException("!!! Error : only 'NONE' or 'LU' or 'ILU' preconditioners are acceptable !!!" );
406 void ProblemCoreFlows::setNewtonSolver(double precision, int iterations, nonLinearSolver solverName)
408 _maxNewtonIts=iterations;
409 _precision_Newton=precision;
410 _nonLinearSolver=solverName;
415 // Cette methode lance une execution du ProblemCoreFlows
416 // Elle peut etre utilisee si le probleme n'est couple a aucun autre.
417 // (s'il n'a besoin d'aucun champ d'entree).
418 // Precondition: initialize
419 // Seule la methode terminate peut etre appelée apres
420 bool ProblemCoreFlows::run()
422 if(!_initializedMemory)
424 _runLogFile->close();
425 throw CdmathException("ProblemCoreFlows::run() call initialize() first");
427 bool stop=false; // Does the Problem want to stop (error) ?
428 bool ok; // Is the time interval successfully solved ?
429 _isStationary=false;//in case of a second run with a different physics or cfl
431 cout<< "Running test case "<< _fileName<<endl;
433 _runLogFile->open((_fileName+".log").c_str(), ios::out | ios::trunc);;//for creation of a log file to save the history of the simulation
434 *_runLogFile<< "Running test case "<< _fileName<<endl;
437 while(!stop && !_isStationary &&_time<_timeMax && _nbTimeStep<_maxNbOfTimeStep)
439 ok=false; // Is the time interval successfully solved ?
441 // Guess the next time step length
442 _dt=computeTimeStep(stop);
444 cout << "Failed computing time step "<<_nbTimeStep<<", time = " << _time <<", dt= "<<_dt<<", stopping calculation"<< endl;
445 *_runLogFile << "Failed computing time step "<<_nbTimeStep<<", time = " << _time <<", dt= "<<_dt<<", stopping calculation"<< endl;
448 // Loop on the time interval tries
449 while (!ok && !stop )
451 stop=!initTimeStep(_dt);
452 // Prepare the next time step
454 cout << "Failed initializing time step "<<_nbTimeStep<<", time = " << _time <<", dt= "<<_dt<<", stopping calculation"<< endl;
455 *_runLogFile << "Failed initializing time step "<<_nbTimeStep<<", time = " << _time <<", dt= "<<_dt<<", stopping calculation"<< endl;
458 // Solve the next time step
461 if (!ok) // The resolution failed, try with a new time interval.
464 cout<<"ComputeTimeStep returned _dt="<<_dt<<endl;
465 cout << "Failed solving time step "<<_nbTimeStep<<", time = " << _time <<" _dt= "<<_dt<<", cfl= "<<_cfl<<", trying again with dt/2"<< endl;
466 *_runLogFile << "Failed solving time step "<<_nbTimeStep<<", time = " << _time <<" _dt= "<<_dt<<", cfl= "<<_cfl<<", trying again with dt/2"<< endl;
467 double dt=_dt/2;//We chose to divide the time step by 2
468 abortTimeStep();//Cancel the initTimeStep
469 _dt=dt;//new value of time step is previous time step divided by 2 (we do not call computeTimeStep
470 //_cfl*=0.5;//If we change the cfl, we must compute the new time step with computeTimeStep
471 //_dt=computeTimeStep(stop);
474 cout << "Failed solving time step "<<_nbTimeStep<<", _time = " << _time<<" _dt= "<<_dt<<", cfl= "<<_cfl <<", stopping calculation"<< endl;
475 *_runLogFile << "Failed solving time step "<<_nbTimeStep<<", _time = " << _time<<" _dt= "<<_dt<<", cfl= "<<_cfl <<", stopping calculation"<< endl;
476 stop=true; // Impossible to solve the next time step, the Problem has given up
480 else // The resolution was successful, validate and go to the next time step.
483 if (_nbTimeStep%_freqSave ==0){
484 cout << "Time step = "<< _nbTimeStep << ", dt = "<< _dt <<", time = "<<_time << ", ||Un+1-Un||= "<<_erreur_rel<<endl;
485 *_runLogFile << "Time step = "<< _nbTimeStep << ", dt = "<< _dt <<", time = "<<_time << ", ||Un+1-Un||= "<<_erreur_rel<<endl;
491 cout << "Stationary state reached" <<endl;
492 *_runLogFile << "Stationary state reached" <<endl;
494 else if(_time>=_timeMax){
495 cout<<"Maximum time "<<_timeMax<<" reached"<<endl;
496 *_runLogFile<<"Maximum time "<<_timeMax<<" reached"<<endl;
498 else if(_nbTimeStep>=_maxNbOfTimeStep){
499 cout<<"Maximum number of time steps "<<_maxNbOfTimeStep<<" reached"<<endl;
500 *_runLogFile<<"Maximum number of time steps "<<_maxNbOfTimeStep<<" reached"<<endl;
503 cout<<"Error problem wants to stop!"<<endl;
504 *_runLogFile<<"Error problem wants to stop!"<<endl;
506 cout << "End of calculation time t= " << _time << " at time step number "<< _nbTimeStep << endl;
507 *_runLogFile << "End of calculation time t= " << _time << " at time step number "<< _nbTimeStep << endl;
509 _runLogFile->close();
513 void ProblemCoreFlows::displayMatrix(double *matrix, int size, string name)
516 for(int p=0; p<size; p++)
518 for(int q=0; q<size; q++)
520 cout << matrix[p*size+q] << "\t";
527 void ProblemCoreFlows::displayVector(double *vector, int size, string name)
530 for(int q=0; q<size; q++)
532 cout << vector[q] << "\t";
536 void ProblemCoreFlows::setFileName(string fileName){
537 if( _nbTimeStep>0 && fileName!=_fileName)//This is a change of file name during a simulation
538 _restartWithNewFileName=true;
539 _fileName = fileName;
542 void ProblemCoreFlows::setFreqSave(int freqSave){
543 _freqSave = freqSave;
546 bool ProblemCoreFlows::solveTimeStep(){
548 bool converged=false, ok=true;
549 while(!converged && ok && _NEWTON_its < _maxNewtonIts){
550 ok=iterateTimeStep(converged);//resolution du systeme lineaire si schema implicite
552 if(_timeScheme == Implicit && _nbTimeStep%_freqSave ==0)//To monitor the convergence of the newton scheme
554 cout << "\n Newton iteration " << _NEWTON_its<< ", "<< _ksptype << " iterations : " << " : " << _PetscIts<< " maximum variation ||Uk+1-Uk||: " << _erreur_rel << endl;
555 *_runLogFile<< "\n Newton iteration " << _NEWTON_its<< ", "<< _ksptype << " iterations : " << " : " << _PetscIts<< " maximum variation ||Uk+1-Uk||: " << _erreur_rel << endl;
559 PetscReal sv_max, sv_min;
560 KSPComputeExtremeSingularValues(_ksp, &sv_max, &sv_min);
561 cout<<" singular value max = " << sv_max <<" singular value min = " << sv_min <<" condition number = " << sv_max/sv_min <<endl;
562 *_runLogFile<<" singular value max = " << sv_max <<" singular value min = " << sv_min <<" condition number = " << sv_max/sv_min <<endl;
568 if(_NEWTON_its >= _maxNewtonIts){
569 cout << "Maximum number of Newton iterations "<<_maxNewtonIts<<" reached"<< endl;
570 *_runLogFile << "Maximum number of Newton iterations "<<_maxNewtonIts<<" reached"<< endl;
573 cout<<"iterateTimeStep: solving Newton iteration "<<_NEWTON_its<<" Failed"<<endl;
574 *_runLogFile<<"iterateTimeStep: solving Newton iteration "<<_NEWTON_its<<" Failed"<<endl;
577 else if(_timeScheme == Implicit && _nbTimeStep%_freqSave ==0)
580 cout << "Nombre d'iterations de Newton "<< _NEWTON_its << ", Nombre max d'iterations "<< _ksptype << " : " << _MaxIterLinearSolver << endl;
582 *_runLogFile << "Nombre d'iterations de Newton "<< _NEWTON_its << " Variation ||Un+1-Un||= "<< _erreur_rel<<endl;
583 *_runLogFile << "Nombre max d'iterations "<< _ksptype << " : " << _MaxIterLinearSolver << endl;
584 _MaxIterLinearSolver = 0;
589 ProblemCoreFlows::~ProblemCoreFlows()
592 PetscBool petscInitialized;
593 PetscInitialized(&petscInitialized);
601 ProblemCoreFlows::getConditionNumber(bool isSingular, double tol) const
603 SparseMatrixPetsc A = SparseMatrixPetsc(_A);
604 return A.getConditionNumber( isSingular, tol);
606 std::vector< double >
607 ProblemCoreFlows::getEigenvalues(int nev, EPSWhich which, double tol) const
609 SparseMatrixPetsc A = SparseMatrixPetsc(_A);
610 return A.getEigenvalues( nev, which, tol);
612 std::vector< Vector >
613 ProblemCoreFlows::getEigenvectors(int nev, EPSWhich which, double tol) const
615 SparseMatrixPetsc A = SparseMatrixPetsc(_A);
616 return A.getEigenvectors( nev, which, tol);
619 ProblemCoreFlows::getEigenvectorsField(int nev, EPSWhich which, double tol) const
621 SparseMatrixPetsc A = SparseMatrixPetsc(_A);
622 MEDCoupling::DataArrayDouble * d = A.getEigenvectorsDataArrayDouble( nev, which, tol);
626 my_eigenfield = Field("Eigenvectors field", NODES, _mesh, nev);
628 my_eigenfield = Field("Eigenvectors field", CELLS, _mesh, nev);
630 my_eigenfield.setFieldByDataArrayDouble(d);
632 return my_eigenfield;
635 std::vector< double >
636 ProblemCoreFlows::getSingularValues( int nsv, SVDWhich which, double tol) const
638 SparseMatrixPetsc A = SparseMatrixPetsc(_A);
639 return A.getSingularValues( nsv, which, tol);
641 std::vector< Vector >
642 ProblemCoreFlows::getSingularVectors(int nsv, SVDWhich which, double tol) const
644 SparseMatrixPetsc A = SparseMatrixPetsc(_A);
645 return A.getSingularVectors( nsv, which, tol);
649 ProblemCoreFlows::getUnknownField() const
651 if(!_initializedMemory)
653 _runLogFile->close();
654 throw CdmathException("ProblemCoreFlows::getUnknownField() call initialize() first");