PSCF v1.1
pspc/solvers/Mixture.tpp
1#ifndef PSPC_MIXTURE_TPP
2#define PSPC_MIXTURE_TPP
3
4/*
5* PSCF - Polymer Self-Consistent Field Theory
6*
7* Copyright 2016 - 2022, The Regents of the University of Minnesota
8* Distributed under the terms of the GNU General Public License.
9*/
10
11#include "Mixture.h"
12#include <pscf/mesh/Mesh.h>
13
14#include <cmath>
15
16namespace Pscf {
17namespace Pspc
18{
19
20 template <int D>
22 : ds_(-1.0),
23 meshPtr_(0),
24 unitCellPtr_(0),
25 hasStress_(false)
26 { setClassName("Mixture"); }
27
28 template <int D>
30 {}
31
32 template <int D>
33 void Mixture<D>::readParameters(std::istream& in)
34 {
35 MixtureTmpl< Polymer<D>, Solvent<D> >::readParameters(in);
36 read(in, "ds", ds_);
37
38 UTIL_CHECK(nMonomer() > 0);
39 UTIL_CHECK(nPolymer()+ nSolvent() > 0);
40 UTIL_CHECK(ds_ > 0);
41 }
42
43 template <int D>
44 void Mixture<D>::setMesh(Mesh<D> const& mesh)
45 {
46 UTIL_CHECK(nMonomer() > 0);
47 UTIL_CHECK(nPolymer()+ nSolvent() > 0);
48 UTIL_CHECK(ds_ > 0);
49
50 // Save address of mesh
51 meshPtr_ = &mesh;
52
53 // Set discretization in space and s for all polymer blocks
54 if (nPolymer() > 0) {
55 int i, j;
56 for (i = 0; i < nPolymer(); ++i) {
57 for (j = 0; j < polymer(i).nBlock(); ++j) {
58 polymer(i).block(j).setDiscretization(ds_, mesh);
59 }
60 }
61 }
62
63 // Set spatial discretization for solvents
64 if (nSolvent() > 0) {
65 for (int i = 0; i < nSolvent(); ++i) {
66 solvent(i).setDiscretization(mesh);
67 }
68 }
69
70 }
71
72 template <int D>
74 {
75
76 // Set association of unitCell to this Mixture
77 unitCellPtr_ = &unitCell;
78
79 // SetupUnitCell for all polymers
80 if (nPolymer() > 0) {
81 for (int i = 0; i < nPolymer(); ++i) {
82 polymer(i).setupUnitCell(unitCell);
83 }
84 }
85
86 hasStress_ = false;
87 }
88
89
90 /*
91 * Reset statistical segment length for one monomer type.
92 */
93 template <int D>
94 void Mixture<D>::setKuhn(int monomerId, double kuhn)
95 {
96 // Set new Kuhn length for relevant Monomer object
97 monomer(monomerId).setKuhn(kuhn);
98
99 // Update kuhn length for all blocks of this monomer type
100 for (int i = 0; i < nPolymer(); ++i) {
101 for (int j = 0; j < polymer(i).nBlock(); ++j) {
102 if (monomerId == polymer(i).block(j).monomerId()) {
103 polymer(i).block(j).setKuhn(kuhn);
104 }
105 }
106 }
107 hasStress_ = false;
108 }
109
110 /*
111 * Compute concentrations (but not total free energy).
112 */
113 template <int D>
114 void Mixture<D>::compute(DArray< RField<D> > const & wFields,
115 DArray< RField<D> > & cFields,
116 double phiTot)
117 {
118 UTIL_CHECK(meshPtr_);
119 UTIL_CHECK(mesh().size() > 0);
120 UTIL_CHECK(nMonomer() > 0);
121 UTIL_CHECK(nPolymer() + nSolvent() > 0);
122 UTIL_CHECK(wFields.capacity() == nMonomer());
123 UTIL_CHECK(cFields.capacity() == nMonomer());
124
125 int nMesh = mesh().size();
126 int nm = nMonomer();
127 int i, j, k;
128
129 // Clear all monomer concentration fields, check capacities
130 for (i = 0; i < nm; ++i) {
131 UTIL_CHECK(cFields[i].capacity() == nMesh);
132 UTIL_CHECK(wFields[i].capacity() == nMesh);
133 for (j = 0; j < nMesh; ++j) {
134 cFields[i][j] = 0.0;
135 }
136 }
137
138 // Process polymer species
139 // Solve MDE for all polymers
140 for (i = 0; i < nPolymer(); ++i) {
141 polymer(i).compute(wFields, phiTot);
142 }
143
144 // Accumulate block contributions to monomer concentrations
145 int monomerId;
146 for (i = 0; i < nPolymer(); ++i) {
147 for (j = 0; j < polymer(i).nBlock(); ++j) {
148 monomerId = polymer(i).block(j).monomerId();
149 UTIL_CHECK(monomerId >= 0);
150 UTIL_CHECK(monomerId < nm);
151 RField<D>& monomerField = cFields[monomerId];
152 RField<D> const & blockField = polymer(i).block(j).cField();
153 UTIL_CHECK(blockField.capacity() == nMesh);
154 for (k = 0; k < nMesh; ++k) {
155 monomerField[k] += blockField[k];
156 }
157 }
158 }
159
160 // Process solvent species
161 // For each solvent, call compute and accumulate cFields
162 for (i = 0; i < nSolvent(); ++i) {
163 monomerId = solvent(i).monomerId();
164 UTIL_CHECK(monomerId >= 0);
165 UTIL_CHECK(monomerId < nm);
166
167 // Compute solvent concentration
168 solvent(i).compute(wFields[monomerId], phiTot);
169
170 // Add solvent contribution to relevant monomer concentration
171 RField<D>& monomerField = cFields[monomerId];
172 RField<D> const & solventField = solvent(i).cField();
173 UTIL_CHECK(solventField.capacity() == nMesh);
174 for (k = 0; k < nMesh; ++k) {
175 monomerField[k] += solventField[k];
176 }
177
178 }
179
180 hasStress_ = false;
181 }
182
183 /*
184 * Compute total stress for this mixture.
185 */
186 template <int D>
188 {
189 int i, j;
190
191 // Initialize all stress components to zero
192 for (i = 0; i < 6; ++i) {
193 stress_[i] = 0.0;
194 }
195
196 if (nPolymer() > 0) {
197
198 // Compute stress for all polymers, after solving MDE
199 for (i = 0; i < nPolymer(); ++i) {
200 polymer(i).computeStress();
201 }
202
203 // Accumulate stress for all the polymer chains
204 for (i = 0; i < unitCellPtr_->nParameter(); ++i) {
205 for (j = 0; j < nPolymer(); ++j) {
206 stress_[i] += polymer(j).stress(i);
207 }
208 }
209
210 }
211
212 // Note: Solvent does not contribute to derivatives of f_Helmholtz
213 // with respect to unit cell parameters at fixed volume fractions.
214
215 hasStress_ = true;
216 }
217
218 template <int D>
220 {
221 // Check ensemble of all polymers
222 for (int i = 0; i < nPolymer(); ++i) {
223 if (polymer(i).ensemble() == Species::Open) {
224 return false;
225 }
226 }
227 // Check ensemble of all solvents
228 for (int i = 0; i < nSolvent(); ++i) {
229 if (solvent(i).ensemble() == Species::Open) {
230 return false;
231 }
232 }
233 // Returns true if false was never returned
234 return true;
235 }
236
237 /*
238 * Combine cFields for each block (and solvent) into one DArray
239 */
240 template <int D>
241 void
243 const
244 {
245 UTIL_CHECK(nMonomer() > 0);
246 UTIL_CHECK(nBlock() + nSolvent() > 0);
247
248 int np = nSolvent() + nBlock();
249 int nx = mesh().size();
250 int i, j;
251
252 UTIL_CHECK(blockCFields.capacity() == nBlock() + nSolvent());
253
254 // Clear all monomer concentration fields, check capacities
255 for (i = 0; i < np; ++i) {
256 UTIL_CHECK(blockCFields[i].capacity() == nx);
257 for (j = 0; j < nx; ++j) {
258 blockCFields[i][j] = 0.0;
259 }
260 }
261
262 // Process polymer species
263 int sectionId = -1;
264
265 if (nPolymer() > 0) {
266
267 // Write each block's r-grid data to blockCFields
268 for (i = 0; i < nPolymer(); ++i) {
269 for (j = 0; j < polymer(i).nBlock(); ++j) {
270 sectionId++;
271
272 UTIL_CHECK(sectionId >= 0);
273 UTIL_CHECK(sectionId < np);
274 UTIL_CHECK(blockCFields[sectionId].capacity() == nx);
275
276 blockCFields[sectionId] = polymer(i).block(j).cField();
277 }
278 }
279 }
280
281 // Process solvent species
282 if (nSolvent() > 0) {
283
284 // Write each solvent's r-grid data to blockCFields
285 for (i = 0; i < nSolvent(); ++i) {
286 sectionId++;
287
288 UTIL_CHECK(sectionId >= 0);
289 UTIL_CHECK(sectionId < np);
290 UTIL_CHECK(blockCFields[sectionId].capacity() == nx);
291
292 blockCFields[sectionId] = solvent(i).cField();
293 }
294 }
295 }
296
297} // namespace Pspc
298} // namespace Pscf
299#endif
Description of a regular grid of points in a periodic domain.
Definition: Mesh.h:61
A mixture of polymer and solvent species.
Definition: MixtureTmpl.h:27
Solvent< D > Solvent
Solvent species solver typename.
Definition: MixtureTmpl.h:40
bool isCanonical()
Is this mixture being treated in canonical ensemble?
void createBlockCRGrid(DArray< RField< D > > &blockCFields) const
Combine cFields for each block/solvent into one DArray, which is used in System.tpp to print a more d...
void setKuhn(int monomerId, double kuhn)
Reset statistical segment length for one monomer type.
void setupUnitCell(const UnitCell< D > &unitCell)
Set unit cell parameters used in solver.
void setMesh(Mesh< D > const &mesh)
Create an association with the mesh and allocate memory.
void compute(DArray< RField< D > > const &wFields, DArray< RField< D > > &cFields, double phiTot=1.0)
Compute partition functions and concentrations.
void readParameters(std::istream &in)
Read all parameters and initialize.
void computeStress()
Compute derivatives of free energy w/ respect to cell parameters.
Field of real double precision values on an FFT mesh.
Definition: RField.h:29
Base template for UnitCell<D> classes, D=1, 2 or 3.
Definition: UnitCell.h:44
int capacity() const
Return allocated size.
Definition: Array.h:159
Dynamically allocatable contiguous array template.
Definition: DArray.h:32
void setClassName(const char *className)
Set class name string.
#define UTIL_CHECK(condition)
Assertion macro suitable for serial or parallel production code.
Definition: global.h:68
C++ namespace for polymer self-consistent field theory (PSCF).