34 if (j.contains(
"alpha")){ j.at(
"alpha").get_to(o.
alpha); }
35 if (j.contains(
"rtol")){ j.at(
"rtol").get_to(o.
rtol); }
36 if (j.contains(
"atol")){ j.at(
"atol").get_to(o.
atol); }
37 if (j.contains(
"max_iters")){ j.at(
"max_iters").get_to(o.
max_iters); }
51 using CompSite = std::tuple<std::size_t, std::string>;
68 ind.
N_sites.resize(molecule_sites.size());
73 std::size_t icomp = 0;
74 std::size_t siteid = 0;
75 for (
auto& molecule: molecule_sites){
77 std::map<std::string, int> site_counts;
78 for (
auto& site: molecule){
81 auto unique_sites_on_molecule = std::set(molecule.begin(), molecule.end());
86 std::size_t Cindex = 0;
87 for (
auto& site: unique_sites_on_molecule){
92 ind.
counts[siteid] = site_counts[site];
93 ind.
comp_index[siteid] =
static_cast<int>(icomp);
97 ind.
N_sites[icomp] =
static_cast<int>(molecule.size());
98 ind.
N_unique_sites[icomp] =
static_cast<int>(unique_sites_on_molecule.size());
102 ind.
counts.conservativeResize(siteid);
110 auto make_D(
const IndexMapper& ind,
const AssociationOptions&
options )
const{
112 auto get_DIJ = [&ind, &
options](std::size_t I, std::size_t J) ->
int {
118 auto [ph2, typej] = ind.to_CompSite.at(J);
119 auto contains = [](
auto& container,
const auto& val){
return std::find(container.begin(), container.end(), val) != container.end(); };
122 return ind.counts[J];
127 int Ngroups =
static_cast<int>(ind.to_siteid.size());
128 Eigen::ArrayXXi
D(Ngroups, Ngroups);
130 for (
int I = 0; I < Ngroups; ++I){
131 for (
int J = 0; J < Ngroups; ++J){
132 D(I, J) = get_DIJ(I, J);
144 const Eigen::ArrayXXi
D;
147 Association(
const Eigen::ArrayXd&
b_m3mol,
const Eigen::ArrayXd&
beta,
const Eigen::ArrayXd&
epsilon_Jmol,
const std::vector<std::vector<std::string>>& molecule_sites,
const AssociationOptions&
options) :
b_m3mol(
b_m3mol),
beta(
beta),
epsilon_Jmol(
epsilon_Jmol),
options(
options),
mapper(make_mapper(molecule_sites,
options)),
D(make_D(
mapper,
options)),
m_radial_dist(
options.
radial_dist){
156 template<
typename TType,
typename RhoType,
typename MoleFracsType>
157 auto get_Delta(
const TType& T,
const RhoType& rhomolar,
const MoleFracsType& molefracs)
const {
159 using resulttype = std::common_type_t<
decltype(T),
decltype(rhomolar),
decltype(molefracs[0])>;
160 using Mat = Eigen::Array<resulttype, Eigen::Dynamic, Eigen::Dynamic>;
162 auto bmix = (molefracs*
b_m3mol).sum();
163 auto eta = bmix*rhomolar/4.0;
168 g = (2.0-eta)/(2.0*(1.0-eta)*(1.0-eta)*(1.0-eta));
break;
170 g = 1.0 / (1.0 - 1.9*eta);
break;
172 throw std::invalid_argument(
"Bad radial distribution");
175 Mat Delta = Mat::Zero(Ngroups, Ngroups);
176 for (
auto I = 0U; I < Ngroups; ++I){
178 for (
auto J = 0U; J < Ngroups; ++J){
186 auto beta_ij = sqrt(
beta[i]*
beta[j]);
187 Delta(I, J) = g*b_ij*beta_ij*(exp(epsilon_ij_Jmol/(R_CODATA2017*T))-1.0)/N_A;
194 template<
typename TType,
typename RhoType,
typename MoleFracsType,
typename XType>
195 auto successive_substitution(
const TType& T,
const RhoType& rhomolar,
const MoleFracsType& molefracs,
const XType& X_init)
const {
197 using resulttype = std::common_type_t<
decltype(T),
decltype(rhomolar),
decltype(molefracs[0])>;
198 using Mat = Eigen::Array<resulttype, Eigen::Dynamic, Eigen::Dynamic>;
200 const Mat Delta =
get_Delta(T, rhomolar, molefracs);
204 Eigen::RowVectorX<typename MoleFracsType::Scalar> xj(Ngroups);
205 for (
auto I = 0U; I< Ngroups; ++I){
209 using rDDXtype = std::decay_t<std::common_type_t<
typename decltype(Delta)::Scalar,
decltype(rhomolar),
decltype(molefracs[0])>>;
210 Eigen::MatrixX<rDDXtype> rDDX = rhomolar*N_A*(Delta.array()*
D.cast<resulttype>().array()).matrix();
211 for (
auto j = 0; j < rDDX.rows(); ++j){
212 rDDX.row(j).array() = rDDX.row(j).array()*xj.array();
216 Eigen::ArrayX<std::decay_t<rDDXtype>>
X = X_init, Xnew;
223 auto diff = (Xnew-
X).eval().cwiseAbs().unaryExpr([](
const auto&x){
return getbaseval(x); }).eval();
225 if ((diff < tol).all()){
236 template<
typename TType,
typename RhoType,
typename MoleFracsType>
237 auto alphar(
const TType& T,
const RhoType& rhomolar,
const MoleFracsType& molefracs)
const {
244 using resulttype = std::common_type_t<
decltype(T),
decltype(rhomolar),
decltype(molefracs[0])>;
245 resulttype alpha_r_asso = 0.0;
246 for (
auto icomp = 0; icomp < molefracs.size(); ++icomp){
247 resulttype summer = 0.0;
253 summer += (log(X_A(I))- X_A(I)/2.0 + 0.5)*
static_cast<double>(
mapper.
counts(I));
255 alpha_r_asso += molefracs[icomp]*summer;
269 nlohmann::json
get_assoc_calcs(
double T,
double rhomolar,
const Eigen::ArrayXd& mole_fractions)
const{
271 using Mat = Eigen::Array<double, Eigen::Dynamic, Eigen::Dynamic>;
272 const Mat Delta =
get_Delta(T, rhomolar, mole_fractions);
273 Eigen::ArrayXd XAinit = 0.0*mole_fractions + 1.0;
276 auto fromArrayXd = [](
const Eigen::ArrayXd &x){std::valarray<double>n(x.size());
for (
auto i = 0U; i < n.size(); ++i){ n[i] = x[i];}
return n;};
277 auto fromArrayXXd = [](
const Eigen::ArrayXXd &x){
278 std::size_t N = x.rows();
279 std::vector<std::vector<double>> n; n.resize(N);
280 for (
auto i = 0U; i < N; ++i){
282 for (
auto j = 0U; j < N; ++j){
288 auto fromArrayXXi = [](
const Eigen::ArrayXXi &x){
289 std::size_t N = x.rows();
290 std::vector<std::vector<int>> n; n.resize(N);
291 for (
auto i = 0U; i < N; ++i){
293 for (
auto j = 0U; j < N; ++j){
303 {
"D", fromArrayXXi(
D.array())},
304 {
"Delta", fromArrayXXd(Delta.array())},
305 {
"X_A", fromArrayXd(XA.array())},
306 {
"note",
"X_A is the fraction of non-bonded sites for each siteid"}
const Eigen::ArrayXd epsilon_Jmol
The association energy of each molecule, in J/mol.
nlohmann::json get_assoc_calcs(double T, double rhomolar, const Eigen::ArrayXd &mole_fractions) const
Get things from the association calculations for debug purposes.
std::tuple< std::size_t, std::size_t > CompCIndex
auto get_Delta(const TType &T, const RhoType &rhomolar, const MoleFracsType &molefracs) const
const Eigen::ArrayXd beta
The volume factor, dimensionless.
std::tuple< std::size_t, std::string > CompSite
Association(const Eigen::ArrayXd &b_m3mol, const Eigen::ArrayXd &beta, const Eigen::ArrayXd &epsilon_Jmol, const std::vector< std::vector< std::string > > &molecule_sites, const AssociationOptions &options)
auto successive_substitution(const TType &T, const RhoType &rhomolar, const MoleFracsType &molefracs, const XType &X_init) const
const AssociationOptions options
const radial_dist m_radial_dist
auto alphar(const TType &T, const RhoType &rhomolar, const MoleFracsType &molefracs) const
Calculate the contribution , where the Helmholtz energy is on a molar basis, making dimensionless.
const Eigen::ArrayXd b_m3mol
The covolume b, in m^3/mol.
void from_json(const nlohmann::json &j, AssociationOptions &o)
auto getbaseval(const T &expr)
std::map< std::string, std::vector< std::string > > interaction_partners
std::vector< std::string > site_order
association::radial_dist radial_dist
Eigen::ArrayXi N_unique_sites
How many unique types of sites are on each molecule.
Eigen::ArrayXi comp_index
The pure component indices associated with each siteid.
std::map< CompSite, std::size_t > to_siteid
Eigen::ArrayXi N_sites
How many total sites are on each molecule.
std::map< CompCIndex, std::size_t > CompCIndex_to_siteid
std::map< std::size_t, CompSite > to_CompSite
std::vector< std::vector< std::string > > molecule_sites
Eigen::ArrayXi counts
An array of counts of each siteid for the entire mixture.