21#ifdef REACTIONS_ENABLED
45 vector<double> &ScHips_,
46 bool performReaction_,
47 shared_ptr<void> vcantSol,
51 domainLength(domainLength_),
54 forceTurb(forceTurb_),
58 performReaction(performReaction_),
59 realization(realization_){
61 #ifdef REACTIONS_ENABLED
63 shared_ptr<Cantera::Solution> cantSol = static_pointer_cast<Cantera::Solution>(vcantSol);
64 gas = cantSol->thermo();
65 nsp = gas->nSpecies();
67 bRxr = make_shared<batchReactor_cvode>(cantSol);
73 throw std::runtime_error(
"Error: forceTurb should be false if preformReaction is true");
81 set_tree(nLevels, domainLength, tau0);
89 vector<double> &ScHips_,
90 bool performReaction_,
91 shared_ptr<void> vcantSol,
95 forceTurb(forceTurb_),
99 performReaction(performReaction_),
100 realization(realization_){
102 #ifdef REACTIONS_ENABLED
104 if(performReaction) {
105 shared_ptr<Cantera::Solution> cantSol = static_pointer_cast<Cantera::Solution>(vcantSol);
106 gas = cantSol->thermo();
107 nsp = gas->nSpecies();
113 bRxr = make_shared<batchReactor_cantera>(cantSol);
118 varData.resize(nVar);
119 varName.resize(nVar);
137 for (
int i=0; i<
ScHips.size(); i++)
141 nLevels += ceil(log(maxSc)/log(4));
153 vector<double> levelLengths(
nLevels);
154 vector<double> levelTaus(
nLevels);
157 for (
int i=0; i<
nLevels; i++) {
162 levelRates[i] = 1.0/levelTaus[i] * pow(2.0,i);
168 levelTaus[i] =
tau0 *
171 levelRates[i] = 1.0/levelTaus[i] * pow(2.0,i);
178 for (
int i=0; i<=
Nm3; i++)
182 for (
int i=0; i<=
iEta; i++)
189 for (
int k=0; k<
nVar; k++) {
214void hips::set_tree(
double Re_,
double domainLength_,
double tau0_, std::string ReApproach_) {
220 double baseLevelEstimate = (3.0 / 4) * log(1 /
Re) / log(
Afac);
224 baseLevel = round(baseLevelEstimate);
227 baseLevel = ceil(baseLevelEstimate);
228 int previousLevel = baseLevel - 1;
229 Prob = baseLevelEstimate - previousLevel;
232 baseLevel = ceil(baseLevelEstimate);
233 lStar = std::pow(
Re, -3.0 / 4);
236 baseLevel = round(baseLevelEstimate);
237 Anew = exp(-log(
Re) / ((4.0 / 3.0) * baseLevel));
240 throw std::invalid_argument(
"Invalid ReApproach specified");
250 for (
const auto &sc :
ScHips)
251 maxSc = std::max(maxSc,
static_cast<int>(sc));
253 nLevels += ceil(log(maxSc) / log(4));
263 std::vector<double> levelLengths(
nLevels);
264 std::vector<double> levelTaus(
nLevels);
267 for (
int i = 0; i <
nLevels; ++i) {
271 levelRates[i] = 1.0 / levelTaus[i] * pow(2.0, i);
287 levelRates[i] = 1.0 / levelTaus[i] * pow(2.0, i);
294 for (
int i = 0; i <=
Nm3; ++i)
298 for (
int i = 0; i <=
iEta; ++i)
304 for (
int k = 0; k <
nVar; ++k) {
343void hips::set_varData(std::vector<double> &v, std::vector<double> &w,
const std::string &varN) {
371void hips::set_varData(std::vector<double> &v, std::vector<double> &w,
const std::string &varN,
const std::vector<double> &rho) {
373 std::pair<std::vector<double>, std::vector<double>> results =
projection(v, w, rho);
404std::vector<double>
hips::projection(std::vector<double> &vcfd, std::vector<double> &weight) {
409 int nc =
xc.size() - 1;
410 int nh =
xh.size() - 1;
412 std::vector<double> vh(nh, 0.0);
415 for(
int i = 0; i < nh; i++) {
416 for(
int j = jprev + 1; j <= nc; ++j) {
417 if(
xc[j] <=
xh[i + 1]) {
418 double d1 =
xc[j] -
xc[j - 1];
419 double d2 =
xc[j] -
xh[i];
422 double d = std::min(d1, d2) < 1E-15 ? 0 : std::min(d1, d2);
424 vh[i] += vcfd[j - 1] * d;
427 double d1 =
xh[i + 1] -
xc[j - 1];
428 double d2 =
xh[i + 1] -
xh[i];
431 double d = std::min(d1, d2) < 1E-15 ? 0 : std::min(d1, d2);
433 vh[i] += vcfd[j - 1] * d;
438 vh[i] /= (
xh[i + 1] -
xh[i]);
488std::pair<std::vector<double>, std::vector<double>>
490 std::vector<double> &weight,
491 const std::vector<double> &density) {
496 int nc =
xc.size() - 1;
497 int nh =
xh.size() - 1;
499 std::vector<double> vh(nh, 0.0);
500 std::vector<double> rho_h(nh, 0.0);
504 for (
int i = 0; i < nh; i++)
509 double parcel_length =
xh[i + 1] -
xh[i];
511 for (
int j = jprev + 1; j <= nc; ++j)
514 double overlap_start = std::max(
xh[i],
xc[j - 1]);
515 double overlap_end = std::min(
xh[i + 1],
xc[j]);
517 double overlap_len = overlap_end - overlap_start;
518 if (overlap_len <= 0.0)
continue;
521 double effective_len = overlap_len * (
wPar[i] / parcel_length);
524 double rho = density[j - 1];
525 double phi = vcfd[j - 1];
526 M += rho * effective_len;
527 Mphi += rho * phi * effective_len;
530 if (
xc[j] >=
xh[i + 1]) {
537 if (
wPar[i] > 0.0) rho_h[i] = M /
wPar[i];
538 if (M > 0.0) vh[i] = Mphi / M;
566 for(
int i=0; i<w.size(); i++)
569 std::vector<double> pos;
574 while (i <= w.size()) {
603 std::vector<double>
xh(N + 1);
604 double step = 1.0 / N;
606 for(
int i = 0; i <= N; i++)
651 unsigned long long nEddies = 0;
656 int lastEddyOutput = 0;
682 if (shouldWriteData) {
687 else if (writeByTime) {
723 static double c1 = 1.0 - pow(2.0, 5.0/3.0*(
iEta+1));
724 static double c2 = pow(2.0,
Nm2) - pow(2.0,
iEta+1);
725 static double c3 = pow(2.0,
iEta+1);
738 iLevel = ceil(3.0/5.0*log2(1.0-r*c1) - 1.0);
739 if (iLevel < 0) iLevel = 0;
745 iLevel = ceil(log2(r*c2 + c3) - 1.0);
746 if (iLevel <
iEta+1) iLevel =
iEta+1;
747 if (iLevel >
Nm3) iLevel =
Nm3;
809 int Qstart = (zero_q << (
Nm3-iLevel)) + (iTree << (
Nm1-iLevel));
810 int Rstart = (one_r << (
Nm3-iLevel)) + (iTree << (
Nm1-iLevel));
811 int nPswap = 1 << (
Nm3-iLevel);
813 int Qend = Qstart + nPswap;
814 int Rend = Rstart + nPswap;
815 vector<int> aa(
pLoc.begin()+Qstart,
pLoc.begin()+Qend);
816 copy(
pLoc.begin()+Rstart,
pLoc.begin()+Rend,
pLoc.begin()+Qstart);
817 copy(aa.begin(), aa.end(),
pLoc.begin()+Rstart);
851 bool rxnDone =
false;
852 for (
int k = 0; k <
nVar; k++) {
854 if ((iLevel >=
i_plus[k]) ||
895 auto it = std::find(this->varName.begin(), this->varName.end(),
varName);
896 if (it == this->varName.end()) {
897 throw std::runtime_error(
"Error: Variable name '" +
varName +
"' not found.");
899 return std::distance(this->varName.begin(), it);
935 #ifdef REACTIONS_ENABLED
938 std::vector<int> yIdx(
nsp);
939 for (
int k = 0; k <
nsp; ++k) {
943 const int nP = 1 << (
Nm1 - iLevel);
944 const int istart = iTree * nP;
945 const int iend = istart + nP;
947 std::vector<double> y(
nsp);
949 for (
int i = istart; i < iend; ++i) {
950 const int ime =
pLoc[i];
954 double h = (*
varData[enthalpyIdx])[ime];
955 for (
int k = 0; k <
nsp; ++k) {
956 y[k] = (*
varData[yIdx[k]])[ime];
960 const double rho_old =
varRho[ime];
964 bRxr->react(h, y, dt);
967 const double rho_new = bRxr->getDensity();
971 wPar[ime] *= (rho_old / rho_new);
978 (*
varData[enthalpyIdx])[ime] = h;
979 for (
int k = 0; k <
nsp; ++k) {
980 (*
varData[yIdx[k]])[ime] = y[k];
1033 int nPmix = 1 << (
nLevels - iLevel - 2);
1037 istart = iTree << (
Nm1 - iLevel);
1038 iend = istart + nPmix;
1043 for (
int i = istart; i < iend; i++) {
1047 s += (*
varData[kVar])[ime] * m;
1055 ? ((msum > 0.0) ? (s / msum) : 0.0)
1058 for (
int i = istart; i < iend; i++) {
1065 iend = istart + nPmix;
1070 for (
int i = istart; i < iend; i++) {
1074 s += (*
varData[kVar])[ime] * m;
1082 ? ((msum > 0.0) ? (s / msum) : 0.0)
1085 for (
int i = istart; i < iend; i++) {
1116 for (
int k = 0; k <
varData.size(); k++) {
1121 for (
int i = 0; i < nparcels >> 1; i++)
1126 for (
int i = 0; i < nparcels >> 1; i++)
1172 stringstream ss1, ss2;
1176 ss1 <<
"../data/rlz_" << setfill(
'0') << setw(5) << real;
1181 system((
"mkdir " + s1).c_str());
1183 system((
"mkdir -p " + s1).c_str());
1186 ss2 <<
"Data_" << setfill(
'0') << setw(5) << ifile <<
".dat";
1189 string fname = s1 +
"/" + s2;
1190 ofstream ofile(fname.c_str());
1191 cout << endl <<
"writing data for time " << outputTime <<
" to file: " << fname.c_str();
1195 cerr <<
"Error: Unable to open file " << fname <<
" for writing!" << endl;
1200 ofile <<
"# time = " << outputTime <<
"\n";
1201 ofile <<
"# Grid Points = " <<
nparcels <<
"\n";
1205 ofile << setw(19) <<
"# Temp";
1207 for (
const auto& varN :
varName) {
1208 ofile << setw(19) <<
"# " << varN;
1213 ofile << scientific;
1214 ofile << setprecision(10);
1217 for (
int i = 0; i <
nparcels; i++) {
1219 #ifdef REACTIONS_ENABLED
1221 vector<double> yy(
nsp);
1222 for(
int k=0; k<
nsp; k++)
1224 gas->setMassFractions(yy.data());
1225 gas->setState_HP((*
varData[0])[
pLoc[i]], gas->pressure());
1226 ofile << setw(19) << gas->temperature();
1231 for (
int k = 0; k <
nVar; k++) {
1283 int nh =
xh.size() - 1;
1284 int nc =
xc.size() - 1;
1286 std::vector<double> vc(nc, 0.0);
1289 for (
int i = 0; i < nc; ++i) {
1290 for (
int j = jprev + 1; j <= nh; ++j) {
1291 if (
xh[j] <=
xc[i + 1]) {
1292 double d1 =
xh[j] -
xh[j - 1];
1293 double d2 =
xh[j] -
xc[i];
1296 double d = std::min(d1, d2) < 1E-15 ? 0 : std::min(d1, d2);
1298 vc[i] += vh[j - 1] * d;
1300 double d1 =
xc[i + 1] -
xh[j - 1];
1301 double d2 =
xc[i + 1] -
xc[i];
1304 double d = std::min(d1, d2) < 1E-15 ? 0 : std::min(d1, d2);
1306 vc[i] += vh[j - 1] * d;
1312 vc[i] /= (
xc[i + 1] -
xc[i]);
1356 std::vector<double> &rho_h,
1357 std::vector<double> &rho_c) {
1358 const int nh =
static_cast<int>(
xh.size()) - 1;
1359 const int nc =
static_cast<int>(
xc.size()) - 1;
1361 std::vector<double> phi_c(nc, 0.0);
1362 std::vector<double> M_cfd(nc, 0.0);
1363 std::vector<double> Mphi_cfd(nc, 0.0);
1366 for (
int i = 0; i < nc; ++i) {
1368 const double cell_len =
xc[i + 1] -
xc[i];
1370 for (
int j = jprev + 1; j <= nh; ++j) {
1372 const double overlap_start = std::max(
xh[j - 1],
xc[i]);
1373 const double overlap_end = std::min(
xh[j],
xc[i + 1]);
1374 const double overlap_len = overlap_end - overlap_start;
1375 if (overlap_len <= 0.0)
continue;
1378 const double parcel_len =
xh[j] -
xh[j - 1];
1379 const double effective_len = overlap_len * (
wPar[
pLoc[j - 1]] / parcel_len);
1382 const double rhoP = rho_h[j - 1];
1383 const double phiP = vh[j - 1];
1384 M_cfd[i] += rhoP * effective_len;
1385 Mphi_cfd[i] += rhoP * phiP * effective_len;
1388 if (
xc[i + 1] <=
xh[j]) { jprev = j - 1;
break; }
1392 rho_c[i] = (cell_len > 0.0) ? (M_cfd[i] / cell_len) : 0.0;
1393 phi_c[i] = (M_cfd[i] > 1e-300) ? (Mphi_cfd[i] / M_cfd[i]) : 0.0;
1421 std::vector<std::vector<double>> varDataProjections;
1423 for (
int i = 0; i <
varData.size(); i++) {
1427 for (
int j = 0; j <
nparcels; j++) {
1432 varDataProjections.push_back(vc);
1435 return varDataProjections;
1460 std::vector<std::vector<double>> varDataProjections;
1463 std::vector<double> rho_h(
nparcels);
1464 for (
int i = 0; i <
nparcels; i++) {
1470 for (
int i = 0; i <
varData.size(); i++) {
1474 for (
int j = 0; j <
nparcels; j++) {
1479 varDataProjections.push_back(vc);
1482 return {varDataProjections, rho_c};
1541 std::string filepath =
"../post/parameters.dat";
1542 std::ofstream file(filepath);
1545 std::cerr <<
"Error: Could not open " << filepath <<
" for writing!\n";
1550 file <<
"nLevels " <<
nLevels <<
"\n";
1552 file <<
"tau0 " <<
tau0 <<
"\n";
1553 file <<
"C_param " <<
C_param <<
"\n";
1554 file <<
"forceTurb " <<
forceTurb <<
"\n";
1555 file <<
"nVar " <<
nVar <<
"\n";
1562 for (
const std::string &name :
varName) {
1563 file << name <<
" ";
1567 file <<
"varName (undefined)\n";
1572 file <<
"i_batchelor ";
1578 file <<
"i_batchelor (undefined or size mismatch)\n";
std::vector< double > setGridHips(int N)
Generates a physical domain for HiPS parcels.
std::vector< double > parcelTimes
current times corresponding to the parcel states
double lastOutputTime
Last time data was written.
int nVar
number of parcel variables (e.g., h, ysp)
int nLevels_
number of tree levels?
int getVariableIndex(const std::string &varName) const
Retrieves the index of a variable by its name in the varName list.
std::vector< double > xc
vector containing physical domain of flow particles
std::vector< int > pLoc
parcel index array for fast implementation of swaps
bool performReaction
flag indicating whether chemical reactions are performed in the simulation
void forceProfile()
Adjusts the HiPS profile to enforce statistical stationarity.
std::vector< double > xh
vector containing physical domain of HiPS parcels
void set_tree(int nLevels_, double domainLength_, double tau0_)
Sets up the HiPS tree using explicitly specified tree parameters.
std::vector< double > wPar
parcel volume fractions
int nL
adjusted number of levels based on the Reynolds number
bool forceTurb
forcing function for statistically stationary: -1 = none, 1 = source term, 2 = dir
std::vector< double > projection_back(std::vector< double > &vb)
Projects HiPS parcel values back onto the flow particles.
void setOutputIntervalEddy(int interval)
Sets the interval (in number of eddy events) for writing simulation data.
std::vector< std::vector< double > > get_varData()
Retrieves the final data from the simulation.
std::vector< int > i_plus
ceil(i_batchelor)
double outputIntervalTime
Default: write data every 0.1s.
double Afac
level lengthscale reduction factor (0.5)
double C_param
Eddy frequency parameter.
int realization
number of realizations
const int DEFAULT_EDDY_INTERVAL
Default: Write every 1000 eddies.
void selectAndSwapTwoSubtrees(const int iLevel, int &iTree)
Performs eddy events by swapping parcels within the HiPS tree.
void writeData(int real, const int ifile, const double outputTime)
Writes simulation data to a file for a specific realization, time, and file index.
double eddyRate_inertial
total rate of all eddies 0 through iEta (= eddyRate_total if Sc=1)
double Anew
adjusted level lengthscale reduction factor for dynamic adjustment of reduction factor
int currentIndex
member variable to keep track of current index of variables
std::vector< double > projection_back_with_density(std::vector< double > &vh, std::vector< double > &rho_h, std::vector< double > &rho_c)
Projects HiPS parcel values and densities back onto the flow particles (CFD cells).
std::vector< double > i_batchelor
Batchelor level for variable Sc scalars; NOTE: double, as in, between levels.
void calculateSolution(const double tRun, bool shouldWriteData=false)
Runs the HiPS simulation, advancing the solution using eddy events.
double time
current simulation time
void sample_hips_eddy(double &dt, int &iLevel)
Samples stochastic eddy events on the HiPS tree, determining the time increment and tree level.
void setOutputIntervalTime(double interval)
Sets the interval (in simulation time) for writing simulation data.
std::vector< double > varRho
density
void reactParcels_LevelTree(const int iLevel, const int iTree)
Simulates chemical reactions for parcels affected by a micromixing event.
hips(double C_param_, bool forceTurb_, int nVar_, std::vector< double > &ScHips_, bool performReaction, std::shared_ptr< void > vcantSol=nullptr, int seed=10, int realization_=1)
Constructor for initializing a HiPS object without building the tree immediately.
std::pair< std::vector< std::vector< double > >, std::vector< double > > get_varData_with_density()
Retrieves final simulation data, including both values and densities.
bool useTimeBasedWriting
Tracks if time writing is set.
std::vector< double > levelRates
list of eddy event rates at each level
std::vector< std::string > varName
vector containing the names of parcel variables
double Re
Reynolds number.
bool useEddyBasedWriting
Tracks if eddy writing is set.
void set_varData(std::vector< double > &v, std::vector< double > &w, const std::string &varN)
Assigns variables, their corresponding weights, and names to the parcels in the HiPS tree.
int nparcels
number of parcels
double Prob
probability value for probability-based solution
void mixAcrossLevelTree(int kVar, const int iMixLevel, const int iTree)
Uniformly mixes parcels at a specified level and subtree within the HiPS model.
double dtEE
time increment to next eddy event
int iEta
Kolmogorov level (needed for variable Sc scalars)
double eddyRate_total
total rate of all eddies 0 through nLevels-3
double domainLength
length of domain (m)
int eddyCounter
Counter for eddy events.
std::vector< std::shared_ptr< std::vector< double > > > varData
vector of pointers to vector
std::vector< double > projection(std::vector< double > &vcfd, std::vector< double > &weight)
Projects values from flow particles onto HiPS parcels assuming constant density.
std::vector< double > setGridCfd(std::vector< double > &w)
Generates a physical domain for flow particles based on their weights.
void advanceHips(const int iLevel, const int iTree)
Advances the HiPS model by simulating micromixing and reactions at a specific tree level.
double lStar
length of the level associated with the Reynolds number
int outputIntervalEddy
Default: write data every 10 eddy events.
double tau0
integral timescale
void saveAllParameters()
Saves all user-defined to a file.
int nLevels
number of tree levels
bool LScHips
hips schmidt number
std::vector< double > ScHips
vector containing Schmidt numbers related to each variable
int getRandInt(unsigned n)