PSCF v1.3
rpc/fts/compressor/IntraCorrelation.tpp
1#ifndef RPC_INTRACORRELATION_TPP
2#define RPC_INTRACORRELATION_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 "IntraCorrelation.h"
12
13#include <rpc/system/System.h>
14#include <rpc/solvers/Mixture.h>
15#include <rpc/field/Domain.h>
16
17#include <prdc/cpu/FFT.h>
18#include <prdc/cpu/RField.h>
19#include <prdc/crystal/shiftToMinimum.h>
20#include <prdc/crystal/UnitCell.h>
21
22#include <pscf/mesh/MeshIterator.h>
23#include <pscf/chem/PolymerSpecies.h>
24#include <pscf/chem/Edge.h>
25#include <pscf/chem/Debye.h>
26#include <pscf/chem/EdgeIterator.h>
27
28#include <util/global.h>
29
30namespace Pscf {
31namespace Rpc{
32
33 using namespace Util;
34
35 /*
36 * Constructor.
37 */
38 template <int D>
40 : systemPtr_(&system),
41 kSize_(1)
42 {}
43
44 /*
45 * Destructor.
46 */
47 template <int D>
50
51 /*
52 * Compute k-space array of intramolecular correlation functions.
53 */
54 template<int D>
55 void
57 {
58 // Local copies of system properties
59 Mixture<D> const & mixture = system().mixture();
60 UnitCell<D> const & unitCell = system().domain().unitCell();
61 IntVec<D> const & dimensions = system().domain().mesh().dimensions();
62 const int nPolymer = mixture.nPolymer();
63 const int nSolvent = mixture.nSolvent();
64 const double vMonomer = mixture.vMonomer();
65
66 // Compute Fourier space kMeshDimensions_ and kSize_
67 FFT<D>::computeKMesh(dimensions, kMeshDimensions_, kSize_);
68 UTIL_CHECK(correlations.capacity() == kSize_);
69
70 // Allocate Gsq (k-space array of square wavenumber values)
72 Gsq.allocate(kSize_);
73
74 // Compute Gsq
75 IntVec<D> G, Gmin;
76 MeshIterator<D> iter;
77 iter.setDimensions(kMeshDimensions_);
78 for (iter.begin(); !iter.atEnd(); ++iter) {
79 G = iter.position();
80 Gmin = shiftToMinimum(G, dimensions, unitCell);
81 Gsq[iter.rank()] = unitCell.ksq(Gmin);
82 }
83
84 // Initialize correlations to zero
85 for (int i = 0; i < correlations.capacity(); ++i){
86 correlations[i] = 0.0;
87 }
88
89 double phi, cPolymer, polymerLength, rsqAB;
90 double length, lengthA, lengthB, lengthC, ksq;
91 double kuhn, kuhnA, kuhnB, kuhnC, eA, eB;
92 int monomerId, monomerIdA, monomerIdB, monomerIdC;
93 int rank;
94
95 // Loop over polymer species
96 for (int i = 0; i < nPolymer; i++){
97
98 // Local copies of polymer properties
99 PolymerSpecies const & polymer = mixture.polymerSpecies(i);
100 const int nBlock = polymer.nBlock();
101 phi = polymer.phi();
102
103 // Compute polymerLength (sum of lengths of all blocks)
104 polymerLength = 0.0;
105 for (int j = 0; j < nBlock; j++) {
107 length = polymer.edge(j).length();
108 } else {
109 length = (double) polymer.edge(j).nBead();
110 }
111 polymerLength += length;
112 }
113
114 // Compute cPolymer (polymer number concentration)
115 cPolymer = phi/(polymerLength*vMonomer);
116
117 // Compute diagonal (j = k) contributions
118 for (int j = 0; j < nBlock; j++) {
119
120 monomerId = polymer.edge(j).monomerId();
121 kuhn = mixture.monomer(monomerId).kuhn();
122
123 // Loop over ksq to increment correlations
125 length = polymer.edge(j).length();
126 for (iter.begin(); !iter.atEnd(); ++iter) {
127 rank = iter.rank();
128 ksq = Gsq[rank];
129 correlations[rank] +=
130 cPolymer * Debye::dt(ksq, length, kuhn);
131 }
132 } else {
133 length = (double) polymer.edge(j).nBead();
134 for (iter.begin(); !iter.atEnd(); ++iter) {
135 rank = iter.rank();
136 ksq = Gsq[rank];
137 correlations[rank] +=
138 cPolymer * Debye::db(ksq, length, kuhn);
139 }
140 }
141
142 }
143
144 // Compute off-diagonal contributions
145 if (nBlock > 1) {
146 EdgeIterator edgeItr(polymer);
147
148 // Outer loop over blocks
149 for (int ia = 1; ia < nBlock; ++ia) {
150
151 // Block A properties
152 Edge const & edgeA = polymer.edge(ia);
154 lengthA = edgeA.length();
155 } else {
156 lengthA = (double) edgeA.nBead();
157 }
158 monomerIdA = edgeA.monomerId();
159 kuhnA = mixture.monomer(monomerIdA).kuhn();
160
161 // Inner loop over blocks
162 for (int ib = 0; ib < ia; ++ib) {
163
164 // Block B properties
165 Edge const & edgeB = polymer.edge(ib);
167 lengthB = edgeB.length();
168 } else {
169 lengthB = (double) edgeB.nBead();
170 }
171 monomerIdB = edgeB.monomerId();
172 kuhnB = mixture.monomer(monomerIdB).kuhn();
173
174 // Initialize rsqAB
176 rsqAB = 0.0;
177 } else {
178 rsqAB = 0.5*(kuhnA*kuhnA + kuhnB*kuhnB);
179 }
180
181 // Iterate over intermediate blocks, if any
182 int edgeId;
183 edgeItr.begin(ia, ib);
184 while (edgeItr.notEnd()) {
185 edgeId = edgeItr.currentEdgeId();
186 Edge const & edgeC = polymer.edge(edgeId);
187 monomerIdC = edgeC.monomerId();
188 kuhnC = mixture.monomer(monomerIdC).kuhn();
189 if (edgeId != ia && edgeId != ib) {
191 lengthC = edgeC.length();
192 } else {
193 lengthC = double(edgeC.nBead());
194 }
195 rsqAB += lengthC * kuhnC * kuhnC;
196 }
197 ++edgeItr;
198 }
199
200 // Loop over ksq to increment intra-block correlations
201 double x;
202 double prefactor = 2.0*cPolymer;
204 for (iter.begin(); !iter.atEnd(); ++iter) {
205 rank = iter.rank();
206 ksq = Gsq[rank];
207 x = std::exp( -rsqAB * ksq / 6.0);
208 eA = Debye::et(ksq, lengthA, kuhnA);
209 eB = Debye::et(ksq, lengthB, kuhnB);
210 correlations[rank] += prefactor * x * eA * eB;
211 }
212 } else {
213 for (iter.begin(); !iter.atEnd(); ++iter) {
214 rank = iter.rank();
215 ksq = Gsq[rank];
216 x = std::exp( -rsqAB * ksq / 6.0);
217 eA = Debye::eb(ksq, lengthA, kuhnA);
218 eB = Debye::eb(ksq, lengthB, kuhnB);
219 correlations[rank] += prefactor * x * eA * eB;
220 }
221 }
222
223 } // loop: block ib
224 } // loop: block ia
225 } // if (nBlock > 1)
226
227 } // loop over polymer species
228
229 // Loop over solvent species (if any)
230 if (nSolvent > 0) {
231 double size, dcorr;
232 for (int i = 0; i < nSolvent; i++){
233 Solvent<D> const & solvent = mixture.solvent(i);
234 phi = solvent.phi();
235 size = solvent.size();
236 dcorr = phi*size/vMonomer;
237 for (iter.begin(); !iter.atEnd(); ++iter) {
238 correlations[iter.rank()] += dcorr;
239 }
240 }
241 }
242
243 }
244
245}
246}
247#endif
Edge iterator for graph associated with a polymer.
int currentEdgeId() const
Get index of the current edge.
bool notEnd() const
Return true iff currentId != targetId.
void begin(int sourceId, int targetId)
Initialize iterator.
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
An IntVec<D, T> is a D-component vector of elements of integer type T.
Definition IntVec.h:27
Iterator over points in a Mesh<D>.
int rank() const
Get the rank of current element.
void begin()
Set iterator to the first point in the mesh.
bool atEnd() const
Is this the end (i.e., one past the last point)?
void setDimensions(const IntVec< D > &dimensions)
Set the grid dimensions in all directions.
IntVec< D > position() const
Get current position in the grid, as integer vector.
double kuhn() const
Statistical segment length (random walk step size).
Definition Monomer.h:131
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.
static void computeKMesh(IntVec< D > const &rMeshDimensions, IntVec< D > &kMeshDimensions, int &kSize)
Compute dimensions and size of k-space mesh for DFT of real data.
Definition cpu/FFT.tpp:262
Field of real double precision values on an FFT mesh.
Definition cpu/RField.h:29
SolventT & solvent(int id)
Get a solvent solver object.
PolymerSpecies const & polymerSpecies(int id) const final
Get a PolymerSpecies descriptor by const reference.
virtual double ksq(IntVec< D > const &k) const
Compute square magnitude of reciprocal lattice vector.
Base template for UnitCell<D> classes, D=1, 2 or 3.
Definition UnitCell.h:56
void computeIntraCorrelations(RField< D > &correlations)
Compute and modify intramolecular correlations.
System< D > & system()
Return reference to parent system.
IntraCorrelation(System< D > &system)
Constructor.
Solver and descriptor for a mixture of polymers and solvents.
int nPolymer() const
Get number of polymer species.
Monomer const & monomer(int id) const
Get a Monomer type descriptor by const reference.
int nSolvent() const
Get number of solvent (point particle) species.
double vMonomer() const
Get monomer reference volume (set to 1.0 by default).
Solver and descriptor for a solvent species.
double phi() const
Get the overall volume fraction for this species.
Definition Species.h:149
double size() const
Get the size (number of monomers) in this solvent.
Main class, representing one complete system.
double phi() const
Get the overall volume fraction for this species.
Definition Species.h:149
int capacity() const
Return allocated size.
Definition Array.h:159
Dynamically allocatable contiguous array template.
Definition DArray.h:32
void allocate(int capacity)
Allocate the underlying C array.
Definition DArray.h:199
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 (thread 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
bool isThread()
Is the thread model in use ?
Real periodic fields, SCFT and PS-FTS (CPU).
Definition param_pc.dox:2
PSCF package top-level namespace.
Definition param_pc.dox:1