Commit 03fc9e35 authored by Robert Caulk's avatar Robert Caulk Committed by Janek Kozicki

Add ThermalEngine features such as cavity model, parallelization, heat...

Add ThermalEngine features such as cavity model, parallelization, heat transfer coefficient based on RE, fluid conduction, air compressibility etc.
parent b6543e6d
......@@ -82,6 +82,7 @@ class State: public Serializable, public Indexable{
((int,boundaryId,-1,,"identifies if a particle is associated with constant temperature thrermal boundary condition"))
((Real,stabilityCoefficient,0,,"sum of solid and fluid thermal resistivities for use in automatic timestep estimation"))
((Real,delRadius,0,,"radius change due to thermal expansion"))
((bool,isCavity,true,,"flag used for unbounding cavity bodies"))
#endif
,
/* additional initializers */
......
......@@ -101,7 +101,9 @@ modulus = 1000./abs(e22)
flow.dead=0
flow.defTolerance=0.3
flow.meshUpdateInterval=200
flow.useSolver=3
flow.fluidBulkModulus=2.2e9
flow.useSolver=4
flow.desiredPorosity=0
flow.permeabilityFactor=1
flow.viscosity=10
flow.bndCondIsPressure=[0,0,1,1,0,0]
......
......@@ -27,7 +27,7 @@ from yade import pack
# The following 5 lines will be used later for batch execution
nRead=readParamsFromTable(
num_spheres=1000,# number of spheres
num_spheres=10000,# number of spheres
compFricDegree = 30, # contact friction during the confining phase
key='_triax_base_', # put you simulation's name here
unknownOk=True
......@@ -127,16 +127,16 @@ if nRead==0: yade.qt.Controller(), yade.qt.View()
#the value of (isotropic) confining stress defines the target stress to be applied in all three directions
triax.goal1=triax.goal2=triax.goal3=-10000
#while 1:
#O.run(1000, True)
##the global unbalanced force on dynamic bodies, thus excluding boundaries, which are not at equilibrium
#unb=unbalancedForce()
#print 'unbalanced force:',unb,' mean stress: ',triax.meanStress
#if unb<stabilityThreshold and abs(-10000-triax.meanStress)/10000<0.001:
#break
while 1:
O.run(1000, True)
#the global unbalanced force on dynamic bodies, thus excluding boundaries, which are not at equilibrium
unb=unbalancedForce()
print 'unbalanced force:',unb,' mean stress: ',triax.meanStress
if unb<stabilityThreshold and abs(-10000-triax.meanStress)/10000<0.001:
break
#O.save('confinedState'+key+'.yade.gz')
#print "### Isotropic state saved ###"
O.save('confinedState'+key+'.yade.gz')
print "### Isotropic state saved ###"
###################################################
### REACHING A SPECIFIED POROSITY PRECISELY ###
......@@ -146,20 +146,20 @@ triax.goal1=triax.goal2=triax.goal3=-10000
### (see http://dx.doi.org/10.2516/ogst/2012032 and
### http://www.geosyntheticssociety.org/Resources/Archive/GI/src/V9I2/GI-V9-N2-Paper1.pdf)
#import sys #this is only for the flush() below
#while triax.porosity>targetPorosity:
## we decrease friction value and apply it to all the bodies and contacts
#compFricDegree = 0.95*compFricDegree
#setContactFriction(radians(compFricDegree))
#print "\r Friction: ",compFricDegree," porosity:",triax.porosity,
#sys.stdout.flush()
## while we run steps, triax will tend to grow particles as the packing
## keeps shrinking as a consequence of decreasing friction. Consequently
## porosity will decrease
#O.run(500,1)
#O.save('compactedState'+key+'.yade.gz')
#print "### Compacted state saved ###"
import sys #this is only for the flush() below
while triax.porosity>targetPorosity:
# we decrease friction value and apply it to all the bodies and contacts
compFricDegree = 0.95*compFricDegree
setContactFriction(radians(compFricDegree))
print "\r Friction: ",compFricDegree," porosity:",triax.porosity,
sys.stdout.flush()
# while we run steps, triax will tend to grow particles as the packing
# keeps shrinking as a consequence of decreasing friction. Consequently
# porosity will decrease
O.run(500,1)
O.save('compactedState'+key+'.yade.gz')
print "### Compacted state saved ###"
##############################
### DEVIATORIC LOADING ###
......
......@@ -48,6 +48,10 @@ class FlowBoundingSphere : public Network<_Tesselation>
bool factorizeOnly;
bool getCHOLMODPerfTimings;
bool reuseOrdering;
bool controlCavityPressure;
bool controlCavityVolumeChange;
bool averageCavityPressure;
double cavityDV;
bool thermalEngine;
double fluidRho;
......@@ -59,6 +63,8 @@ class FlowBoundingSphere : public Network<_Tesselation>
vector<CellHandle> IPCells;
vector<pair<Point,Real> > imposedF;
vector<CellHandle> IFCells;
vector<Point> imposedCavity;
vector<CellHandle> cavityCells;
//Blocked cells, where pressure may be computed in undrained condition
vector<CellHandle> blockedCells;
//Pointers to vectors used for user defined boundary pressure
......@@ -110,6 +116,8 @@ class FlowBoundingSphere : public Network<_Tesselation>
virtual void resetRHS() {};////reset only B in the linear system A*P=B, done typically after changing values of imposed pressures
double kFactor; //permeability moltiplicator
double cavityFactor; // permeability factor for cavity cell neighbors
bool tempDependentViscosity;
std::string key; //to give to consolidation files a name with iteration number
// std::vector<double> pressures; //for automatic write maximum pressures during consolidation
bool tessBasedForce; //allow the force computation method to be chosen from FlowEngine
......@@ -117,6 +125,11 @@ class FlowBoundingSphere : public Network<_Tesselation>
double viscosity;
double fluidBulkModulus;
double equivalentCompressibility;
double netCavityFlux;
double phiZero;
double cavityFlux;
double cavityFluidDensity;
bool multithread;
void displayStatistics();
......@@ -177,8 +190,12 @@ class FlowBoundingSphere : public Network<_Tesselation>
double averagePressure();
int getCell (double X,double Y,double Z);
double boundaryFlux(unsigned int boundaryId);
double boundaryArea(unsigned int boundaryId);
void setBlocked(CellHandle& cell);
void adjustCavityPressure(double dt, int stepsSinceLastMesh, double pZero);
void adjustCavityVolumeChange(double dt, int stepsSinceLastMesh, double pZero);
void adjustCavityCompressibility(double pZero);
double getCavityFlux();
vector<Real> averageFluidVelocityOnSphere(unsigned int Id_sph);
//Solver?
int useSolver;//(0 : GaussSeidel, 1:CHOLMOD)
......
This diff is collapsed.
......@@ -52,7 +52,9 @@ public:
using FlowType::tolerance;
using FlowType::relax;
using FlowType::fluidBulkModulus;
using FlowType::equivalentCompressibility;
using FlowType::reApplyBoundaryConditions;
using FlowType::phiZero;
using FlowType::pressureChanged;
using FlowType::computedOnce;
using FlowType::resetNetwork;
......@@ -66,6 +68,9 @@ public:
using FlowType::fluidRho;
using FlowType::fluidCp;
using FlowType::thermalEngine;
using FlowType::controlCavityPressure;
using FlowType::controlCavityVolumeChange;
using FlowType::cavityDV;
//! TAUCS DECs
vector<FiniteCellsIterator> orderedCells;
......
......@@ -250,7 +250,10 @@ int FlowBoundingSphereLinSolv<_Tesselation,FlowType>::setLinearSystem(Real dt)
vs[T_nnz]=0;
for (int j=0;j<4;j++) if (!cell->neighbor(j)->info().blocked) vs[T_nnz]+= (cell->info().kNorm())[j];
// vs[T_nnz] = (cell->info().kNorm())[0]+ (cell->info().kNorm())[1]+ (cell->info().kNorm())[2]+ (cell->info().kNorm())[3];
if (fluidBulkModulus>0) vs[T_nnz] += (1.f/(dt*fluidBulkModulus*cell->info().invVoidVolume()));
if (fluidBulkModulus>0) {
if (cell->info().isCavity && phiZero>0) vs[T_nnz] += (1.f * equivalentCompressibility/(dt*cell->info().invVoidVolume())); else
vs[T_nnz] += (1.f/(dt*fluidBulkModulus*cell->info().invVoidVolume()));
}
++T_nnz;
}
for (int j=0; j<4; j++) {
......@@ -374,10 +377,36 @@ void FlowBoundingSphereLinSolv<_Tesselation,FlowType>::copyLinToCells() {
template<class _Tesselation, class FlowType>
void FlowBoundingSphereLinSolv<_Tesselation,FlowType>::copyCellsToLin (Real dt)
{
for (int ii=1; ii<=ncols; ii++) {
// trunk
/* for (int ii=1; ii<=ncols; ii++) {*/
/* T_bv[ii-1]=T_b[ii-1]-T_cells[ii]->info().dv();*/
/* if (fluidBulkModulus>0) T_bv[ii-1] += T_cells[ii]->info().p()/(fluidBulkModulus*dt*T_cells[ii]->info().invVoidVolume());*/
/* }*/
// update T_b for cells abutting Pconditions since our Pcondition value might want to change sub remesh
#pragma omp parallel for
for (int ii=1;ii<=ncols;ii++){
if (controlCavityPressure){
T_b[ii-1]=0;
for (int j=0; j<4; j++) {
CellHandle neighborCell = T_cells[ii]->neighbor(j);
if (neighborCell->info().Pcondition && !neighborCell->info().blocked) {
T_b[ii-1]+=T_cells[ii]->info().kNorm()[j]*(neighborCell->info().p());
}
}
}
T_bv[ii-1]=T_b[ii-1]-T_cells[ii]->info().dv();
if (fluidBulkModulus>0) T_bv[ii-1] += T_cells[ii]->info().p()/(fluidBulkModulus*dt*T_cells[ii]->info().invVoidVolume());}
if (fluidBulkModulus>0) {
if (phiZero>0 && T_cells[ii]->info().isCavity){ // consider air compressibility in cavity
T_bv[ii-1] += T_cells[ii]->info().p()*equivalentCompressibility/(dt*T_cells[ii]->info().invVoidVolume());
if (controlCavityVolumeChange) T_bv[ii-1] += cavityDV;
} else { // use normal bulkmodulus
T_bv[ii-1] += T_cells[ii]->info().p()/(fluidBulkModulus*dt*T_cells[ii]->info().invVoidVolume());
}
}
}
}
/// For Gauss Seidel, we need the full matrix
......@@ -670,10 +699,13 @@ int FlowBoundingSphereLinSolv<_Tesselation,FlowType>::cholmodSolve(Real dt)
template<class _Tesselation, class FlowType>
void FlowBoundingSphereLinSolv<_Tesselation,FlowType>::initializeInternalEnergy() {
RTriangulation& Tri = T[currentTes].Triangulation();
FiniteCellsIterator cellEnd = Tri.finite_cells_end();
for (FiniteCellsIterator cell = Tri.finite_cells_begin(); cell != cellEnd; cell++){
if (!cell->info().isGhost) cell->info().internalEnergy = fluidCp*fluidRho*cell->info().temp()*(1./cell->info().invVoidVolume());
Tesselation& Tes = T[currentTes];
const long sizeCells = Tes.cellHandles.size();
#pragma omp parallel for
for (long i=0; i<sizeCells; i++){
CellHandle& cell = Tes.cellHandles[i];
if (!cell->info().isFictious && !cell->info().blocked && !cell->info().isCavity) cell->info().internalEnergy = fluidCp*fluidRho*cell->info().temp()*(1./cell->info().invVoidVolume());
if (cell->info().isCavity) cell->info().internalEnergy = fluidCp*fluidRho*cell->info().temp()*(cell->info().volume()); // ignore particles used for fluid discr. in cavity (i.e. use volume())
}
}
......@@ -684,10 +716,30 @@ void FlowBoundingSphereLinSolv<_Tesselation,FlowType>::augmentConductivityMatrix
Real energyFlux; Real upwindTemp; Real facetFlowRate;
RTriangulation& Tri = T[currentTes].Triangulation();
// cycle through facets instead of cells to avoid duplicate math
/* Tesselation& Tes = T[currentTes];*/
/* const long sizeFacets = Tes.facetHandles.size();*/
/* #pragma omp parallel for*/
/* for (long i=0; i<sizeFacets; i++){*/
/* Facet& facet = Tes.facetHandles[i];*/
/* const CellHandle& cell = facet->first;*/
/* const CellHandle& neighborCell = facet->first->neighbor(facet->second);*/
/* facetFlowRate = cell->info().kNorm()[facet->second] * (cell->info().p() - cell->neighbor(facet->second)->info().p());*/
/* if (facetFlowRate>0){*/
/* upwindTemp = cell->info().temp();*/
/* } else { */
/* upwindTemp = neighborCell->info().temp();*/
/* }*/
/* energyFlux = fluidCp*fluidRho*dt*upwindTemp*facetFlowRate;*/
/* if (!cell->info().Tcondition && !cell->info().isFictious && !cell->info().blocked) cell->info().internalEnergy -= energyFlux;*/
/* if (!neighborCell->info().Tcondition && !neighborCell->info().isFictious && !neighborCell->info().blocked) neighborCell->info().internalEnergy += energyFlux;*/
/* }*/
for (FiniteFacetsIterator f_it=Tri.finite_facets_begin(); f_it != Tri.finite_facets_end();f_it++){
const CellHandle& cell = f_it->first;
const CellHandle& neighborCell = f_it->first->neighbor(f_it->second);
if (cell->info().isGhost || neighborCell->info().isGhost) continue;
if (cell->info().blocked || neighborCell->info().blocked || (cell->info().Pcondition && neighborCell->info().Pcondition)) continue;
facetFlowRate = cell->info().kNorm()[f_it->second] * (cell->info().p() - cell->neighbor(f_it->second)->info().p());
if (facetFlowRate>0){
upwindTemp = cell->info().temp();
......@@ -695,24 +747,52 @@ void FlowBoundingSphereLinSolv<_Tesselation,FlowType>::augmentConductivityMatrix
upwindTemp = neighborCell->info().temp();
}
energyFlux = fluidCp*fluidRho*dt*upwindTemp*facetFlowRate;
if (!cell->info().Tcondition) cell->info().internalEnergy -= energyFlux;
if (!neighborCell->info().Tcondition) neighborCell->info().internalEnergy += energyFlux;
if (!cell->info().Tcondition && !cell->info().isFictious) cell->info().internalEnergy -= energyFlux;
if (!neighborCell->info().Tcondition && !neighborCell->info().isFictious) neighborCell->info().internalEnergy += energyFlux;
}
}
template<class _Tesselation, class FlowType>
void FlowBoundingSphereLinSolv<_Tesselation,FlowType>::setNewCellTemps()
{
RTriangulation& Tri = T[currentTes].Triangulation();
FiniteCellsIterator cellEnd = Tri.finite_cells_end();
for (FiniteCellsIterator cell = Tri.finite_cells_begin(); cell != cellEnd; cell++) {
if (!cell->info().Tcondition && !cell->info().isGhost) {
Tesselation& Tes = T[currentTes];
const long sizeCells = Tes.cellHandles.size();
double cavityInternalEnergy = 0;
double cavityVolume = 0;
#pragma omp parallel for
for (long i=0; i<sizeCells; i++){
CellHandle& cell = Tes.cellHandles[i];
if (!cell->info().isFictious && !cell->info().blocked) {
Real oldTemp = cell->info().temp();
cell->info().temp()=cell->info().internalEnergy/((1./cell->info().invVoidVolume())*fluidCp*fluidRho); //FIXME: invVoidVolume depends on volumeSolidPore() which uses CGAL points only updated each remesh. We need our own volumeSolidPore().
//cell->info().temp()=cell->info().internalEnergy/(cell->info().volume()*fluidCp*fluidRho);
if (!cell->info().isCavity){
cell->info().temp()=cell->info().internalEnergy/((1./cell->info().invVoidVolume())*fluidCp*fluidRho); //FIXME: invVoidVolume depends on volumeSolidPore() which uses CGAL points only updated each remesh. We might need our own volumeSolidPore().
} else {
cell->info().temp()=cell->info().internalEnergy/((cell->info().volume())*fluidCp*fluidRho);
}
cell->info().dtemp() = cell->info().temp() - oldTemp;
}
if (controlCavityPressure && cell->info().isCavity && !cell->info().blocked) {
cavityInternalEnergy += cell->info().internalEnergy;
cavityVolume += 1./cell->info().invVoidVolume();
}
}
double cavityTemp;
if (controlCavityPressure) {
cavityTemp = cavityInternalEnergy/(cavityVolume*fluidCp*fluidRho); //use cavityFluidDensity?
#pragma omp parallel for
for (long i=0; i<sizeCells; i++){
CellHandle& cell = Tes.cellHandles[i];
if (!cell->info().isCavity) continue;
Real oldTemp = cell->info().temp();
cell->info().temp()=cavityTemp;
cell->info().dtemp() = cell->info().temp() - oldTemp;
}
}
}
template<class _Tesselation, class FlowType>
......
......@@ -143,7 +143,6 @@ typedef typename RTriangulation::Cell_iterator CellIterator;
typedef typename RTriangulation::Finite_cells_iterator FiniteCellsIterator;
typedef typename RTriangulation::Cell_circulator CellCirculator;
typedef typename RTriangulation::Cell_handle CellHandle;
typedef typename RTriangulation::Facet Facet;
typedef typename RTriangulation::Facet_iterator FacetIterator;
typedef typename RTriangulation::Facet_circulator FacetCirculator;
......
......@@ -97,6 +97,7 @@ public:
typedef std::vector<VertexHandle> VectorVertex;
typedef std::vector<CellHandle> VectorCell;
typedef std::vector<std::pair<CellHandle,int>> VectorFacetPair;
typedef std::list<Point> ListPoint;
typedef typename VectorCell::iterator VCellIterator;
int maxId;
......@@ -112,6 +113,7 @@ public:
Real TotalInternalVoronoiPorosity;
VectorVertex vertexHandles;//This is a redirection vector to get vertex pointers by spheres id
VectorCell cellHandles;//for speedup of global loops, iterating on this vector is faster than cellIterator++
VectorFacetPair facetCells; //for speedup on global loops (can be parallelized)
bool redirected;//is vertexHandles filled with current vertex pointers?
bool computed;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -33,8 +33,10 @@ class ThermalEngine : public PartialEngine
typedef FlowEngineT::Tesselation Tesselation;
typedef FlowEngineT::RTriangulation RTriangulation;
typedef FlowEngineT::FiniteCellsIterator FiniteCellsIterator;
typedef RTriangulation::Finite_facets_iterator FiniteFacetsIterator;
typedef FlowEngineT::CellHandle CellHandle;
typedef FlowEngineT::VertexHandle VertexHandle;
typedef FlowEngineT::Facet Facet;
typedef std::vector<CellHandle> VectorCell;
typedef typename VectorCell::iterator VCellIterator;
......@@ -51,10 +53,18 @@ class ThermalEngine : public PartialEngine
bool first;
bool runConduction;
Real maxTimeStep;
Real Pr;
Real Nu;
Real NutimesFluidK;
double cavitySolidVolumeChange;
double cavityVolume;
double cavityDtemp;
virtual ~ThermalEngine();
virtual void action();
void setInitialValues();
void applyTempDeltaToSolids(Real delT);
void resetFlowBoundaryTemps();
void resetBoundaryFluxSums();
void setConductionBoundary();
void thermalExpansion();
......@@ -62,40 +72,62 @@ class ThermalEngine : public PartialEngine
void computeNewPoreTemperatures();
void computeNewParticleTemperatures();
void computeSolidFluidFluxes();
void computeFluidFluidConduction();
void updateForces();
void computeVertexSphericalArea();
void computeFlux(CellHandle& cell, const shared_ptr<Body>& b, const double surfaceArea);
void computeSolidSolidFluxes();
void timeStepEstimate();
const Real computeCellPressureChangeFromDeltaTemp(CellHandle& cell);
const Real computeCellPressureChangeFromDeltaVolume(CellHandle& cell);
CVector cellBarycenter(const CellHandle& cell);
void computeCellVolumeChangeFromDeltaTemp(CellHandle& cell,double cavDens);
void accountForCavitySolidVolumeChange();
void accountForCavityThermalVolumeChange();
void unboundCavityParticles();
void computeCellVolumeChangeFromSolidVolumeChange(CellHandle& cell);
Real getThermalDT() {return thermalDT;}
int getConductionIterPeriod() {return conductionIterPeriod;}
Real getMaxTimeStep() {return maxTimeStep;}
YADE_CLASS_BASE_DOC_ATTRS_INIT_CTOR_PY(ThermalEngine,PartialEngine,"preliminary",
/*attributes*/
((bool,advection,true,,"Activates advection"))
((bool,fluidConduction,true,,"Activates conduction within fluid"))
((bool,debug,false,,"debugging flags"))
((bool,conduction,true,,"Activates conduction"))
((bool,thermoMech,true,,"Activates thermoMech"))
((bool,fluidThermoMech,true,,"Activates thermoMech"))
((bool,solidThermoMech,true,,"Activates thermoMech"))
((bool,ignoreFictiousConduction,false,,"Allows user to ignore conduction between fictious cells and particles. Mainly for debugging purposes."))
((vector<bool>, bndCondIsTemperature, vector<bool>(6,false),,"defines the type of boundary condition for each side. True if temperature is imposed, False for no heat-flux. Indices can be retrieved with :yref:`FlowEngine::xmin` and friends."))
((vector<double>, thermalBndCondValue, vector<double>(6,0),,"Imposed value of a boundary condition."))
((vector<double>, thermalBndFlux, vector<double>(6,0),,"Flux through thermal boundary."))
((bool,boundarySet,false,,"set false after changing boundary conditions"))
((bool,boundarySet,false,,"set false to change boundary conditions"))
((bool,useKernMethod,false,,"flag to use Kern method for thermal conductivity area calc"))
((bool,useHertzMethod,false,,"flag to use hertzmethod for thermal conductivity area calc"))
((Real,fluidBeta,0.0002,,"volumetric temperature coefficient m^3/m^3C, default water, <= 0 deactivates"))
((Real,particleT0,0,,"Initial temperature of particles"))
//((bool,useVolumeChange,false,,"Use volume change for thermal-mechanical-hydraulic coupling instead of pressure change. False by default."))
((bool,letThermalRunFlowForceUpdates,false,,"If true, Thermal will run force updates according to new pressures instead of FlowEngine. only useful if useVolumeChange=false."))
((bool,flowTempBoundarySet,true,,"set false to change boundary conditions"))
((bool,unboundCavityBodies,true,,"automatically unbound bodies touching only cavity cells."))
((Real,particleK,3.0,,"Particle thermal conductivity (W/(mK)"))
((Real,particleCp,750.,,"Particle thermal heat capacity (J/(kgK)"))
((Real,fluidConductionAreaFactor,1.,,"Factor for the porethroat area (used for fluid-fluid conduction model)"))
((Real,particleAlpha,11.6e-6,,"Particle volumetric thermal expansion coeffcient"))
((double, fluidK, 0.650,,"Thermal conductivity of the fluid."))
((double, tsSafetyFactor, 0.8,,"Allow user to control the timstep estimate with a safety factor. Default 0.8"))
((Real,particleDensity,0,,"If > 0, this value will override material density for thermodynamic calculations (useful for quasi-static simulations involving unphysical particle densities)"))
((Real
,fluidK,0.580,,"Thermal conductivity of the fluid."))
((Real,Reynolds,0.,,"Used for the fluid-solid conduction model (calculation of Nusselt). Anything other than 0 is experimental. "))
((double,fluidBulkModulus,0,,"If > 0, thermalEngine uses this value instead of flow.fluidBulkModulus."))
((Real, delT, 0,,"Allows user to apply a delT to solids and observe macro thermal expansion. Resets to 0 after one conduction step."))
((double,tsSafetyFactor,0.8,,"Allow user to control the timstep estimate with a safety factor. Default 0.8. If <= 0, thermal timestep is equal to DEM"))
((double,porosityFactor,0,,"If >0, factors the fluid thermal expansion. Useful for simulating low porosity matrices."))
((bool,tempDependentFluidBeta,false,,"If true, fluid volumetric thermal expansion is temperature dependent (linear model between 20-70 degC)"))
,
/* extra initializers */
,
/* ctor */
energySet=false;timeStepEstimated=false;thermalDT=0;elapsedTime=0;first=true;runConduction=false;maxTimeStep=10000;
energySet=false;timeStepEstimated=false;thermalDT=0;elapsedTime=0;elapsedIters=0;conductionIterPeriod=1;first=true;runConduction=false;maxTimeStep=10000;Nu=0;Pr=0;NutimesFluidK=0;
,
/* py */
.def("getThermalDT",&ThermalEngine::getThermalDT,"let user check estimated thermalDT .")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment