PSCF v1.4.0
pscf/correlation/Mixture.tpp
1/*
2* PSCF - Polymer Self-Consistent Field
3*
4* Copyright 2015 - 2025, The Regents of the University of Minnesota
5* Distributed under the terms of the GNU General Public License.
6*/
7
8#include "Mixture.h"
9#include "Polymer.h"
10
11#include <pscf/chem/MixtureBase.h>
12#include <pscf/chem/SolventSpecies.h>
13
14#include <util/global.h>
15
16#include "Polymer.tpp"
17
18namespace Pscf {
19namespace Correlation {
20
21 using namespace Util;
22
23 /*
24 * Default constructor.
25 */
26 template <typename WT>
28 : mixturePtr_(nullptr)
29 {}
30
31 /*
32 * Constructor.
33 */
34 template <typename WT>
36 : mixturePtr_(&mixture)
37 {}
39 /*
40 * Destructor.
41 */
42 template <typename WT>
45
46 /*
47 * Create an association with a Mixture.
48 */
49 template <typename WT>
51 {
52 UTIL_CHECK(!mixturePtr_);
53 mixturePtr_ = &mixture;
54 }
55
56 /*
57 * Allocate memory.
58 */
59 template <typename WT>
61 {
62 // Constant and preconditions
63 UTIL_CHECK(mixturePtr_);
64 const int nMonomer = mixture().nMonomer();
65 const int nPolymer = mixture().nPolymer();
66 UTIL_CHECK(nMonomer > 0);
67 UTIL_CHECK(nPolymer > 0);
68 UTIL_CHECK(!polymers_.isAllocated());
69
70 // Allocation
71 polymers_.allocate(nPolymer);
72 for (int i = 0; i < nPolymer; ++i) {
73 polymers_[i].associate(mixture().polymerSpecies(i));
74 polymers_[i].allocate(nMonomer);
75 }
76 }
77
78 /*
79 * Compute mutable state variables by calling setup for all polymers.
80 */
81 template <typename WT>
83 {
84 UTIL_CHECK(mixturePtr_);
86 const int nMonomer = mixture().nMonomer();
87 const int nPolymer = mixture().nPolymer();
88 UTIL_CHECK(nMonomer > 0);
89 UTIL_CHECK(nPolymer > 0);
90 UTIL_CHECK(polymers_.capacity() == nPolymer);
91
92 // Construct array of segment lengths, indexed by monomer type
93 DArray<double> kuhn;
94 kuhn.allocate(nMonomer);
95 for (int i = 0; i < nMonomer; ++i) {
96 kuhn[i] = mixture().monomer(i).kuhn();
97 }
98
99 // Setup all Correlation::Polymer objects
100 for (int i = 0; i < nPolymer; ++i) {
101 polymers_[i].setup(kuhn);
102 }
103
104 }
105
106 /*
107 * Compute an array of Omega(k) values for one monomer type pair.
108 */
109 template <typename WT>
110 void Mixture<WT>::computeOmega(int ma, int mb,
111 Array<double> const & kSq,
112 Array<double> & correlations) const
113 {
114 // Constants
115 const double vMonomer = mixture().vMonomer();
116 const int nPolymer = mixture().nPolymer();
117 const int nSolvent = mixture().nSolvent();
118 const int nk = kSq.capacity();
119
120 // Preconditions
121 UTIL_CHECK(nPolymer > 0);
122 UTIL_CHECK(polymers_.capacity() == nPolymer);
123 UTIL_CHECK(nSolvent >= 0);
124 UTIL_CHECK(nk > 0);
125 UTIL_CHECK(correlations.capacity() == nk);
126
127 // Initialize correlations array to zero
128 for (int j = 0; j < nk; ++j){
129 correlations[j] = 0.0;
130 }
131
132 // Loop over polymer species
133 double phi, length, c;
134 int ip; // polymer species index
135 int nA, nB; // number of blocks of types ma and mb
136 int ja, jb; // block indices
137 int ia, ib; // loop indices
138 for (ip = 0; ip < nPolymer; ip++){
139
140 // Polymer properties
141 Polymer<WT> const & polymer = polymers_[ip];
142 phi = polymer.phi();
143 length = polymer.totalLength();
144 c = phi/(length*vMonomer);
145
146 if (ma == mb) {
147
148 // Case: Equal monomer type indices
149 nA = polymer.blockIds(ma).size(); // # of blocks of type ma
150 if (nA > 0) {
151 // Intrablock contribution
152 for (ia = 0; ia < nA; ++ia) {
153 ja = polymer.blockIds(ma)[ia]; // block index
154 polymer.computeOmega(ja, ja, c, kSq, correlations);
155 }
156 if (nA > 1) {
157 // If the polymer contains multiple blocks of type ma,
158 // compute inter-block contributions
159 for (ia = 0; ia < nA; ++ia) {
160 ja = polymer.blockIds(ma)[ia]; // block index
161 for (ib = 0; ib < ia; ++ib) {
162 jb = polymer.blockIds(ma)[ib]; // block index
163 UTIL_CHECK(jb != ja);
164 polymer.computeOmega(ja, jb, 2.0*c, kSq,
165 correlations);
166 }
167 }
168 }
169 }
170
171 } else {
172
173 // Case: Unequal monomer type indices
174 nA = polymer.blockIds(ma).size(); // # of blocks of type ma
175 nB = polymer.blockIds(mb).size(); // # of blocks of type mb
176 if (nA > 0 && nB > 0) {
177 for (ia = 0; ia < nA; ++ia) {
178 ja = polymer.blockIds(ma)[ia]; // block index for ma
179 for (ib = 0; ib < nB; ++ib) {
180 jb = polymer.blockIds(mb)[ib]; // block index for mb
181 UTIL_CHECK(jb != ja);
182 polymer.computeOmega(ja, jb, c, kSq, correlations);
183 }
184 }
185 }
186
187 }
188
189 } // end loop over polymer species
190
191 // Solvent contributions (if any)
192 if (nSolvent > 0 and ma == mb) {
193 double size;
194 for (int i = 0; i < nSolvent; i++) {
195 SolventSpecies<WT> const & solvent
196 = mixture().solventSpecies(i);
197 if (solvent.monomerId() == ma) {
198 phi = solvent.phi();
199 size = solvent.size();
200 c = phi*size/vMonomer;
201 for (int i = 0; i < nk; ++i) {
202 correlations[i] += c;
203 }
204 }
205 }
206 }
207
208 }
209
210 /*
211 * Compute k-space array of total intramolecular correlation function.
212 */
213 template <typename WT>
215 Array<double> & correlations) const
216 {
217 // Constants
218 const double vMonomer = mixture().vMonomer();
219 const int nPolymer = mixture().nPolymer();
220 const int nSolvent = mixture().nSolvent();
221 const int nk = kSq.capacity();
222
223 // Preconditions
224 UTIL_CHECK(nPolymer > 0);
225 UTIL_CHECK(nSolvent >= 0);
226 UTIL_CHECK(nk > 0);
227 UTIL_CHECK(correlations.capacity() == nk);
228
229 // Initialize correlations to zero
230 for (int j = 0; j < nk; ++j){
231 correlations[j] = 0.0;
232 }
233
234 // Loop over polymer species
235 double phi, totalLength, c;
236 for (int ip = 0; ip < nPolymer; ip++){
237 Correlation::Polymer<WT> const & polymer = polymers_[ip];
238 phi = polymer.phi();
239 totalLength = polymer.totalLength();
240 c = phi/(totalLength*vMonomer);
241 polymer.computeOmegaTotal(c, kSq, correlations);
242 }
243
244 // Loop over solvent species (if any)
245 if (nSolvent > 0) {
246 double size;
247 for (int i = 0; i < nSolvent; i++){
248 SolventSpecies<WT> const & solvent
249 = mixture().solventSpecies(i);
250 phi = solvent.phi();
251 size = solvent.size();
252 c = phi*size/vMonomer;
253 for (int j = 0; j < nk; ++j) {
254 correlations[j] += c;
255 }
256 }
257 }
258
259 }
260
261}
262}
void allocate()
Allocate private data structures, set immutable private data.
void setup()
Set mutable private data.
void associate(MixtureBase< WT > const &mixture)
Create an association with a Mixture.
void computeOmegaTotal(Array< double > const &kSq, Array< double > &correlations) const
Compute total ideal gas density correlation functions.
MixtureBase< WT > const & mixture() const
Return reference to a descriptor for the associated mixture.
void computeOmega(int ma, int mb, Array< double > const &kSq, Array< double > &correlations) const
Compute ideal gas correlation functions for a monomer type pair.
Correlation::Polymer< RealT > const & polymer(int i) const
Intramolecular correlation analysis for one polymer Species.
Abstract descriptor for a mixture of polymer and solvent species.
Definition MixtureBase.h:58
Descriptor for a solvent species.
double size() const
Get the size (number of monomers) in this solvent.
int monomerId() const
Get the monomer type id.
WT phi() const
Get the overall volume fraction for this species.
Definition Species.h:159
Array container class template.
Definition Array.h:40
int capacity() const
Return allocated size.
Definition Array.h:144
Dynamically allocatable contiguous array template.
Definition DArray.h:32
void allocate(int capacity)
Allocate the underlying C array.
Definition DArray.h:269
File containing preprocessor macros for error handling.
#define UTIL_CHECK(condition)
Assertion macro suitable for serial or parallel production code.
Definition global.h:68
Intramolecular correlations in homogeneous systems.
PSCF package top-level namespace.