PSCF v1.4.0
pscf/correlation/Polymer.tpp
1#ifndef PSCF_CORRELATION_POLYMER_TPP
2#define PSCF_CORRELATION_POLYMER_TPP
3
4/*
5* PSCF - Polymer Self-Consistent Field
6*
7* Copyright 2015 - 2025, The Regents of the University of Minnesota
8* Distributed under the terms of the GNU General Public License.
9*/
10
11#include "Polymer.h"
12
13#include <pscf/chem/PolymerSpecies.h>
14#include <pscf/chem/Edge.h>
15#include <pscf/chem/EdgeIterator.h>
16#include <pscf/chem/PolymerModel.h>
17#include <pscf/correlation/Debye.h>
18#include <util/global.h>
19
20#include <cmath>
21
22namespace Pscf {
23namespace Correlation {
24
25 using namespace Util;
26
27 /*
28 * Default constructor.
29 */
30 template <typename WT>
32 : speciesPtr_(nullptr),
33 phi_(-1.0),
34 totalLength_(-1.0),
35 nBlock_(0)
36 {}
37
38 /*
39 * Constructor.
40 */
41 template <typename WT>
43 : speciesPtr_(&polymer),
44 phi_(-1.0),
45 totalLength_(-1.0),
46 nBlock_(0)
47 {}
48
49 /*
50 * Destructor.
51 */
52 template <typename WT>
55
56 /*
57 * Create an association with a PolymerSpecies descriptor.
58 */
59 template <typename WT>
61 { speciesPtr_ = &polymer; }
62
63 /*
64 * Allocation and initialization that depend on immutable data.
65 */
66 template <typename WT>
67 void Polymer<WT>::allocate(int nMonomer)
68 {
69 UTIL_CHECK(speciesPtr_);
70 UTIL_CHECK(nMonomer > 0);
71 nMonomer_ = nMonomer;
72 nBlock_ = species().nBlock();
73 UTIL_CHECK(nBlock_ > 0);
74
75 kuhn_.allocate(nBlock_);
76 length_.allocate(nBlock_);
77 rSq_.allocate(nBlock_, nBlock_);
78 blockIds_.allocate(nMonomer_);
79
80 // Construct blocksIds_ container
81 int monomerId;
82 for (int i = 0; i < nBlock_; ++i) {
83 monomerId = species().edge(i).monomerId();
84 UTIL_CHECK(monomerId >= 0);
85 UTIL_CHECK(monomerId < nMonomer_);
86 blockIds_[monomerId].append(i);
87 }
88 }
89
90 /*
91 * Set member variables that depends on mutable system data.
92 */
93 template <typename WT>
95 {
96 // Preconditions
97 UTIL_CHECK(speciesPtr_);
98 UTIL_CHECK(nBlock_ > 0);
99 UTIL_CHECK(kuhn.capacity() == nMonomer_);
100
101 /*
102 * Note: Array parameter kuhn contains statistical segment lengths
103 * indexed by monomer type id. Member variable kuhn_ contains segment
104 * length values for specific blocks, indexed by block id.
105 */
106
107 // Set block properties (arrays length_ and kuhn_) and totalLength_
108 int monomerId;
109 totalLength_ = 0.0;
110 for (int i = 0; i < nBlock_; ++i) {
111 Edge const & edge = species().edge(i);
113 length_[i] = edge.length();
114 } else {
115 length_[i] = (double) edge.nBead();
116 }
117 totalLength_ += length_[i];
118 monomerId = edge.monomerId();
119 // std::cout << "\n i, momonomerId, length = "
120 // << i << " " << monomerId << " " << length_[i];
121 UTIL_CHECK(monomerId >= 0);
122 UTIL_CHECK(monomerId < nMonomer_);
123 kuhn_[i] = kuhn[monomerId];
124 }
125 // std::cout << "\n totalLength = " << totalLength_;
126
127 // Set species volume fraction phi_
128 phi_ = species().phi();
129
130 // Set all diagonal elements of rSq_ matrix to zero
131 for (int ia = 0; ia < nBlock_; ++ia) {
132 rSq_(ia, ia) = 0.0;
133 }
134
135 // Compute off-diagonal elements of Rsq_
136 if (nBlock_ > 1) {
137
138 EdgeIterator<WT> edgeItr(species());
139 double kuhnA, kuhnB, kuhnC, lengthC, rsq;
140 int ia, ib, ic;
141
142 // Outer loop over block A
143 for (ia = 1; ia < nBlock_; ++ia) {
144 kuhnA = kuhn_[ia];
145
146 // Inner loop over block B (ib < ia)
147 for (ib = 0; ib < ia; ++ib) {
148 kuhnB = kuhn_[ib];
149
150 // Initialize rsq
152 rsq = 0.0;
153 } else {
154 rsq = 0.5*(kuhnA*kuhnA + kuhnB*kuhnB);
155 }
156
157 // Loop over intermediate block C, if any
158 edgeItr.begin(ia, ib);
159 while (edgeItr.notEnd()) {
160 ic = edgeItr.currentEdgeId();
161 if (ic != ia && ic != ib) {
162 lengthC = length_[ic];
163 kuhnC = kuhn_[ic];
164 rsq += lengthC * kuhnC * kuhnC;
165 // Includes two half-bonds at ends of block C
166 }
167 ++edgeItr;
168 }
169
170 // Assign matrix elements of rSq_
171 rSq_(ia, ib) = rsq;
172 rSq_(ib, ia) = rsq;
173
174 } // end loop over block B
175 } // end loop over block A
176 } // end if nBlock_ > 1
177
178 }
179
180 /*
181 * Compute and return an intramolecular correlation functions.
182 */
183 template <typename WT>
184 double Polymer<WT>::computeOmega(int ia, int ib,
185 double prefactor,
186 double kSq) const
187 {
188 // Preconditions
189 UTIL_CHECK(speciesPtr_); // check if associated
190 UTIL_CHECK(nBlock_ > 0); // check if allocated
191 UTIL_CHECK(totalLength_ > 0.0); // check if setup
192
193 double correlation;
194 double lengthA = length_[ia];
195 double kuhnA = kuhn_[ia];
196 if (ia == ib) {
198 correlation = prefactor * Correlation::dt(kSq, lengthA, kuhnA);
199 } else {
200 correlation = prefactor * Correlation::db(kSq, lengthA, kuhnA);
201 }
202 } else {
203 double lengthB = length_[ib];
204 double kuhnB = kuhn_[ib];
205 double x = std::exp( -rSq_(ia, ib) * kSq / 6.0);
206 double eA, eB;
208 eA = Correlation::et(kSq, lengthA, kuhnA);
209 eB = Correlation::et(kSq, lengthB, kuhnB);
210 } else {
211 eA = Correlation::eb(kSq, lengthA, kuhnA);
212 eB = Correlation::eb(kSq, lengthB, kuhnB);
213 }
214 correlation = prefactor * x * eA * eB;
215 }
216 return correlation;
217 }
218
219 /*
220 * Compute array of correlation function values for a pair of blocks.
221 *
222 * Parameters:
223 * - ia and ib are block indices.
224 * - kSq and correlation must have the same nonzero capacity
225 */
226 template <typename WT>
227 void Polymer<WT>::computeOmega(int ia, int ib,
228 double prefactor,
229 Array<double> const & kSq,
230 Array<double> & correlation) const
231 {
232 // Preconditions
233 UTIL_CHECK(speciesPtr_); // check if associated
234 UTIL_CHECK(nBlock_ > 0); // check if allocated
235 UTIL_CHECK(totalLength_ > 0.0); // check if setup
236 const int nk = kSq.capacity();
237 UTIL_CHECK(nk > 0);
238 UTIL_CHECK(correlation.capacity() == nk);
239
240 const double lengthA = length_[ia];
241 const double kuhnA = kuhn_[ia];
242
243 if (ia == ib) {
244 double d;
246 for (int j = 0; j < nk; ++j) {
247 d = Correlation::dt(kSq[j], lengthA, kuhnA);
248 correlation[j] += prefactor * d;
249 }
250 } else {
251 for (int j = 0; j < nk; ++j) {
252 d = Correlation::db(kSq[j], lengthA, kuhnA);
253 correlation[j] += prefactor * d;
254 }
255 }
256 } else {
257 const double lengthB = length_[ib];
258 const double kuhnB = kuhn_[ib];
259 const double alpha = -1.0*rSq_(ia, ib)/6.0;
260 double ks, x, eA, eB;
262 for (int j = 0; j < nk; ++j) {
263 ks = kSq[j];
264 x = std::exp(alpha*ks);
265 eA = Correlation::et(ks, lengthA, kuhnA);
266 eB = Correlation::et(ks, lengthB, kuhnB);
267 correlation[j] += prefactor * x * eA * eB;
268 }
269 } else {
270 for (int j = 0; j < nk; ++j) {
271 ks = kSq[j];
272 x = std::exp(alpha*ks);
273 eA = Correlation::eb(ks, lengthA, kuhnA);
274 eB = Correlation::eb(ks, lengthB, kuhnB);
275 correlation[j] += prefactor * x * eA * eB;
276 }
277 }
278 }
279 }
280
281 /*
282 * Increment k-space array of total intramolecular correlation function.
283 */
284 template <typename WT>
285 void Polymer<WT>::computeOmegaTotal(double prefactor,
286 Array<double> const & kSq,
287 Array<double> & correlation) const
288 {
289 // Preconditions
290 UTIL_CHECK(speciesPtr_);
291 UTIL_CHECK(nBlock_ > 0);
292 UTIL_CHECK(totalLength_ > 0.0);
293 int const nk = kSq.capacity();
294 UTIL_CHECK(nk > 0);
295 UTIL_CHECK(correlation.capacity() == nk);
296
297 // Compute intra-block contributions
298 double lengthA, kuhnA, d;
299 for (int ia = 0; ia < nBlock_; ++ia) {
300 lengthA = length_[ia];
301 kuhnA = kuhn_[ia];
303 for (int j = 0; j < nk; ++j) {
304 d = Correlation::dt(kSq[j], lengthA, kuhnA);
305 correlation[j] += prefactor * d;
306 }
307 } else {
308 for (int j = 0; j < nk; ++j) {
309 d = Correlation::db(kSq[j], lengthA, kuhnA);
310 correlation[j] += prefactor * d;
311 }
312 }
313 }
314
315 // Compute inter-block contributions
316 if (nBlock_ > 0) {
317 double lengthB, kuhnB, alpha, c, ks, x, eA, eB;
318 int ia, ib;
319 for (ia = 1; ia < nBlock_; ++ia) {
320 lengthA = length_[ia];
321 kuhnA = kuhn_[ia];
322 for (ib = 0; ib < ia; ++ib) {
323 lengthB = length_[ib];
324 kuhnB = kuhn_[ib];
325 alpha = -1.0*rSq_(ia, ib)/6.0;
326 c = 2.0 * prefactor;
328 for (int j = 0; j < nk; ++j) {
329 ks = kSq[j];
330 x = std::exp(alpha*ks);
331 eA = Correlation::et(ks, lengthA, kuhnA);
332 eB = Correlation::et(ks, lengthB, kuhnB);
333 correlation[j] += c * x * eA * eB;
334 }
335 } else {
336 for (int j = 0; j < nk; ++j) {
337 ks = kSq[j];
338 x = std::exp(alpha*ks);
339 eA = Correlation::eb(ks, lengthA, kuhnA);
340 eB = Correlation::eb(ks, lengthB, kuhnB);
341 correlation[j] += c * x * eA * eB;
342 }
343 }
344 }
345 }
346 }
347
348 }
349
350} // namespace Correlation
351} // namespace Pscf
352#endif
double computeOmega(int ia, int ib, double prefactor, double kSq) const
Compute intramolecular correlation function for a pair of blocks.
void associate(PolymerSpecies< WT > const &polymer)
Create association with a PolymerSpecies.
void allocate(int nMonomer)
Allocate memory and initialize immutable data.
void setup(Array< double > const &kuhn)
Set private mutable data.
void computeOmegaTotal(double prefactor, Array< double > const &kSq, Array< double > &correlations) const
Compute total intramolecular correlation function.
Edge iterator for graph associated with a polymer.
Descriptor for a block within a block polymer.
Definition Edge.h:59
int nBead() const
Get the number of beads in this block, in the bead model.
Definition Edge.h:302
int monomerId() const
Get the monomer type id for this block.
Definition Edge.h:284
double length() const
Get the length of this block, in the thread model.
Definition Edge.h:311
Descriptor for a linear or acyclic branched block polymer.
Array container class template.
Definition Array.h:40
int capacity() const
Return allocated size.
Definition Array.h:144
File containing preprocessor macros for error handling.
#define UTIL_CHECK(condition)
Assertion macro suitable for serial or parallel production code.
Definition global.h:68
double dt(double ksq, double length, double kuhn)
Compute and return intrablock correlation function (thread model)
Definition Debye.cpp:17
double et(double ksq, double length, double kuhn)
Compute and return one-sided factor for one block (thread model).
Definition Debye.cpp:53
double eb(double ksq, double nBead, double kuhn)
Compute and return one-sided factor for one block (bead model).
Definition Debye.cpp:69
double db(double ksq, double nBead, double kuhn)
Compute and return an intrablock correlation function (bead model)
Definition Debye.cpp:33
Intramolecular correlations in homogeneous systems.
bool isThread()
Is the thread model in use ?
PSCF package top-level namespace.