kOmegaSSTLM.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2016-2026 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "kOmegaSSTLM.H"
27 
28 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
29 
30 namespace Foam
31 {
32 namespace RASModels
33 {
34 
35 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
36 
37 template<class BasicMomentumTransportModel>
39 (
40  const volScalarField& CDkOmega
41 ) const
42 {
43  const volScalarField Ry(this->y()*sqrt(this->k_)/this->nu());
44  const volScalarField F3(exp(-pow(Ry/120.0, 8)));
45 
47 }
48 
49 
50 template<class BasicMomentumTransportModel>
52 (
54 ) const
55 {
56  return gammaIntEff_*kOmegaSST<BasicMomentumTransportModel>::Pk(G);
57 }
58 
59 
60 template<class BasicMomentumTransportModel>
63 (
66 ) const
67 {
68  return
69  min(max(gammaIntEff_, scalar(0.1)), scalar(1))
71 }
72 
73 
74 template<class BasicMomentumTransportModel>
76 (
77  const volScalarField::Internal& Us,
78  const volScalarField::Internal& Omega,
79  const volScalarField::Internal& nu
80 ) const
81 {
82  const volScalarField::Internal& omega = this->omega_();
83  const volScalarField::Internal& y = this->y()();
84 
85  const volScalarField::Internal yBydelta
86  (
87  sqr(Us)
88  /max(375*Omega*nu*ReThetat_(), sqr(deltaU_))
89  );
90  const volScalarField::Internal ReOmega(sqr(y)*omega/nu);
91  const volScalarField::Internal Fwake(exp(-sqr(ReOmega/1e5)));
92 
94  (
95  this->groupName("Fthetat"),
96  min
97  (
98  max
99  (
100  Fwake*exp(-pow4(yBydelta)),
101  (1 - sqr((gammaInt_() - 1.0/ce2_)/(1 - 1.0/ce2_)))
102  ),
103  scalar(1)
104  )
105  );
106 }
107 
108 
109 template<class BasicMomentumTransportModel>
112 {
114  (
116  (
117  this->groupName("ReThetac"),
118  this->mesh_,
119  dimless
120  )
121  );
122  volScalarField::Internal& ReThetac = tReThetac.ref();
123 
124  forAll(ReThetac, celli)
125  {
126  const scalar ReThetat = ReThetat_[celli];
127 
128  ReThetac[celli] =
129  ReThetat <= 1870
130  ?
131  ReThetat
132  - 396.035e-2
133  + 120.656e-4*ReThetat
134  - 868.230e-6*sqr(ReThetat)
135  + 696.506e-9*pow3(ReThetat)
136  - 174.105e-12*pow4(ReThetat)
137  :
138  ReThetat - 593.11 - 0.482*(ReThetat - 1870);
139  }
140 
141  return tReThetac;
142 }
143 
144 
145 template<class BasicMomentumTransportModel>
147 (
148  const volScalarField::Internal& nu
149 ) const
150 {
152  (
154  (
155  this->groupName("Flength"),
156  this->mesh_,
157  dimless
158  )
159  );
160  volScalarField::Internal& Flength = tFlength.ref();
161 
162  const volScalarField::Internal& omega = this->omega_();
163  const volScalarField::Internal& y = this->y()();
164 
165  forAll(ReThetat_, celli)
166  {
167  const scalar ReThetat = ReThetat_[celli];
168 
169  if (ReThetat < 400)
170  {
171  Flength[celli] =
172  398.189e-1
173  - 119.270e-4*ReThetat
174  - 132.567e-6*sqr(ReThetat);
175  }
176  else if (ReThetat < 596)
177  {
178  Flength[celli] =
179  263.404
180  - 123.939e-2*ReThetat
181  + 194.548e-5*sqr(ReThetat)
182  - 101.695e-8*pow3(ReThetat);
183  }
184  else if (ReThetat < 1200)
185  {
186  Flength[celli] = 0.5 - 3e-4*(ReThetat - 596);
187  }
188  else
189  {
190  Flength[celli] = 0.3188;
191  }
192 
193  const scalar Fsublayer =
194  exp(-sqr(sqr(y[celli])*omega[celli]/(200*nu[celli])));
195 
196  Flength[celli] = Flength[celli]*(1 - Fsublayer) + 40*Fsublayer;
197  }
198 
199  return tFlength;
200 }
201 
202 
203 template<class BasicMomentumTransportModel>
206 (
207  const volScalarField::Internal& Us,
208  const volScalarField::Internal& dUsds,
209  const volScalarField::Internal& nu
210 ) const
211 {
213  (
215  (
216  this->groupName("ReThetat0"),
217  this->mesh_,
218  dimless
219  )
220  );
221  volScalarField::Internal& ReThetat0 = tReThetat0.ref();
222 
223  const volScalarField& k = this->k_;
224 
225  label maxIter = 0;
226 
227  forAll(ReThetat0, celli)
228  {
229  const scalar Tu
230  (
231  max(100*sqrt((2.0/3.0)*k[celli])/Us[celli], scalar(0.027))
232  );
233 
234  // Initialise lambda to zero.
235  // If lambda were cached between time-steps convergence would be faster
236  // starting from the previous time-step value.
237  scalar lambda = 0;
238 
239  scalar lambdaErr;
240  scalar thetat;
241  label iter = 0;
242 
243  do
244  {
245  // Previous iteration lambda for convergence test
246  const scalar lambda0 = lambda;
247 
248  if (Tu <= 1.3)
249  {
250  const scalar Flambda =
251  dUsds[celli] <= 0
252  ?
253  1
254  - (
255  - 12.986*lambda
256  - 123.66*sqr(lambda)
257  - 405.689*pow3(lambda)
258  )*exp(-pow(Tu/1.5, 1.5))
259  :
260  1
261  + 0.275*(1 - exp(-35*lambda))
262  *exp(-Tu/0.5);
263 
264  thetat =
265  (1173.51 - 589.428*Tu + 0.2196/sqr(Tu))
266  *Flambda*nu[celli]
267  /Us[celli];
268  }
269  else
270  {
271  const scalar Flambda =
272  dUsds[celli] <= 0
273  ?
274  1
275  - (
276  -12.986*lambda
277  -123.66*sqr(lambda)
278  -405.689*pow3(lambda)
279  )*exp(-pow(Tu/1.5, 1.5))
280  :
281  1
282  + 0.275*(1 - exp(-35*lambda))
283  *exp(-2*Tu);
284 
285  thetat =
286  331.50*pow((Tu - 0.5658), -0.671)
287  *Flambda*nu[celli]/Us[celli];
288  }
289 
290  lambda = sqr(thetat)/nu[celli]*dUsds[celli];
291  lambda = max(min(lambda, 0.1), -0.1);
292 
293  lambdaErr = mag(lambda - lambda0);
294 
295  maxIter = max(maxIter, ++iter);
296 
297  } while (lambdaErr > lambdaErr_);
298 
299  ReThetat0[celli] = max(thetat*Us[celli]/nu[celli], scalar(20));
300  }
301 
302  if (maxIter > maxLambdaIter_)
303  {
305  << "Number of lambda iterations exceeds maxLambdaIter("
306  << maxLambdaIter_ << ')'<< endl;
307  }
308 
309  return tReThetat0;
310 }
311 
312 
313 template<class BasicMomentumTransportModel>
315 (
316  const volScalarField::Internal& Rev,
317  const volScalarField::Internal& ReThetac,
318  const volScalarField::Internal& RT
319 ) const
320 {
321  const volScalarField::Internal Fonset1(Rev/(2.193*ReThetac));
322 
323  const volScalarField::Internal Fonset2
324  (
325  min(max(Fonset1, pow4(Fonset1)), scalar(2))
326  );
327 
328  const volScalarField::Internal Fonset3(max(1 - pow3(RT/2.5), scalar(0)));
329 
331  (
332  this->groupName("Fonset"),
333  max(Fonset2 - Fonset3, scalar(0))
334  );
335 }
336 
337 
338 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
339 
340 template<class BasicMomentumTransportModel>
342 (
343  const alphaField& alpha,
344  const rhoField& rho,
345  const volVectorField& U,
346  const surfaceScalarField& alphaRhoPhi,
347  const surfaceScalarField& phi,
348  const viscosity& viscosity,
349  const word& type
350 )
351 :
352  kOmegaSST<BasicMomentumTransportModel>
353  (
354  alpha,
355  rho,
356  U,
357  alphaRhoPhi,
358  phi,
359  viscosity
360  ),
361 
362  ca1_("ca1", this->typeDict(type), 2),
363  ca2_("ca2", this->typeDict(type), 0.06),
364  ce1_("ce1", this->typeDict(type), 1),
365  ce2_("ce2", this->typeDict(type), 50),
366  cThetat_("cThetat", this->typeDict(type), 0.03),
367  sigmaThetat_("sigmaThetat", this->typeDict(type), 2),
368  lambdaErr_(this->typeDict(type).lookupOrDefault("lambdaErr", 1e-6)),
369  maxLambdaIter_(this->typeDict(type).lookupOrDefault("maxLambdaIter", 10)),
370  deltaU_("deltaU", dimVelocity, small),
371 
372  ReThetat_
373  (
374  IOobject
375  (
376  this->groupName("ReThetat"),
377  this->runTime_.name(),
378  this->mesh_,
379  IOobject::MUST_READ,
380  IOobject::AUTO_WRITE
381  ),
382  this->mesh_
383  ),
384 
385  gammaInt_
386  (
387  IOobject
388  (
389  this->groupName("gammaInt"),
390  this->runTime_.name(),
391  this->mesh_,
392  IOobject::MUST_READ,
393  IOobject::AUTO_WRITE
394  ),
395  this->mesh_
396  ),
397 
398  gammaIntEff_
399  (
400  IOobject
401  (
402  this->groupName("gammaIntEff"),
403  this->runTime_.name(),
404  this->mesh_
405  ),
406  this->mesh_,
408  )
409 {}
410 
411 
412 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
413 
414 template<class BasicMomentumTransportModel>
416 {
418  {
419  ca1_.readIfPresent(this->typeDict());
420  ca2_.readIfPresent(this->typeDict());
421  ce1_.readIfPresent(this->typeDict());
422  ce2_.readIfPresent(this->typeDict());
423  sigmaThetat_.readIfPresent(this->typeDict());
424  cThetat_.readIfPresent(this->typeDict());
425  this->typeDict().readIfPresent("lambdaErr", lambdaErr_);
426  this->typeDict().readIfPresent("maxLambdaIter", maxLambdaIter_);
427 
428  return true;
429  }
430  else
431  {
432  return false;
433  }
434 }
435 
436 
437 template<class BasicMomentumTransportModel>
439 {
440  // Local references
441  const alphaField& alpha = this->alpha_;
442  const rhoField& rho = this->rho_;
443  const surfaceScalarField& alphaRhoPhi = this->alphaRhoPhi_;
444  const volVectorField& U = this->U_;
445  const volScalarField& k = this->k_;
446  const volScalarField& omega = this->omega_;
447  const tmp<volScalarField> tnu = this->nu();
448  const volScalarField::Internal& nu = tnu()();
449  const volScalarField::Internal& y = this->y()();
450  const Foam::fvModels& fvModels(Foam::fvModels::New(this->mesh_));
452  (
453  Foam::fvConstraints::New(this->mesh_)
454  );
455 
456  // Fields derived from the velocity gradient
457  tmp<volTensorField> tgradU = fvc::grad(U);
458  const volScalarField::Internal Omega(sqrt(2*magSqr(skew(tgradU()()))));
459  const volScalarField::Internal S(sqrt(2*magSqr(symm(tgradU()()))));
460  const volScalarField::Internal Us(max(mag(U()), deltaU_));
461  const volScalarField::Internal dUsds((U() & (U() & tgradU()()))/sqr(Us));
462  tgradU.clear();
463 
464  const volScalarField::Internal Fthetat(this->Fthetat(Us, Omega, nu));
465 
466  {
467  const volScalarField::Internal t(500*nu/sqr(Us));
468  const volScalarField::Internal Pthetat
469  (
470  alpha()*rho()*(cThetat_/t)*(1 - Fthetat)
471  );
472 
473  // Transition onset momentum-thickness Reynolds number equation
474  tmp<fvScalarMatrix> ReThetatEqn
475  (
476  fvm::ddt(alpha, rho, ReThetat_)
477  + fvm::div(alphaRhoPhi, ReThetat_)
478  - fvm::laplacian(alpha*rho*DReThetatEff(), ReThetat_)
479  ==
480  Pthetat*ReThetat0(Us, dUsds, nu) - fvm::Sp(Pthetat, ReThetat_)
481  + fvModels.source(alpha, rho, ReThetat_)
482  );
483 
484  ReThetatEqn.ref().relax();
485  fvConstraints.constrain(ReThetatEqn.ref());
486  solve(ReThetatEqn);
487  fvConstraints.constrain(ReThetat_);
488  bound(ReThetat_, 0);
489  }
490 
491  const volScalarField::Internal ReThetac(this->ReThetac());
492  const volScalarField::Internal Rev(sqr(y)*S/nu);
493  const volScalarField::Internal RT(k()/(nu*omega()));
494 
495  {
496  const volScalarField::Internal Pgamma
497  (
498  alpha()*rho()
499  *ca1_*Flength(nu)*S*sqrt(gammaInt_()*Fonset(Rev, ReThetac, RT))
500  );
501 
502  const volScalarField::Internal Fturb(exp(-pow4(0.25*RT)));
503 
504  const volScalarField::Internal Egamma
505  (
506  alpha()*rho()*ca2_*Omega*Fturb*gammaInt_()
507  );
508 
509  // Intermittency equation
510  tmp<fvScalarMatrix> gammaIntEqn
511  (
512  fvm::ddt(alpha, rho, gammaInt_)
513  + fvm::div(alphaRhoPhi, gammaInt_)
514  - fvm::laplacian(alpha*rho*DgammaIntEff(), gammaInt_)
515  ==
516  Pgamma - fvm::Sp(ce1_*Pgamma, gammaInt_)
517  + Egamma - fvm::Sp(ce2_*Egamma, gammaInt_)
518  + fvModels.source(alpha, rho, gammaInt_)
519  );
520 
521  gammaIntEqn.ref().relax();
522  fvConstraints.constrain(gammaIntEqn.ref());
523  solve(gammaIntEqn);
524  fvConstraints.constrain(gammaInt_);
525  bound(gammaInt_, 0);
526  }
527 
528  const volScalarField::Internal Freattach(exp(-pow4(RT/20.0)));
529  const volScalarField::Internal gammaSep
530  (
531  min(2*max(Rev/(3.235*ReThetac) - 1, scalar(0))*Freattach, scalar(2))
532  *Fthetat
533  );
534 
535  gammaIntEff_ = max(gammaInt_(), gammaSep);
536 }
537 
538 
539 template<class BasicMomentumTransportModel>
541 {
542  if (!this->turbulence_)
543  {
544  return;
545  }
546 
547  // Correct ReThetat and gammaInt
548  correctReThetatGammaInt();
549 
550  // Correct k and omega
552 }
553 
554 
555 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
556 
557 } // End namespace RASModels
558 } // End namespace Foam
559 
560 // ************************************************************************* //
scalar y
label k
#define F2(B, C, D)
Definition: SHA1.C:174
#define F1(B, C, D)
Definition: SHA1.C:173
#define F3(B, C, D)
Definition: SHA1.C:175
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:449
static fvModels & New(const word &name, const fvMesh &mesh)
Construct and return the named DemandDrivenMeshObject.
Field with dimensions and associated with geometry type GeoMesh which is used to size the field and a...
static tmp< DimensionedField< Type, GeoMesh, PrimitiveField > > New(const word &name, const GeoMesh &mesh, const dimensionSet &, const PrimitiveField< Type > &)
Return a temporary field constructed from name, mesh,.
Generic GeometricField class.
IOobject defines the attributes of an object for which implicit objectRegistry management is supporte...
Definition: IOobject.H:99
tmp< volScalarField::Internal > Flength(const volScalarField::Internal &nu) const
Empirical correlation that controls the length of the.
Definition: kOmegaSSTLM.C:147
virtual tmp< volScalarField > F1(const volScalarField &CDkOmega) const
Modified form of the k-omega SST F1 function.
Definition: kOmegaSSTLM.C:39
virtual void correct()
Solve the turbulence equations and correct the turbulence viscosity.
Definition: kOmegaSSTLM.C:540
virtual tmp< volScalarField::Internal > epsilonByk(const volScalarField::Internal &F1, const volScalarField::Internal &F2) const
Modified form of the k-omega SST epsilon/k.
Definition: kOmegaSSTLM.C:63
tmp< volScalarField::Internal > Fthetat(const volScalarField::Internal &Us, const volScalarField::Internal &Omega, const volScalarField::Internal &nu) const
Freestream blending-function.
Definition: kOmegaSSTLM.C:76
kOmegaSSTLM(const alphaField &alpha, const rhoField &rho, const volVectorField &U, const surfaceScalarField &alphaRhoPhi, const surfaceScalarField &phi, const viscosity &viscosity, const word &type=typeName)
Construct from components.
Definition: kOmegaSSTLM.C:342
void correctReThetatGammaInt()
Solve the turbulence equations and correct the turbulence viscosity.
Definition: kOmegaSSTLM.C:438
tmp< volScalarField::Internal > ReThetac() const
Empirical correlation for critical Reynolds number where the.
Definition: kOmegaSSTLM.C:111
virtual tmp< volScalarField::Internal > Pk(const volScalarField::Internal &G) const
Modified form of the k-omega SST k production rate.
Definition: kOmegaSSTLM.C:52
tmp< volScalarField::Internal > Fonset(const volScalarField::Internal &Rev, const volScalarField::Internal &ReThetac, const volScalarField::Internal &RT) const
Transition onset location control function.
Definition: kOmegaSSTLM.C:315
tmp< volScalarField::Internal > ReThetat0(const volScalarField::Internal &Us, const volScalarField::Internal &dUsds, const volScalarField::Internal &nu) const
Return the transition onset momentum-thickness Reynolds number.
Definition: kOmegaSSTLM.C:206
virtual bool read()
Re-read model coefficients if they have changed.
Definition: kOmegaSSTLM.C:415
Specialisation for RAS of the generic kOmegaSSTBase base class. For more information,...
Definition: kOmegaSST.H:64
Finite volume constraints.
Definition: fvConstraints.H:68
bool constrain(fvMatrix< Type > &eqn) const
Apply constraints to an equation.
Finite volume models.
Definition: fvModels.H:69
tmp< fvMatrix< Type > > source(const VolField< Type > &field) const
Return source for an equation.
virtual void correct()
Solve the turbulence equations and correct the turbulence viscosity.
virtual tmp< volScalarField::Internal > epsilonByk(const volScalarField::Internal &F1, const volScalarField::Internal &F2) const
Return epsilon/k which for standard RAS is betaStar*omega.
virtual tmp< volScalarField::Internal > Pk(const volScalarField::Internal &G) const
Return k production rate.
BasicMomentumTransportModel::alphaField alphaField
BasicMomentumTransportModel::rhoField rhoField
Convenience class to handle the input of constant rotational speed. Reads an omega entry with default...
Definition: omega.H:54
A class for managing temporary objects.
Definition: tmp.H:55
void clear() const
If object pointer points to valid object:
Definition: tmpI.H:253
T & ref() const
Return non-const reference or generate a fatal error.
Definition: tmpI.H:197
Abstract base class for all fluid physical properties.
Definition: viscosity.H:50
A class for handling words, derived from string.
Definition: word.H:63
Foam::fvConstraints & fvConstraints(Foam::fvConstraints::New(mesh))
Foam::fvModels & fvModels(Foam::fvModels::New(mesh))
const scalar omega
U
Definition: pEqn.H:72
rho
Definition: pEqn.H:1
dimensionedScalar lambda(viscosity->lookup("lambda"))
volScalarField alpha(IOobject("alpha", runTime.name(), mesh, IOobject::READ_IF_PRESENT, IOobject::AUTO_WRITE), lambda *max(Ua &U, zeroSensitivity))
#define WarningInFunction
Report a warning using Foam::Warning.
const dimensionedScalar G
Newtonian constant of gravitation.
tmp< VolField< typename outerProduct< vector, Type >::type > > grad(const SurfaceField< Type > &ssf)
Definition: fvcGrad.C:46
tmp< fvMatrix< Type > > S(const Pair< tmp< volScalarField::Internal >> &, const VolField< Type > &)
tmp< fvMatrix< Type > > laplacian(const VolField< Type > &vf, const word &name)
Definition: fvmLaplacian.C:47
tmp< fvMatrix< Type > > div(const surfaceScalarField &flux, const VolField< Type > &vf, const word &name)
Definition: fvmDiv.C:48
tmp< fvMatrix< Type > > Sp(const volScalarField::Internal &, const VolField< Type > &)
tmp< fvMatrix< Type > > ddt(const VolField< Type > &vf)
Definition: fvmDdt.C:46
Namespace for OpenFOAM.
void skew(pointPatchField< tensor > &, const pointPatchField< tensor > &)
const doubleScalar e
Definition: doubleScalar.H:106
dimensionedScalar exp(const dimensionedScalar &ds)
const dimensionSet & dimless
Definition: dimensions.C:138
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:288
void pow4(LagrangianPatchField< scalar > &f, const LagrangianPatchField< scalar > &f1)
tensor Ry(const scalar &omega)
Rotational transformation tensor about the y-axis by omega radians.
Definition: transform.H:106
tmp< DimensionedField< typename outerProduct< Type, Type >::type, GeoMesh, Field >> sqr(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
const dimensionSet & dimVelocity
Definition: dimensions.C:154
dimensioned< Type > min(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
void symm(pointPatchField< tensor > &, const pointPatchField< tensor > &)
bool bound(volScalarField &, const dimensionedScalar &min)
Bound the given scalar field where it is below the specified min value.
Definition: bound.C:31
void pow3(LagrangianPatchField< scalar > &f, const LagrangianPatchField< scalar > &f1)
word name(const LagrangianState state)
Return a string representation of a Lagrangian state enumeration.
tmp< DimensionedField< typename powProduct< Type, r >::type, GeoMesh, Field > > pow(const DimensionedField< Type, GeoMesh, PrimitiveField > &df, typename powProduct< Type, r >::type)
tmp< DimensionedField< scalar, GeoMesh, Field > > mag(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
void sqrt(LagrangianPatchField< scalar > &f, const LagrangianPatchField< scalar > &f1)
tmp< DimensionedField< scalar, GeoMesh, Field > > magSqr(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
dimensioned< Type > max(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
fileType type(const fileName &, const bool checkVariants=true, const bool followLink=true)
Return the file type: directory or file.
Definition: POSIX.C:488
SolverPerformance< Type > solve(fvMatrix< Type > &, const word &)
Solve returning the solution statistics given convergence tolerance.