8#include "FhMixture.tpp"
9#include <pscf/floryHuggins/FhInteraction.h>
10#include <pscf/math/LuSolver.h>
38 hasComposition_(false)
60 c_.allocate(nMonomer_);
61 w_.allocate(nMonomer_);
64 molecules_.allocate(nMolecule_);
65 mu_.allocate(nMolecule_);
66 phi_.allocate(nMolecule_);
67 for (
int i = 0; i < nMolecule_; ++i) {
79 molecules_.allocate(nMolecule_);
80 mu_.allocate(nMolecule_);
81 phi_.allocate(nMolecule_);
89 c_.allocate(nMonomer_);
90 w_.allocate(nMonomer_);
103 for (
int i = 0; i < nMolecule_ - 1; ++i) {
110 phi_[nMolecule_ -1] = 1.0 - sum;
113 hasComposition_ =
true;
116 void FhMixture::computeC()
120 for (k = 0; k < nMonomer_; ++k) {
125 double concentration;
127 for (i = 0; i < nMolecule_; ++i) {
128 FhMolecule& mol = molecules_[i];
129 concentration = phi_[i]/mol.size();
130 for (j = 0; j < molecules_[i].nClump(); ++j) {
131 k = mol.clump(j).monomerId();
132 c_[k] += concentration*mol.clump(j).size();
138 for (k = 0; k < nMonomer_; ++k) {
145 for (k = 0; k < nMonomer_; ++k) {
167 for (m = 0; m < nMolecule_; ++m) {
191 if (residual_.capacity() == 0) {
192 residual_.allocate(nMolecule_);
193 dX_.allocate(nMolecule_);
194 dWdC_.allocate(nMonomer_, nMonomer_);
195 dWdPhi_.allocate(nMonomer_, nMolecule_);
196 jacobian_.allocate(nMolecule_, nMolecule_);
197 phiOld_.allocate(nMolecule_);
199 solverPtr_->allocate(nMolecule_);
209 double epsilon = 1.0E-10;
210 computeResidual(
mu, error);
213 std::cout <<
"mu[0] =" <<
mu[0] << std::endl;
214 std::cout <<
"mu[1] =" <<
mu[1] << std::endl;
215 std::cout <<
"mu_[0] =" << mu_[0] << std::endl;
216 std::cout <<
"mu_[1] =" << mu_[1] << std::endl;
217 std::cout <<
"residual[0] =" << residual_[0] << std::endl;
218 std::cout <<
"residual[1] =" << residual_[1] << std::endl;
219 std::cout <<
"error =" << error << std::endl;
222 if (error < epsilon)
return;
231 for (
int it = 0; it < 50; ++it) {
237 for (t1 = 0; t1 < nMonomer_; ++t1) {
238 for (m1 = 0; m1 < nMolecule_; ++m1) {
239 dWdPhi_(t1, m1) = 0.0;
242 for (m1 = 0; m1 < nMolecule_; ++m1) {
248 for (t2 = 0; t2 < nMonomer_; ++t2) {
249 dWdPhi_(t2, m1) += dWdC_(t2, t1)*f1;
255 for (m1 = 0; m1 < nMolecule_; ++m1) {
256 for (m2 = 0; m2 < nMolecule_; ++m2) {
257 jacobian_(m1, m2) = 0.0;
259 jacobian_(m1, m1) = 1.0/phi_[m1];
261 for (m1 = 0; m1 < nMolecule_; ++m1) {
266 for (m2 = 0; m2 < nMolecule_; ++m2) {
267 jacobian_(m1, m2) += s1*dWdPhi_(t1, m2);
273 int mLast = nMolecule_ - 1;
274 for (m1 = 0; m1 < nMolecule_; ++m1) {
275 for (m2 = 0; m2 < nMolecule_ - 1; ++m2) {
276 jacobian_(m1, m2) -= jacobian_(m1, mLast);
283 solverPtr_->computeLU(jacobian_);
284 solverPtr_->solve(residual_, dX_);
287 for (m1 = 0; m1 < nMolecule_; ++m1) {
288 phiOld_[m1] = phi_[m1];
292 bool inRange =
false;
293 for (
int j = 0; j < 5; ++j) {
297 for (m1 = 0; m1 < nMolecule_ - 1; ++m1) {
298 phi_[m1] = phiOld_[m1] - dX_[m1];
301 phi_[mLast] = 1.0 - sum;
305 for (m1 = 0; m1 < nMolecule_; ++m1) {
306 if (phi_[m1] < 0.0) inRange =
false;
307 if (phi_[m1] > 1.0) inRange =
false;
314 for (m1 = 0; m1 < nMolecule_; ++m1) {
321 xi = xi - dX_[mLast];
323 UTIL_THROW(
"Volume fractions remain out of range");
330 computeResidual(
mu, error);
333 std::cout <<
"mu[0] =" <<
mu[0] << std::endl;
334 std::cout <<
"mu[1] =" <<
mu[1] << std::endl;
335 std::cout <<
"mu_[0] =" << mu_[0] << std::endl;
336 std::cout <<
"mu_[1] =" << mu_[1] << std::endl;
337 std::cout <<
"residual[0] =" << residual_[0] << std::endl;
338 std::cout <<
"residual[1] =" << residual_[1] << std::endl;
339 std::cout <<
"error =" << error << std::endl;
342 if (error < epsilon)
return;
352 for (
int i=0; i < nMolecule_; ++i) {
353 dxi +=
mu[i] - mu_[i];
354 sum += molecules_[i].size();
357 for (
int i=0; i < nMolecule_; ++i) {
358 mu_[i] += dxi*molecules_[i].size();
363 void FhMixture::computeResidual(
DArray<double> const & mu,
double& error)
366 for (
int i = 0; i < nMolecule_; ++i) {
367 residual_[i] = mu_[i] -
mu[i];
368 if (std::abs(residual_[i]) > error) {
369 error = std::abs(residual_[i]);
383 for (
int i = 0; i < nMolecule_; ++i) {
384 size = molecules_[i].size();
385 fHelmholtz_ += phi_[i]*( log(phi_[i]) - 1.0 )/size;
392 pressure_ = -fHelmholtz_;
393 for (
int i = 0; i < nMolecule_; ++i) {
394 size = molecules_[i].size();
395 pressure_ += phi_[i]*mu_[i]/size;
407 for (
int i = 0; i < nMolecule_; ++i) {
410 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.
Flory-Huggins interaction model.
virtual void computeW(Array< double > const &c, Array< double > &w) const
Compute chemical potential from concentration.
int nMonomer() const
Get number of monomer types.
virtual void computeDwDc(Array< double > const &c, Matrix< double > &dWdC) const
Compute second derivatives of free energy.
virtual double fHelmholtz(Array< double > const &c) const
Compute excess Helmholtz free energy per monomer.
void setComposition(DArray< double > const &phi)
Set system composition.
FhMolecule & molecule(int id)
Get a molecule object (non-const reference).
void initialize(MixtureBase< WT > const &mixture)
Initialize to properties of a MixtureBase descriptor.
int nMolecule() const
Get number of molecule species (polymer + solvent).
void validate() const
Validate all data structures.
void computePhi(FhInteraction const &interaction, DArray< double > const &mu, DArray< double > const &phi, double &xi)
Compute composition from chemical potentials.
double mu(int id) const
Return chemical potential for one species.
int nMonomer() const
Get number of monomer types.
void computeMu(FhInteraction const &interaction, double xi=0.0)
Compute chemical potential from preset composition.
void computeFreeEnergy(FhInteraction const &interaction)
Compute Helmholtz free energy and pressure.
double c(int id) const
Return monomer volume fraction for one monomer type.
void setNMolecule(int nMolecule)
Set the number of molecular species and allocate memory.
void setNMonomer(int nMonomer)
Set the number of monomer types.
virtual void readParameters(std::istream &in)
Read parameters from file and initialize.
double phi(int id) const
Return molecular volume fraction for one species.
Molecular species in a homogeneous Flory-Huggins mixture.
double size() const
Total molecule size = volume / reference volume.
FhClump & clump(int id)
Get a specified FhClump.
int nClump() const
Number of monomer clumps (monomer types).
Solve Ax=b by LU decomposition of A.
Abstract descriptor for a mixture of polymer and solvent species.
Dynamically allocatable contiguous array template.
ScalarParam< Type > & read(std::istream &in, const char *label, Type &value)
Add and read a new required ScalarParam < Type > object.
void setClassName(const char *className)
Set class name string.
ParamComposite()
Constructor.
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.
double sum(Array< double > const &in)
Compute sum of array elements (real).
PSCF package top-level namespace.