9#include <pscf/chem/MixtureBase.h>
10#include <pscf/chem/PolymerSpecies.h>
11#include <pscf/chem/SolventSpecies.h>
12#include <pscf/chem/Edge.h>
13#include <pscf/inter/Interaction.h>
14#include <pscf/math/LuSolver.h>
43 hasComposition_(false)
65 c_.allocate(nMonomer_);
66 w_.allocate(nMonomer_);
69 molecules_.allocate(nMolecule_);
70 mu_.allocate(nMolecule_);
71 phi_.allocate(nMolecule_);
72 for (
int i = 0; i < nMolecule_; ++i) {
84 molecules_.allocate(nMolecule_);
85 mu_.allocate(nMolecule_);
86 phi_.allocate(nMolecule_);
94 c_.allocate(nMonomer_);
95 w_.allocate(nMonomer_);
136 for (i = 0; i < np; ++i) {
140 for (j = 0; j < nm; ++j) {
146 for (k = 0; k < nb; ++k) {
154 for (j = 0; j < nm; ++j) {
155 if (c_[j] > 1.0E-8) {
163 for (j = 0; j < nm; ++j) {
164 if (c_[j] > 1.0E-8) {
180 for (
int is = 0; is < ns; ++is) {
184 size = solvent.
size();
205 for (
int i = 0; i < nMolecule_ - 1; ++i) {
212 phi_[nMolecule_ -1] = 1.0 - sum;
215 hasComposition_ =
true;
218 void Mixture::computeC()
222 for (k = 0; k < nMonomer_; ++k) {
227 double concentration;
229 for (i = 0; i < nMolecule_; ++i) {
230 Molecule& mol = molecules_[i];
231 concentration = phi_[i]/mol.size();
232 for (j = 0; j < molecules_[i].nClump(); ++j) {
233 k = mol.clump(j).monomerId();
234 c_[k] += concentration*mol.clump(j).size();
240 for (k = 0; k < nMonomer_; ++k) {
247 for (k = 0; k < nMonomer_; ++k) {
269 for (m = 0; m < nMolecule_; ++m) {
293 if (residual_.capacity() == 0) {
294 residual_.allocate(nMolecule_);
295 dX_.allocate(nMolecule_);
296 dWdC_.allocate(nMonomer_, nMonomer_);
297 dWdPhi_.allocate(nMonomer_, nMolecule_);
298 jacobian_.allocate(nMolecule_, nMolecule_);
299 phiOld_.allocate(nMolecule_);
301 solverPtr_->allocate(nMolecule_);
311 double epsilon = 1.0E-10;
312 computeResidual(
mu, error);
315 std::cout <<
"mu[0] =" <<
mu[0] << std::endl;
316 std::cout <<
"mu[1] =" <<
mu[1] << std::endl;
317 std::cout <<
"mu_[0] =" << mu_[0] << std::endl;
318 std::cout <<
"mu_[1] =" << mu_[1] << std::endl;
319 std::cout <<
"residual[0] =" << residual_[0] << std::endl;
320 std::cout <<
"residual[1] =" << residual_[1] << std::endl;
321 std::cout <<
"error =" << error << std::endl;
324 if (error < epsilon)
return;
333 for (
int it = 0; it < 50; ++it) {
339 for (t1 = 0; t1 < nMonomer_; ++t1) {
340 for (m1 = 0; m1 < nMolecule_; ++m1) {
341 dWdPhi_(t1, m1) = 0.0;
344 for (m1 = 0; m1 < nMolecule_; ++m1) {
350 for (t2 = 0; t2 < nMonomer_; ++t2) {
351 dWdPhi_(t2, m1) += dWdC_(t2, t1)*f1;
357 for (m1 = 0; m1 < nMolecule_; ++m1) {
358 for (m2 = 0; m2 < nMolecule_; ++m2) {
359 jacobian_(m1, m2) = 0.0;
361 jacobian_(m1, m1) = 1.0/phi_[m1];
363 for (m1 = 0; m1 < nMolecule_; ++m1) {
368 for (m2 = 0; m2 < nMolecule_; ++m2) {
369 jacobian_(m1, m2) += s1*dWdPhi_(t1, m2);
375 int mLast = nMolecule_ - 1;
376 for (m1 = 0; m1 < nMolecule_; ++m1) {
377 for (m2 = 0; m2 < nMolecule_ - 1; ++m2) {
378 jacobian_(m1, m2) -= jacobian_(m1, mLast);
385 solverPtr_->computeLU(jacobian_);
386 solverPtr_->solve(residual_, dX_);
389 for (m1 = 0; m1 < nMolecule_; ++m1) {
390 phiOld_[m1] = phi_[m1];
394 bool inRange =
false;
395 for (
int j = 0; j < 5; ++j) {
399 for (m1 = 0; m1 < nMolecule_ - 1; ++m1) {
400 phi_[m1] = phiOld_[m1] - dX_[m1];
403 phi_[mLast] = 1.0 - sum;
407 for (m1 = 0; m1 < nMolecule_; ++m1) {
408 if (phi_[m1] < 0.0) inRange =
false;
409 if (phi_[m1] > 1.0) inRange =
false;
416 for (m1 = 0; m1 < nMolecule_; ++m1) {
423 xi = xi - dX_[mLast];
425 UTIL_THROW(
"Volume fractions remain out of range");
432 computeResidual(
mu, error);
435 std::cout <<
"mu[0] =" <<
mu[0] << std::endl;
436 std::cout <<
"mu[1] =" <<
mu[1] << std::endl;
437 std::cout <<
"mu_[0] =" << mu_[0] << std::endl;
438 std::cout <<
"mu_[1] =" << mu_[1] << std::endl;
439 std::cout <<
"residual[0] =" << residual_[0] << std::endl;
440 std::cout <<
"residual[1] =" << residual_[1] << std::endl;
441 std::cout <<
"error =" << error << std::endl;
444 if (error < epsilon)
return;
454 for (
int i=0; i < nMolecule_; ++i) {
455 dxi +=
mu[i] - mu_[i];
456 sum += molecules_[i].size();
459 for (
int i=0; i < nMolecule_; ++i) {
460 mu_[i] += dxi*molecules_[i].size();
465 void Mixture::computeResidual(
DArray<double> const & mu,
double& error)
468 for (
int i = 0; i < nMolecule_; ++i) {
469 residual_[i] = mu_[i] -
mu[i];
470 if (std::abs(residual_[i]) > error) {
471 error = std::abs(residual_[i]);
485 for (
int i = 0; i < nMolecule_; ++i) {
486 size = molecules_[i].size();
487 fHelmholtz_ += phi_[i]*( log(phi_[i]) - 1.0 )/size;
494 pressure_ = -fHelmholtz_;
495 for (
int i = 0; i < nMolecule_; ++i) {
496 size = molecules_[i].size();
497 pressure_ += phi_[i]*mu_[i]/size;
509 for (
int i = 0; i < nMolecule_; ++i) {
510 Molecule const & mol = molecules_[i];
512 for (
int j = 0; j < mol.
nClump(); ++j) {
Descriptor for a block within a block polymer.
int monomerId() const
Get the monomer type id for this block.
double length() const
Get the length of this block, in the thread model.
int monomerId() const
Get the monomer type id.
void setSize(double size)
Set the size of this clump.
double size() const
Get the size (number of monomers) in this block.
void setMonomerId(int monomerId)
Set the monomer type id.
int nMonomer() const
Get number of monomer types.
double phi(int id) const
Return molecular volume fraction for one species.
double c(int id) const
Return monomer volume fraction for one monomer type.
void setComposition(DArray< double > const &phi)
Set system composition.
void setNMolecule(int nMolecule)
Set the number of molecular species and allocate memory.
void computeMu(Interaction const &interaction, double xi=0.0)
Compute chemical potential from preset composition.
int nMolecule() const
Get number of molecule species (polymer + solvent).
void setNMonomer(int nMonomer)
Set the number of monomer types.
double mu(int id) const
Return chemical potential for one species.
Molecule & molecule(int id)
Get a molecule object (non-const reference).
void computeFreeEnergy(Interaction const &interaction)
Compute Helmholtz free energy and pressure.
void computePhi(Interaction const &interaction, DArray< double > const &mu, DArray< double > const &phi, double &xi)
Compute composition from chemical potentials.
void validate() const
Validate all data structures.
void initialize(MixtureBase const &mixture)
Initialize to properties of a MixtureBase Mixture descriptor.
virtual void readParameters(std::istream &in)
Read parameters from file and initialize.
Descriptor of a molecular species in a homogeneous mixture.
Clump & clump(int id)
Get a specified Clump.
void computeSize()
Compute total molecule size by adding clump sizes.
double size() const
Total molecule size = volume / reference volume.
int nClump() const
Number of monomer clumps (monomer types).
void setNClump(int nClump)
Set the number of clumps, and allocate memory.
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.
Abstract descriptor for a mixture of polymer and solvent species.
virtual SolventSpecies const & solventSpecies(int id) const =0
Set a solvent solver object by const reference.
virtual PolymerSpecies const & polymerSpecies(int id) const =0
Get a PolymerSpecies by const reference.
int nPolymer() const
Get number of polymer species.
int nMonomer() const
Get number of monomer types.
int nSolvent() const
Get number of solvent (point particle) species.
Descriptor for a linear or acyclic branched block polymer.
virtual Edge & edge(int id)=0
Get a specified Edge (block descriptor) by non-const reference.
int nBlock() const
Number of blocks.
Descriptor for a solvent species.
int monomerId() const
Get the monomer type id.
double size() const
Get the size (number of monomers) in this solvent.
Dynamically allocatable contiguous array template.
void allocate(int capacity)
Allocate the underlying C array.
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.
Flory-Huggins theory of spatially homogeneous mixtures.
PSCF package top-level namespace.