22 #include "cantera/base/XML_Writer.h"
40 #define COLL_INT_POLY_DEGREE 8
46 const doublereal ThreeSixteenths = 3.0/16.0;
47 const doublereal TwoOverPi = 2.0/
Pi;
48 const doublereal FiveThirds = 5.0/3.0;
53 TransportFactory* TransportFactory::s_factory = 0;
56 mutex_t TransportFactory::transport_mutex;
71 CanteraError(
"getTransportData",
"error reading transport data: " + msg +
"\n") {
79 void TransportFactory::getBinDiffCorrection(doublereal t,
81 size_t k,
size_t j, doublereal xk, doublereal xj,
82 doublereal& fkj, doublereal& fjk)
84 doublereal w1, w2, wsum, sig1, sig2, sig12, sigratio, sigratio2,
85 sigratio3, tstar1, tstar2, tstar12,
86 om22_1, om22_2, om11_12, astar_12, bstar_12, cstar_12,
87 cnst, wmwp, sqw12, p1, p2, p12, q1, q2, q12;
92 wmwp = (w1 - w2)/wsum;
98 sigratio = sig1*sig1/(sig2*sig2);
99 sigratio2 = sig1*sig1/(sig12*sig12);
100 sigratio3 = sig2*sig2/(sig12*sig12);
109 astar_12 = integrals.
astar(tstar12, tr.
delta(k,j));
110 bstar_12 = integrals.
bstar(tstar12, tr.
delta(k,j));
111 cstar_12 = integrals.
cstar(tstar12, tr.
delta(k,j));
113 cnst = sigratio * sqrt(2.0*w2/wsum) * 2.0 *
115 p1 = cnst * om22_1 / om11_12;
117 cnst = (1.0/sigratio) * sqrt(2.0*w1/wsum) * 2.0*w2*w2/(wsum*w1);
118 p2 = cnst * om22_2 / om11_12;
120 p12 = 15.0 * wmwp*wmwp + 8.0*w1*w2*astar_12/(wsum*wsum);
122 cnst = (2.0/(w2*wsum))*sqrt(2.0*w2/wsum)*sigratio2;
123 q1 = cnst*((2.5 - 1.2*bstar_12)*w1*w1 + 3.0*w2*w2
124 + 1.6*w1*w2*astar_12);
126 cnst = (2.0/(w1*wsum))*sqrt(2.0*w1/wsum)*sigratio3;
127 q2 = cnst*((2.5 - 1.2*bstar_12)*w2*w2 + 3.0*w1*w1
128 + 1.6*w1*w2*astar_12);
130 q12 = wmwp*wmwp*15.0*(2.5 - 1.2*bstar_12)
131 + 4.0*w1*w2*astar_12*(11.0 - 2.4*bstar_12)/(wsum*wsum)
132 + 1.6*wsum*om22_1*om22_2/(om11_12*om11_12*sqw12)
133 * sigratio2 * sigratio3;
135 cnst = 6.0*cstar_12 - 5.0;
136 fkj = 1.0 + 0.1*cnst*cnst *
137 (p1*xk*xk + p2*xj*xj + p12*xk*xj)/
138 (q1*xk*xk + q2*xj*xj + q12*xk*xj);
139 fjk = 1.0 + 0.1*cnst*cnst *
140 (p2*xk*xk + p1*xj*xj + p12*xk*xj)/
141 (q2*xk*xk + q1*xj*xj + q12*xk*xj);
157 void TransportFactory::makePolarCorrections(
size_t i,
size_t j,
171 size_t kp = (tr.
polar[i] ? i : j);
172 size_t knp = (i == kp ? j : i);
174 doublereal d3np, d3p, alpha_star, mu_p_star, xi;
175 d3np = pow(tr.
sigma[knp],3);
176 d3p = pow(tr.
sigma[kp],3);
177 alpha_star = tr.
alpha[knp]/d3np;
178 mu_p_star = tr.
dipole(kp,kp)/sqrt(d3p * tr.
eps[kp]);
179 xi = 1.0 + 0.25 * alpha_star * mu_p_star * mu_p_star *
180 sqrt(tr.
eps[kp]/tr.
eps[knp]);
181 f_sigma = pow(xi, -1.0/6.0);
192 TransportFactory::TransportFactory() :
196 m_models[
"Multi"] = cMulticomponent;
197 m_models[
"Solid"] = cSolidTransport;
198 m_models[
"DustyGas"] = cDustyGasTransport;
199 m_models[
"CK_Multi"] = CK_Multicomponent;
200 m_models[
"CK_Mix"] = CK_MixtureAveraged;
201 m_models[
"Liquid"] = cLiquidTransport;
202 m_models[
"Aqueous"] = cAqueousTransport;
203 m_models[
"Simple"] = cSimpleTransport;
229 m_LTImodelMap[
"pairwiseInteraction"] = LTI_MODEL_PAIRWISE_INTERACTION;
230 m_LTImodelMap[
"stefanMaxwell_PPN"] = LTI_MODEL_STEFANMAXWELL_PPN;
231 m_LTImodelMap[
"moleFractionsExpT"] = LTI_MODEL_MOLEFRACS_EXPT;
255 std::string model =
lowercase(trNode[
"model"]);
257 case LTP_TD_CONSTANT:
260 case LTP_TD_ARRHENIUS:
270 throw CanteraError(
"newLTP",
"unknown transport model: " + model);
271 ltps =
new LTPspecies(&trNode, name, tp_ind, thermo);
291 std::string model = trNode[
"model"];
293 case LTI_MODEL_SOLVENT:
294 lti =
new LTI_Solvent(tp_ind);
295 lti->
init(trNode, thermo);
297 case LTI_MODEL_MOLEFRACS:
299 lti->
init(trNode, thermo);
301 case LTI_MODEL_MASSFRACS:
303 lti->
init(trNode, thermo);
305 case LTI_MODEL_LOG_MOLEFRACS:
307 lti->
init(trNode, thermo);
309 case LTI_MODEL_PAIRWISE_INTERACTION:
311 lti->
init(trNode, thermo);
312 lti->setParameters(trParam);
314 case LTI_MODEL_STEFANMAXWELL_PPN:
316 lti->
init(trNode, thermo);
317 lti->setParameters(trParam);
319 case LTI_MODEL_STOKES_EINSTEIN:
320 lti =
new LTI_StokesEinstein(tp_ind);
321 lti->
init(trNode, thermo);
322 lti->setParameters(trParam);
324 case LTI_MODEL_MOLEFRACS_EXPT:
326 lti->
init(trNode, thermo);
331 lti->
init(trNode, thermo);
344 if (transportModel ==
"") {
358 case cMulticomponent:
362 case CK_Multicomponent:
366 case cMixtureAveraged:
370 case CK_MixtureAveraged:
374 case cSolidTransport:
378 case cDustyGasTransport:
385 case cSimpleTransport:
390 case cLiquidTransport:
395 case cAqueousTransport:
401 throw CanteraError(
"newTransport",
"unknown transport model: " + transportModel);
417 if (!phaseNode.
hasChild(
"transport")) {
419 "no transport XML node");
422 std::string transportModel = transportNode.
attrib(
"model");
423 if (transportModel ==
"") {
425 "transport XML node doesn't have a model string");
453 size_t nsp = tr.
nsp_;
470 tr.
polar.resize(nsp,
false);
471 tr.
alpha.resize(nsp, 0.0);
473 tr.
sigma.resize(nsp);
479 for (
size_t i = 0; i < nsp; i++) {
480 tr.
poly[i].resize(nsp);
483 doublereal ts1, ts2, tstar_min = 1.e8, tstar_max = 0.0;
484 doublereal f_eps, f_sigma;
489 for (
size_t i = 0; i < nsp; i++) {
490 for (
size_t j = i; j < nsp; j++) {
498 epsilon(i,j) = sqrt(tr.
eps[i]*tr.
eps[j]);
504 if (ts1 < tstar_min) {
507 if (ts2 > tstar_max) {
515 doublereal d = diam(i,j);
517 / (epsilon(i,j) * d * d * d);
520 tr.
diam(i,j) *= f_sigma;
521 epsilon(i,j) *= f_eps;
525 diam(j,i) = diam(i,j);
526 epsilon(j,i) = epsilon(i,j);
535 if (mode == CK_Mode) {
545 tr.
xml->XML_open(flog,
"collision_integrals");
549 integrals.
init(tr.
xml, tstar_min, tstar_max, log_level);
553 tr.
xml->XML_close(flog,
"collision_integrals");
559 tr.
xml->XML_open(flog,
"property fits");
565 tr.
xml->XML_close(flog,
"property fits");
583 const std::vector<const XML_Node*> & species_database = thermo->
speciesData();
589 size_t nsp = trParam.
nsp_;
596 trParam.
mw.resize(nsp);
601 trParam.
LTData.resize(nsp);
618 if (phase_database->
hasChild(
"transport")) {
619 XML_Node& transportNode = phase_database->
child(
"transport");
640 thermo_t* thermo,
int mode,
int log_level)
643 const std::vector<const XML_Node*> & transport_database = thermo->
speciesData();
647 if (log_level == 0) {
650 ofstream flog(
"transport_log.xml");
651 trParam.
xml =
new XML_Writer(flog);
653 trParam.
xml->XML_open(flog,
"transport");
657 std::ostream& flog(std::cout);
660 setupMM(flog, transport_database, thermo, mode, log_level, trParam);
665 trParam.
xml->XML_close(flog,
"transport");
684 ofstream flog(
"transport_log.xml");
685 trParam.
xml =
new XML_Writer(flog);
687 trParam.
xml->XML_open(flog,
"transport");
691 std::ostream& flog(std::cout);
698 trParam.
xml->XML_close(flog,
"transport");
711 vector_fp::iterator dptr;
713 size_t nsp = tr.
nsp_;
721 tr.
xml->XML_open(logfile,
"tstar_fits");
722 tr.
xml->XML_comment(logfile,
"fits to A*, B*, and C* vs. log(T*).\n"
723 "These are done only for the required dstar(j,k) values.");
725 tr.
xml->XML_comment(logfile,
"*** polynomial coefficients not printed (log_level < 3) ***");
729 for (i = 0; i < nsp; i++) {
730 for (j = i; j < nsp; j++) {
732 if (mode != CK_Mode) {
733 dstar = tr.
delta(i,j);
745 if (dptr == tr.
fitlist.end()) {
746 vector_fp ca(degree+1), cb(degree+1), cc(degree+1);
748 integrals.
fit(logfile, degree, dstar,
763 tr.
poly[i][j] =
static_cast<int>((dptr - tr.
fitlist.begin()));
770 tr.
xml->XML_close(logfile,
"tstar_fits");
796 std::map<std::string, GasTransportData> datatable;
797 doublereal welldepth, diam, dipole, polar, rot;
799 size_t nsp = xspecies.size();
805 std::string val, type;
806 map<std::string, int> gindx;
808 gindx[
"linear"] = 101;
809 gindx[
"nonlinear"] = 102;
811 for (
size_t i = 0; i < nsp; i++) {
821 geom = gindx[val] - 100;
822 map<std::string, doublereal> fv;
833 if (welldepth >= 0.0) {
836 "negative well depth");
841 "negative or zero diameter");
846 "negative dipole moment");
851 "negative polarizability");
856 "negative rotation relaxation number");
858 datatable[name] = data;
864 for (
size_t i = 0; i < tr.
nsp_; i++) {
919 const std::vector<std::string> &names,
926 std::map<std::string, LiquidTransportData> datatable;
927 std::map<std::string, LiquidTransportData>::iterator it;
930 size_t nsp = trParam.
nsp_;
933 size_t nBinInt = nsp*(nsp-1)/2;
938 for (
size_t i = 0; i < nsp; i++) {
958 for (
size_t iChild = 0; iChild < num; iChild++) {
960 std::string nodeName = xmlChild.
name();
966 case TP_IONCONDUCTIVITY:
969 case TP_MOBILITYRATIO: {
970 for (
size_t iSpec = 0; iSpec< nBinInt; iSpec++) {
972 std::string specName = propSpecNode.
name();
973 size_t loc = specName.find(
":");
974 std::string firstSpec = specName.substr(0,loc);
975 std::string secondSpec = specName.substr(loc+1);
981 case TP_SELFDIFFUSION: {
982 for (
size_t iSpec = 0; iSpec< nsp; iSpec++) {
984 std::string specName = propSpecNode.
name();
985 size_t index = temp_thermo->
speciesIndex(specName.c_str());
1002 case TP_HYDRORADIUS:
1016 throw CanteraError(
"getLiquidSpeciesTransportData",
"unknown transport property: " + nodeName);
1020 datatable.insert(pair<std::string, LiquidTransportData>(name,data));
1029 for (
size_t i = 0; i < trParam.
nsp_; i++) {
1034 it = datatable.find(names[i]);
1035 if (it == datatable.end()) {
1036 throw TransportDBError(0,
"No transport data found for species " + names[i]);
1044 trParam.
LTData.push_back(trdat);
1059 const std::vector<std::string> &names,
1064 size_t nsp = trParam.
nsp_;
1065 size_t nBinInt = nsp*(nsp-1)/2;
1068 for (
size_t iChild = 0; iChild < num; iChild++) {
1071 std::string nodeName = tranTypeNode.
name();
1077 if (tranTypeNode.
hasChild(
"compositionDependence")) {
1079 XML_Node& compDepNode = tranTypeNode.
child(
"compositionDependence");
1085 case TP_IONCONDUCTIVITY:
1090 case TP_MOBILITYRATIO: {
1091 for (
size_t iSpec = 0; iSpec< nBinInt; iSpec++) {
1093 string specName = propSpecNode.
name();
1094 size_t loc = specName.find(
":");
1095 string firstSpec = specName.substr(0,loc);
1096 string secondSpec = specName.substr(loc+1);
1104 case TP_SELFDIFFUSION: {
1105 for (
size_t iSpec = 0; iSpec< nsp; iSpec++) {
1107 string specName = propSpecNode.
name();
1108 size_t index = temp_thermo->
speciesIndex(specName.c_str());
1115 case TP_THERMALCOND:
1120 case TP_DIFFUSIVITY:
1125 case TP_HYDRORADIUS:
1136 throw CanteraError(
"getLiquidInteractionsTransportData",
"unknown transport property: " + nodeName);
1148 if (tranTypeNode.
hasChild(
"velocityBasis")) {
1149 std::string velocityBasis =
1150 tranTypeNode.
child(
"velocityBasis").
attrib(
"basis");
1151 if (velocityBasis ==
"mass") {
1153 }
else if (velocityBasis ==
"mole") {
1158 int linenum = __LINE__;
1159 throw TransportDBError(linenum,
"Unknown attribute \"" + velocityBasis +
"\" for <velocityBasis> node. ");
1164 std::cout << err.
what() << std::endl;
1184 const size_t np = 50;
1186 int mode = tr.
mode_;
1187 int degree = (mode == CK_Mode ? 3 : 4);
1190 doublereal dt = (tr.
tmax - tr.
tmin)/(np-1);
1191 vector_fp tlog(np), spvisc(np), spcond(np);
1192 doublereal val, fit;
1197 for (
size_t n = 0; n < np; n++) {
1203 vector_fp c(degree + 1), c2(degree + 1);
1210 tr.
xml->XML_comment(logfile,
1211 "*** polynomial coefficients not printed (log_level < 2) ***");
1214 doublereal sqrt_T, visc, err, relerr,
1215 mxerr = 0.0, mxrelerr = 0.0, mxerr_cond = 0.0, mxrelerr_cond = 0.0;
1219 tr.
xml->XML_open(logfile,
"viscosity");
1220 tr.
xml->XML_comment(logfile,
"Polynomial fits for viscosity");
1221 if (mode == CK_Mode) {
1222 tr.
xml->XML_comment(logfile,
"log(viscosity) fit to cubic "
1223 "polynomial in log(T)");
1225 sprintf(s,
"viscosity/sqrt(T) fit to "
1226 "polynomial of degree %d in log(T)",degree);
1227 tr.
xml->XML_comment(logfile,s);
1232 doublereal cp_R, cond, w_RT, f_int, A_factor, B_factor,
1233 c1, cv_rot, cv_int, f_rot, f_trans, om11;
1234 doublereal diffcoeff;
1236 for (
size_t k = 0; k < tr.
nsp_; k++) {
1237 for (
size_t n = 0; n < np; n++) {
1250 diffcoeff = ThreeSixteenths *
1262 f_int = w_RT * diffcoeff/visc;
1263 cv_rot = tr.
crot[k];
1265 A_factor = 2.5 - f_int;
1266 B_factor = tr.
zrot[k] + TwoOverPi
1267 *(FiveThirds * cv_rot + f_int);
1268 c1 = TwoOverPi * A_factor/B_factor;
1269 cv_int = cp_R - 2.5 - cv_rot;
1271 f_rot = f_int * (1.0 + c1);
1272 f_trans = 2.5 * (1.0 - c1 * cv_rot/1.5);
1275 + f_rot * cv_rot + f_int * cv_int);
1277 if (mode == CK_Mode) {
1278 spvisc[n] = log(visc);
1279 spcond[n] = log(cond);
1291 spvisc[n] = sqrt(visc/sqrt_T);
1298 spcond[n] = cond/sqrt_T;
1299 w[n] = 1.0/(spvisc[n]*spvisc[n]);
1300 w2[n] = 1.0/(spcond[n]*spcond[n]);
1309 for (
size_t n = 0; n < np; n++) {
1310 if (mode == CK_Mode) {
1311 val = exp(spvisc[n]);
1314 sqrt_T = exp(0.5*tlog[n]);
1315 val = sqrt_T * pow(spvisc[n],2);
1320 if (fabs(err) > mxerr) {
1323 if (fabs(relerr) > mxrelerr) {
1324 mxrelerr = fabs(relerr);
1329 for (
size_t n = 0; n < np; n++) {
1330 if (mode == CK_Mode) {
1331 val = exp(spcond[n]);
1334 sqrt_T = exp(0.5*tlog[n]);
1335 val = sqrt_T * spcond[n];
1340 if (fabs(err) > mxerr_cond) {
1341 mxerr_cond = fabs(err);
1343 if (fabs(relerr) > mxrelerr_cond) {
1344 mxrelerr_cond = fabs(relerr);
1359 sprintf(s,
"Maximum viscosity absolute error: %12.6g", mxerr);
1360 tr.
xml->XML_comment(logfile,s);
1361 sprintf(s,
"Maximum viscosity relative error: %12.6g", mxrelerr);
1362 tr.
xml->XML_comment(logfile,s);
1363 tr.
xml->XML_close(logfile,
"viscosity");
1366 tr.
xml->XML_open(logfile,
"conductivity");
1367 tr.
xml->XML_comment(logfile,
"Polynomial fits for conductivity");
1368 if (mode == CK_Mode)
1369 tr.
xml->XML_comment(logfile,
"log(conductivity) fit to cubic "
1370 "polynomial in log(T)");
1372 sprintf(s,
"conductivity/sqrt(T) fit to "
1373 "polynomial of degree %d in log(T)",degree);
1374 tr.
xml->XML_comment(logfile,s);
1377 for (
size_t k = 0; k < tr.
nsp_; k++) {
1381 sprintf(s,
"Maximum conductivity absolute error: %12.6g", mxerr_cond);
1382 tr.
xml->XML_comment(logfile,s);
1383 sprintf(s,
"Maximum conductivity relative error: %12.6g", mxrelerr_cond);
1384 tr.
xml->XML_comment(logfile,s);
1385 tr.
xml->XML_close(logfile,
"conductivity");
1389 tr.
xml->XML_open(logfile,
"binary_diffusion_coefficients");
1390 tr.
xml->XML_comment(logfile,
"binary diffusion coefficients");
1391 if (mode == CK_Mode)
1392 tr.
xml->XML_comment(logfile,
"log(D) fit to cubic "
1393 "polynomial in log(T)");
1395 sprintf(s,
"D/T**(3/2) fit to "
1396 "polynomial of degree %d in log(T)",degree);
1397 tr.
xml->XML_comment(logfile,s);
1402 mxerr = 0.0, mxrelerr = 0.0;
1404 doublereal
eps, sigma;
1405 for (
size_t k = 0; k < tr.
nsp_; k++) {
1406 for (
size_t j = k; j < tr.
nsp_; j++) {
1407 for (
size_t n = 0; n < np; n++) {
1413 sigma = tr.
diam(j,k);
1416 diffcoeff = ThreeSixteenths *
1419 (
Pi * sigma * sigma * om11);
1424 doublereal fkj, fjk;
1429 if (mode == CK_Mode) {
1430 diff[n] = log(diffcoeff);
1433 diff[n] = diffcoeff/pow(t, 1.5);
1434 w[n] = 1.0/(diff[n]*diff[n]);
1441 for (
size_t n = 0; n < np; n++) {
1442 if (mode == CK_Mode) {
1448 val = pre * diff[n];
1453 if (fabs(err) > mxerr) {
1456 if (fabs(relerr) > mxrelerr) {
1457 mxrelerr = fabs(relerr);
1471 sprintf(s,
"Maximum binary diffusion coefficient absolute error:"
1473 tr.
xml->XML_comment(logfile,s);
1474 sprintf(s,
"Maximum binary diffusion coefficient relative error:"
1475 "%12.6g", mxrelerr);
1476 tr.
xml->XML_comment(logfile,s);
1477 tr.
xml->XML_close(logfile,
"binary_diffusion_coefficients");