21#ifdef REACTIONS_ENABLED
44 vector<double> &ScHips_,
45 bool performReaction_,
46 shared_ptr<void> vcantSol,
50 domainLength(domainLength_),
53 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);
78 set_tree(nLevels, domainLength, tau0, ScHips);
86 bool performReaction_,
87 shared_ptr<void> vcantSol,
91 forceTurb(forceTurb_),
95 performReaction(performReaction_),
96 realization(realization_){
98 #ifdef REACTIONS_ENABLED
100 if(performReaction) {
101 shared_ptr<Cantera::Solution> cantSol = static_pointer_cast<Cantera::Solution>(vcantSol);
102 gas = cantSol->thermo();
103 nsp = gas->nSpecies();
109 bRxr = make_shared<batchReactor_cantera>(cantSol);
114 varData.resize(nVar);
115 varName.resize(nVar);
120void hips::set_tree(
int nLevels_,
double domainLength_,
double tau0_, vector<double> &ScHips_){
134 for (
int i=0; i<
ScHips.size(); i++)
138 nLevels += ceil(log(maxSc)/log(4));
150 vector<double> levelLengths(
nLevels);
151 vector<double> levelTaus(
nLevels);
154 for (
int i=0; i<
nLevels; i++) {
159 levelRates[i] = 1.0/levelTaus[i] * pow(2.0,i);
165 levelTaus[i] =
tau0 *
168 levelRates[i] = 1.0/levelTaus[i] * pow(2.0,i);
175 for (
int i=0; i<=
Nm3; i++)
179 for (
int i=0; i<=
iEta; i++)
186 for (
int k=0; k<
nVar; k++) {
209void hips::set_tree(
double Re_,
double domainLength_,
double tau0_, std::vector<double> &ScHips_, std::string approach_) {
216 double baseLevelEstimate = (3.0 / 4) * log(1 /
Re) / log(
Afac);
220 baseLevel = round(baseLevelEstimate);
222 else if (
approach ==
"probability") {
223 baseLevel = ceil(baseLevelEstimate);
224 int previousLevel = baseLevel - 1;
225 Prob = baseLevelEstimate - previousLevel;
227 else if (
approach ==
"micromixing") {
228 baseLevel = ceil(baseLevelEstimate);
229 lStar = std::pow(
Re, -3.0 / 4);
232 baseLevel = round(baseLevelEstimate);
233 Anew = exp(-log(
Re) / ((4.0 / 3.0) * baseLevel));
236 throw std::invalid_argument(
"Invalid approach specified");
246 for (
const auto &sc :
ScHips)
247 maxSc = std::max(maxSc,
static_cast<int>(sc));
249 nLevels += ceil(log(maxSc) / log(4));
259 std::vector<double> levelLengths(
nLevels);
260 std::vector<double> levelTaus(
nLevels);
263 for (
int i = 0; i <
nLevels; ++i) {
267 levelRates[i] = 1.0 / levelTaus[i] * pow(2.0, i);
283 levelRates[i] = 1.0 / levelTaus[i] * pow(2.0, i);
290 for (
int i = 0; i <=
Nm3; ++i)
294 for (
int i = 0; i <=
iEta; ++i)
300 for (
int k = 0; k <
nVar; ++k) {
337void hips::set_varData(std::vector<double> &v, std::vector<double> &w,
const std::string &varN) {
365void hips::set_varData(std::vector<double> &v, std::vector<double> &w,
const std::string &varN,
const std::vector<double> &rho) {
367 std::pair<std::vector<double>, std::vector<double>> results =
projection(v, w, rho);
368 std::vector<double> vh = results.first;
369 std::vector<double> rho_h = results.second;
372 varRho = std::vector<double>(rho_h);
400std::vector<double>
hips::projection(std::vector<double> &vcfd, std::vector<double> &weight) {
405 int nc =
xc.size() - 1;
406 int nh =
xh.size() - 1;
408 std::vector<double> vh(nh, 0.0);
411 for(
int i = 0; i < nh; i++) {
412 for(
int j = jprev + 1; j <= nc; ++j) {
413 if(
xc[j] <=
xh[i + 1]) {
414 double d1 =
xc[j] -
xc[j - 1];
415 double d2 =
xc[j] -
xh[i];
418 double d = std::min(d1, d2) < 1E-15 ? 0 : std::min(d1, d2);
420 vh[i] += vcfd[j - 1] * d;
423 double d1 =
xh[i + 1] -
xc[j - 1];
424 double d2 =
xh[i + 1] -
xh[i];
427 double d = std::min(d1, d2) < 1E-15 ? 0 : std::min(d1, d2);
429 vh[i] += vcfd[j - 1] * d;
434 vh[i] /= (
xh[i + 1] -
xh[i]);
464std::pair<std::vector<double>, std::vector<double>>
hips::projection(std::vector<double> &vcfd,
465 std::vector<double> &weight,
466 const std::vector<double> &density) {
472 int nc =
xc.size() - 1;
473 int nh =
xh.size() - 1;
475 std::vector<double> vh(nh, 0.0);
476 std::vector<double> rho_h(nh, 0.0);
479 for (
int i = 0; i < nh; i++) {
480 double total_dx = 0.0;
482 for (
int j = jprev + 1; j <= nc; ++j) {
483 if (
xc[j] <=
xh[i + 1]) {
484 double d = std::min(
xc[j] -
xc[j - 1],
xc[j] -
xh[i]);
486 rho_h[i] += density[j - 1] * d;
487 vh[i] += density[j - 1] * vcfd[j - 1] * d;
490 double d = std::min(
xh[i + 1] -
xc[j - 1],
xh[i + 1] -
xh[i]);
492 rho_h[i] += density[j - 1] * d;
493 vh[i] += density[j - 1] * vcfd[j - 1] * d;
501 rho_h[i] /= (
xh[i + 1] -
xh[i]);
502 vh[i] /= rho_h[i] * (
xh[i + 1] -
xh[i]);
528 std::vector<double> pos;
533 while (i <= w.size()) {
562 std::vector<double>
xh(N + 1);
563 double step = 1.0 / N;
565 for(
int i = 0; i <= N; i++)
610 unsigned long long nEddies = 0;
615 int lastEddyOutput = 0;
641 if (shouldWriteData) {
646 else if (writeByTime) {
682 static double c1 = 1.0 - pow(2.0, 5.0/3.0*(
iEta+1));
683 static double c2 = pow(2.0,
Nm2) - pow(2.0,
iEta+1);
684 static double c3 = pow(2.0,
iEta+1);
697 iLevel = ceil(3.0/5.0*log2(1.0-r*c1) - 1.0);
698 if (iLevel < 0) iLevel = 0;
704 iLevel = ceil(log2(r*c2 + c3) - 1.0);
705 if (iLevel <
iEta+1) iLevel =
iEta+1;
706 if (iLevel >
Nm3) iLevel =
Nm3;
768 int Qstart = (zero_q << (
Nm3-iLevel)) + (iTree << (
Nm1-iLevel));
769 int Rstart = (one_r << (
Nm3-iLevel)) + (iTree << (
Nm1-iLevel));
770 int nPswap = 1 << (
Nm3-iLevel);
772 int Qend = Qstart + nPswap;
773 int Rend = Rstart + nPswap;
774 vector<int> aa(
pLoc.begin()+Qstart,
pLoc.begin()+Qend);
775 copy(
pLoc.begin()+Rstart,
pLoc.begin()+Rend,
pLoc.begin()+Qstart);
776 copy(aa.begin(), aa.end(),
pLoc.begin()+Rstart);
810 bool rxnDone =
false;
811 for (
int k = 0; k <
nVar; k++) {
813 if ((iLevel >=
i_plus[k]) ||
854 auto it = std::find(this->varName.begin(), this->varName.end(),
varName);
855 if (it == this->varName.end()) {
856 throw std::runtime_error(
"Error: Variable name '" +
varName +
"' not found.");
858 return std::distance(this->varName.begin(), it);
891 #ifdef REACTIONS_ENABLED
894 int nP = 1 << (
Nm1 - iLevel);
895 int istart = iTree * nP;
896 int iend = istart + nP;
900 std::vector<double> y(
nsp);
902 for (
int i = istart; i < iend; i++) {
907 h = (*
varData[enthalpyIdx])[ime];
910 for (
int k = 0; k <
nsp; k++) {
912 y[k] = (*
varData[speciesIdx])[ime];
915 bRxr->react(h, y, dt);
916 varRho[ime] = bRxr->getDensity();
917 Temp[ime] = bRxr->temperature;
920 (*
varData[enthalpyIdx])[ime] = h;
921 for (
int k = 0; k <
nsp; k++) {
923 (*
varData[speciesIdx])[ime] = y[k];
972 int nPmix = 1 << (
nLevels - iLevel - 2);
978 istart = iTree << (
Nm1-iLevel);
979 iend = istart + nPmix;
982 for (
int i=istart; i<iend; i++) {
986 for (
int i=istart; i<iend; i++) {
988 (*
varData[kVar])[ime] = s / nPmix;
994 iend = istart + nPmix;
997 for (
int i=istart; i<iend; i++) {
1001 for (
int i=istart; i<iend; i++) {
1003 (*
varData[kVar])[ime] = s / nPmix;
1032 for (
int k = 0; k <
varData.size(); k++) {
1037 for (
int i = 0; i < nparcels >> 1; i++)
1042 for (
int i = 0; i < nparcels >> 1; i++)
1088 stringstream ss1, ss2;
1092 ss1 <<
"../data/rlz_" << setfill(
'0') << setw(5) << real;
1097 system((
"mkdir " + s1).c_str());
1099 system((
"mkdir -p " + s1).c_str());
1102 ss2 <<
"Data_" << setfill(
'0') << setw(5) << ifile <<
".dat";
1105 string fname = s1 +
"/" + s2;
1106 ofstream ofile(fname.c_str());
1110 cerr <<
"Error: Unable to open file " << fname <<
" for writing!" << endl;
1115 ofile <<
"# time = " << outputTime <<
"\n";
1116 ofile <<
"# Grid Points = " <<
nparcels <<
"\n";
1120 ofile << setw(19) <<
"# Temp";
1122 for (
const auto& varN :
varName) {
1123 ofile << setw(19) <<
"# " << varN;
1128 ofile << scientific;
1129 ofile << setprecision(10);
1132 for (
int i = 0; i <
nparcels; i++) {
1135 ofile << setw(19) <<
Temp[
pLoc[i]];
1138 for (
int k = 0; k <
nVar; k++) {
1182 int nh =
xh.size() - 1;
1183 int nc =
xc.size() - 1;
1185 std::vector<double> vc(nc, 0.0);
1188 for (
double val : vc)
1189 std::cout << val <<
" ";
1190 std::cout << std::endl;
1192 for (
int i = 0; i < nc; ++i) {
1193 for (
int j = jprev + 1; j <= nh; ++j) {
1194 if (
xh[j] <=
xc[i + 1]) {
1195 double d1 =
xh[j] -
xh[j - 1];
1196 double d2 =
xh[j] -
xc[i];
1199 double d = std::min(d1, d2) < 1E-15 ? 0 : std::min(d1, d2);
1201 vc[i] += vh[j - 1] * d;
1203 double d1 =
xc[i + 1] -
xh[j - 1];
1204 double d2 =
xc[i + 1] -
xc[i];
1207 double d = std::min(d1, d2) < 1E-15 ? 0 : std::min(d1, d2);
1209 vc[i] += vh[j - 1] * d;
1215 vc[i] /= (
xc[i + 1] -
xc[i]);
1257 std::vector<double> &rho_h) {
1258 int nh =
xh.size() - 1;
1259 int nc =
xc.size() - 1;
1261 std::vector<double> vc(nc, 0.0);
1262 std::vector<double> rho_c(nc, 0.0);
1265 for (
int i = 0; i < nc; ++i) {
1266 double total_dx = 0.0;
1268 for (
int j = jprev + 1; j <= nh; ++j) {
1269 if (
xh[j] <=
xc[i + 1]) {
1270 double d = std::min(
xh[j] -
xh[j - 1],
xh[j] -
xc[i]);
1272 rho_c[i] += rho_h[j - 1] * d;
1273 vc[i] += vh[j - 1] * rho_h[j - 1] * d;
1275 double d = std::min(
xc[i + 1] -
xh[j - 1],
xc[i + 1] -
xc[i]);
1277 rho_c[i] += rho_h[j - 1] * d;
1278 vc[i] += vh[j - 1] * rho_h[j - 1] * d;
1313 std::vector<std::vector<double>> varDataProjections;
1315 for (
int i = 0; i <
varData.size(); i++)
1318 return varDataProjections;
1343 std::vector<std::pair<std::vector<double>, std::vector<double>>> varDataProjections;
1345 for (
int i = 0; i <
varData.size(); i++) {
1347 std::vector<double> vh = (*
varData[i]);
1348 std::vector<double> rho_h =
varRho;
1354 return varDataProjections;
1413 std::string filepath =
"../post/parameters.dat";
1414 std::ofstream file(filepath);
1417 std::cerr <<
"Error: Could not open " << filepath <<
" for writing!\n";
1422 file <<
"nLevels " <<
nLevels <<
"\n";
1424 file <<
"tau0 " <<
tau0 <<
"\n";
1425 file <<
"C_param " <<
C_param <<
"\n";
1426 file <<
"forceTurb " <<
forceTurb <<
"\n";
1427 file <<
"nVar " <<
nVar <<
"\n";
1434 for (
const std::string &name :
varName) {
1435 file << name <<
" ";
1439 file <<
"varName (undefined)\n";
1444 file <<
"i_batchelor ";
1450 file <<
"i_batchelor (undefined or size mismatch)\n";
1454 std::cout <<
"All parameters saved in: " << filepath << std::endl;
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?
std::pair< std::vector< double >, std::vector< double > > projection_back_with_density(std::vector< double > &vh, std::vector< double > &rho_h)
Projects HiPS parcel values and densities back onto the flow particles.
int getVariableIndex(const std::string &varName) const
Retrieves the index of a variable by its name in the varName list.
hips(double C_param_, int forceTurb_, int nVar_, 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::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
std::vector< std::pair< std::vector< double >, std::vector< double > > > get_varData_with_density()
Retrieves final simulation data, including both values and densities.
void forceProfile()
Adjusts the HiPS profile to enforce statistical stationarity.
std::vector< double > xh
vector containing physical domain of HiPS parcels
int nL
adjusted number of levels based on the Reynolds number
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 forceTurb
forcing function for statistically stationary: -1 = none, 1 = source term, 2 = dir
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 > 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
void reactParcels_LevelTree(const int iLevel, const int iTree)
Simulates chemical reactions for parcels affected by a micromixing event.
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
std::vector< double > Temp
Vector containg temperature in each parcel;.
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
void set_tree(int nLevels_, double domainLength_, double tau0_, std::vector< double > &ScHips_)
Sets up the HiPS tree using explicitly specified tree parameters.
std::vector< double > ScHips
vector containing Schmidt numbers related to each variable
int getRandInt(unsigned n)