9#include <pscf/inter/Interaction.h>
10#include <pscf/math/LuSolver.h>
14namespace Homogeneous {
39 hasComposition_(false)
56 read<int>(in,
"nMonomer", nMonomer_);
60 read<int>(in,
"nMolecule", nMolecule_);
61 molecules_.allocate(nMolecule_);
64 for (
int i = 0; i < nMolecule_; ++i) {
75 molecules_.allocate(nMolecule_);
98 for (
int i = 0; i < nMolecule_ - 1; ++i) {
105 phi_[nMolecule_ -1] = 1.0 - sum;
108 hasComposition_ =
true;
111 void Mixture::computeC()
115 for (k = 0; k < nMonomer_; ++k) {
120 double concentration;
122 for (i = 0; i < nMolecule_; ++i) {
123 Molecule& mol = molecules_[i];
124 concentration = phi_[i]/mol.size();
125 for (j = 0; j < molecules_[i].nClump(); ++j) {
126 k = mol.clump(j).monomerId();
127 c_[k] += concentration*mol.clump(j).size();
133 for (k = 0; k < nMonomer_; ++k) {
140 for (k = 0; k < nMonomer_; ++k) {
162 for (m = 0; m < nMolecule_; ++m) {
189 dWdC_.
allocate(nMonomer_, nMonomer_);
190 dWdPhi_.
allocate(nMonomer_, nMolecule_);
191 jacobian_.
allocate(nMolecule_, nMolecule_);
204 double epsilon = 1.0E-10;
205 computeResidual(
mu, error);
208 std::cout <<
"mu[0] =" <<
mu[0] << std::endl;
209 std::cout <<
"mu[1] =" <<
mu[1] << std::endl;
210 std::cout <<
"mu_[0] =" << mu_[0] << std::endl;
211 std::cout <<
"mu_[1] =" << mu_[1] << std::endl;
212 std::cout <<
"residual[0] =" << residual_[0] << std::endl;
213 std::cout <<
"residual[1] =" << residual_[1] << std::endl;
214 std::cout <<
"error =" << error << std::endl;
217 if (error < epsilon)
return;
226 for (
int it = 0; it < 50; ++it) {
232 for (t1 = 0; t1 < nMonomer_; ++t1) {
233 for (m1 = 0; m1 < nMolecule_; ++m1) {
234 dWdPhi_(t1, m1) = 0.0;
237 for (m1 = 0; m1 < nMolecule_; ++m1) {
243 for (t2 = 0; t2 < nMonomer_; ++t2) {
244 dWdPhi_(t2, m1) += dWdC_(t2, t1)*f1;
250 for (m1 = 0; m1 < nMolecule_; ++m1) {
251 for (m2 = 0; m2 < nMolecule_; ++m2) {
252 jacobian_(m1, m2) = 0.0;
254 jacobian_(m1, m1) = 1.0/phi_[m1];
256 for (m1 = 0; m1 < nMolecule_; ++m1) {
261 for (m2 = 0; m2 < nMolecule_; ++m2) {
262 jacobian_(m1, m2) += s1*dWdPhi_(t1, m2);
268 int mLast = nMolecule_ - 1;
269 for (m1 = 0; m1 < nMolecule_; ++m1) {
270 for (m2 = 0; m2 < nMolecule_ - 1; ++m2) {
271 jacobian_(m1, m2) -= jacobian_(m1, mLast);
279 solverPtr_->
solve(residual_, dX_);
282 for (m1 = 0; m1 < nMolecule_; ++m1) {
283 phiOld_[m1] = phi_[m1];
287 bool inRange =
false;
288 for (
int j = 0; j < 5; ++j) {
292 for (m1 = 0; m1 < nMolecule_ - 1; ++m1) {
293 phi_[m1] = phiOld_[m1] - dX_[m1];
296 phi_[mLast] = 1.0 - sum;
300 for (m1 = 0; m1 < nMolecule_; ++m1) {
301 if (phi_[m1] < 0.0) inRange =
false;
302 if (phi_[m1] > 1.0) inRange =
false;
309 for (m1 = 0; m1 < nMolecule_; ++m1) {
316 xi = xi - dX_[mLast];
318 UTIL_THROW(
"Volume fractions remain out of range");
325 computeResidual(
mu, error);
328 std::cout <<
"mu[0] =" <<
mu[0] << std::endl;
329 std::cout <<
"mu[1] =" <<
mu[1] << std::endl;
330 std::cout <<
"mu_[0] =" << mu_[0] << std::endl;
331 std::cout <<
"mu_[1] =" << mu_[1] << std::endl;
332 std::cout <<
"residual[0] =" << residual_[0] << std::endl;
333 std::cout <<
"residual[1] =" << residual_[1] << std::endl;
334 std::cout <<
"error =" << error << std::endl;
337 if (error < epsilon)
return;
347 for (
int i=0; i < nMolecule_; ++i) {
348 dxi +=
mu[i] - mu_[i];
349 sum += molecules_[i].size();
352 for (
int i=0; i < nMolecule_; ++i) {
353 mu_[i] += dxi*molecules_[i].size();
358 void Mixture::computeResidual(
DArray<double> const & mu,
double& error)
361 for (
int i = 0; i < nMonomer_; ++i) {
362 residual_[i] = mu_[i] -
mu[i];
363 if (std::abs(residual_[i]) > error) {
364 error = std::abs(residual_[i]);
378 for (
int i = 0; i < nMolecule_; ++i) {
379 size = molecules_[i].size();
380 fHelmholtz_ += phi_[i]*( log(phi_[i]) - 1.0 )/size;
387 pressure_ = -fHelmholtz_;
388 for (
int i = 0; i < nMolecule_; ++i) {
389 size = molecules_[i].size();
390 pressure_ += phi_[i]*mu_[i]/size;
402 for (
int i = 0; i < nMolecule_; ++i) {
403 Molecule const & mol = molecules_[i];
405 for (
int j = 0; j < mol.
nClump(); ++j) {
int monomerId() const
Get the monomer type id.
double size() const
Get the size (number of monomers) in this block.
double c(int id) const
Return monomer volume fraction for one monomer type.
void validate() const
Validate all data structures.
Molecule & molecule(int id)
Get a molecule object (non-const reference).
virtual void readParameters(std::istream &in)
Read parameters from file and initialize.
double phi(int id) const
Return molecular volume fraction for one species.
int nMonomer() const
Get number of monomer types.
void setComposition(DArray< double > const &phi)
Set system composition.
void computePhi(Interaction const &interaction, DArray< double > const &mu, DArray< double > const &phi, double &xi)
Compute composition from chemical potentials.
void computeFreeEnergy(Interaction const &interaction)
Compute Helmholtz free energy and pressure.
int nMolecule() const
Get number of molecule species (polymer + solvent).
double mu(int id) const
Return chemical potential for one species.
void setNMonomer(int nMonomer)
Set the number of monomer types.
void computeMu(Interaction const &interaction, double xi=0.0)
Compute chemical potential from preset composition.
void setNMolecule(int nMolecule)
Set the number of molecular species and allocate memory.
Descriptor of a molecular species in a homogeneous mixture.
int nClump() const
Number of monomer clumps (monomer types).
Clump & clump(int id)
Get a specified Clump.
double size() const
Total molecule size = volume / reference volume.
Flory-Huggins excess free energy model.
virtual double fHelmholtz(Array< double > const &c) const
Compute excess Helmholtz free energy per monomer.
virtual void computeDwDc(Array< double > const &c, Matrix< double > &dWdC) const
Compute second derivatives of free energy.
virtual void computeW(Array< double > const &c, Array< double > &w) const
Compute chemical potential from concentration.
int nMonomer() const
Get number of monomer types.
Solve Ax=b by LU decomposition of A.
void allocate(int n)
Allocate memory.
void solve(Array< double > &b, Array< double > &x)
Solve Ax = b for known b to compute x.
void computeLU(const Matrix< double > &A)
Compute the LU decomposition for later use.
int capacity() const
Return allocated size.
Dynamically allocatable contiguous array template.
void allocate(int capacity)
Allocate the underlying C array.
void allocate(int capacity1, int capacity2)
Allocate memory for a matrix.
An object that can read multiple parameters from file.
void setClassName(const char *className)
Set class name string.
void readParamComposite(std::istream &in, ParamComposite &child, bool next=true)
Add and read a required child ParamComposite.
#define UTIL_CHECK(condition)
Assertion macro suitable for serial or parallel production code.
#define UTIL_THROW(msg)
Macro for throwing an Exception, reporting function, file and line number.
#define UTIL_ASSERT(condition)
Assertion macro suitable for debugging serial or parallel code.
C++ namespace for polymer self-consistent field theory (PSCF).
Utility classes for scientific computation.