PSCF v1.3
rpc/solvers/Propagator.tpp
1#ifndef RPC_PROPAGATOR_TPP
2#define RPC_PROPAGATOR_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 "Propagator.h"
12#include "Block.h"
13
14#include <pscf/mesh/Mesh.h>
15
16namespace Pscf {
17namespace Rpc {
18
19 using namespace Util;
20
21 /*
22 * Constructor.
23 */
24 template <int D>
26 : blockPtr_(nullptr),
27 meshPtr_(nullptr),
28 ns_(0),
29 isAllocated_(false)
30 {}
31
32 /*
33 * Destructor.
34 */
35 template <int D>
38
39 /*
40 * Allocate memory used by this propagator.
41 */
42 template <int D>
43 void Propagator<D>::allocate(int ns, const Mesh<D>& mesh)
44 {
45 UTIL_CHECK(!isAllocated_);
46 ns_ = ns;
47 meshPtr_ = &mesh;
48
49 qFields_.allocate(ns);
50 for (int i = 0; i < ns; ++i) {
51 qFields_[i].allocate(mesh.dimensions());
52 }
53 isAllocated_ = true;
54 }
55
56 /*
57 * Reallocate memory used by this propagator using new ns value.
58 */
59 template <int D>
61 {
62 UTIL_CHECK(meshPtr_);
63 UTIL_CHECK(isAllocated_);
64 UTIL_CHECK(ns_ != ns);
65 ns_ = ns;
66
67 // Deallocate all memory previously used by this propagator.
68 qFields_.deallocate();
69
70 // NOTE: The qFields_ container is a DArray<FieldT>, where FieldT
71 // is a typedef for RField<D>. The DArray::deallocate() function
72 // calls "delete [] ptr", where ptr is a pointer to the underlying
73 // C array. The C++ delete [] command calls the destructor for each
74 // RField<D> element array before deleting the array itself. The
75 // RField<D> destructor deletes the double* array that stores the
76 // field associated with each slice of the propagator.
77
78 // Allocate new memory for qFields_ using new value of ns
79 qFields_.allocate(ns);
80 for (int i = 0; i < ns; ++i) {
81 qFields_[i].allocate(meshPtr_->dimensions());
82 }
83
84 setIsSolved(false);
85 }
86
87 /*
88 * Compute initial head q-field for the thread model.
89 */
90 template <int D>
91 void Propagator<D>::computeHead()
92 {
93 UTIL_CHECK(meshPtr_);
94 int nx = meshPtr_->size();
95
96 // Reference to head of this propagator
97 FieldT& qh = qFields_[0];
98
99 // Initialize qh field to 1.0 at all grid points
100 for (int ix = 0; ix < nx; ++ix) {
101 qh[ix] = 1.0;
102 }
103
104 if (!isHeadEnd()) {
105 // Pointwise multiply tail q-fields of all sources
106 for (int is = 0; is < nSource(); ++is) {
107 if (!source(is).isSolved()) {
108 UTIL_THROW("Source not solved in computeHead");
109 }
110 FieldT const& qt = source(is).tail();
111 for (int ix = 0; ix < nx; ++ix) {
112 qh[ix] *= qt[ix];
113 }
114 }
115 }
116
117 }
118
119 /*
120 * Compute initial head q-field for the bead model.
121 */
122 template <int D>
123 void Propagator<D>::assign(FieldT& lhs, FieldT const & rhs)
124 {
125 int nx = lhs.capacity();
126 UTIL_CHECK(rhs.capacity() == nx);
127 for (int ix = 0; ix < nx; ++ix) {
128 lhs[ix] = rhs[ix];
129 }
130 }
131
132 /*
133 * Solve the modified diffusion equation for this block.
134 */
135 template <int D>
137 {
138 UTIL_CHECK(blockPtr_);
140
141 // Initialize head as pointwise product of source propagators
142 computeHead();
143
145
146 // MDE step loop for thread model
147 for (int iStep = 0; iStep < ns_ - 1; ++iStep) {
148 block().stepThread(qFields_[iStep], qFields_[iStep + 1]);
149 }
150
151 } else
152 if (PolymerModel::isBead()) {
153
154 // Half-bond and bead weight for first bead
155 if (isHeadEnd()) {
156 assign(qFields_[1], qFields_[0]);
157 } else {
158 block().stepHalfBondBead(qFields_[0], qFields_[1]);
159 }
160 block().stepFieldBead(qFields_[1]);
161
162 // MDE step loop for bead model (stop before tail vertex)
163 int iStep;
164 for (iStep = 1; iStep < ns_ - 2; ++iStep) {
165 block().stepBead(qFields_[iStep], qFields_[iStep + 1]);
166 }
167
168 // Half-bond for tail slice
169 if (isTailEnd()) {
170 assign(qFields_[ns_-1], qFields_[ns_-2]);
171 } else {
172 block().stepHalfBondBead(qFields_[ns_-2], qFields_[ns_-1]);
173 }
174
175 } else {
176 // This should be impossible
177 UTIL_THROW("Unexpected PolymerModel type");
178 }
179
180 setIsSolved(true);
181 }
182
183 /*
184 * Solve the MDE with a specified initial condition at the head.
185 */
186 template <int D>
188 {
189 UTIL_CHECK(blockPtr_);
190 UTIL_CHECK(meshPtr_);
191 int nx = meshPtr_->size();
192 UTIL_CHECK(head.capacity() == nx);
193
194 // Initialize initial (head) field
195 FieldT& qh = qFields_[0];
196 for (int i = 0; i < nx; ++i) {
197 qh[i] = head[i];
198 }
199
201
202 // MDE step loop for thread model
203 for (int iStep = 0; iStep < ns_ - 1; ++iStep) {
204 block().stepThread(qFields_[iStep], qFields_[iStep + 1]);
205 }
206
207 } else
208 if (PolymerModel::isBead()) {
209
210 // Half-bond and bead weight for first bead
211 if (isHeadEnd()) {
212 assign(qFields_[1], qFields_[0]);
213 } else {
214 block().stepHalfBondBead(qFields_[0], qFields_[1]);
215 }
216 block().stepFieldBead(qFields_[1]);
217
218 // MDE step loop for bead model (stop before tail vertex)
219 int iStep;
220 for (iStep = 1; iStep < ns_ - 2; ++iStep) {
221 block().stepBead(qFields_[iStep], qFields_[iStep + 1]);
222 }
223
224 // Half-bond for tail
225 if (isTailEnd()) {
226 assign(qFields_[ns_-1], qFields_[ns_-2]);
227 } else {
228 block().stepHalfBondBead(qFields_[ns_-2], qFields_[ns_-1]);
229 }
230
231 } else {
232 // This should be impossible
233 UTIL_THROW("Unexpected PolymerModel type");
234 }
235
236 setIsSolved(true);
237 }
238
239 /*
240 * Compute spatial average of product of head and tail of partner.
241 */
242 template <int D>
244 {
245 // Preconditions
246 if (!isSolved()) {
247 UTIL_THROW("Propagator is not solved.");
248 }
249 if (!hasPartner()) {
250 UTIL_THROW("Propagator has no partner set.");
251 }
252 if (!partner().isSolved()) {
253 UTIL_THROW("Partner propagator is not solved");
254 }
256 UTIL_CHECK(meshPtr_);
257 int nx = meshPtr_->size();
258
259 double Q = 0.0;
260 if (PolymerModel::isBead() && isHeadEnd()) {
261 // Compute average of q for last bead of partner
262 FieldT const& qt = partner().q(ns_-2);
263 for (int ix = 0; ix < nx; ++ix) {
264 Q += qt[ix];
265 }
266 } else {
267 // Compute average product of head slice and partner tail slice
268 FieldT const& qh = head();
269 FieldT const& qt = partner().tail();
270 for (int ix = 0; ix < nx; ++ix) {
271 Q += qh[ix]*qt[ix];
272 }
273 }
274 Q /= double(nx);
275 return Q;
276 }
277
278}
279}
280#endif
Description of a regular grid of points in a periodic domain.
Definition Mesh.h:61
IntVec< D > dimensions() const
Get an IntVec<D> of the grid dimensions.
Definition Mesh.h:217
void solve()
Solve the modified diffusion equation (MDE) for this block.
double computeQ() const
Compute and return partition function for the polymer.
const Propagator< D > & partner() const
Get partner propagator.
bool isHeadEnd() const
Is the head vertex a chain end?
int ns() const
Get the number of values of s (or slices), including head and tail.
void allocate(int ns, const Mesh< D > &mesh)
Allocate memory used by this propagator.
void setIsSolved(bool isSolved)
Set the isSolved flag to true or false.
bool isSolved() const
Has the modified diffusion equation been solved?
bool isTailEnd() const
Is the tail vertex a chain end?
bool isAllocated() const
Has memory been allocated for this propagator?
const FieldT & head() const
Return q-field at beginning of the block (initial condition).
void reallocate(int ns)
Reallocate memory used by this propagator.
bool hasPartner() const
Does this have a partner propagator?
Block< D > const & block() const
Get the associated Block object by const reference.
RField< D > FieldT
Field type (function of position, defined on a r-space grid).
#define UTIL_CHECK(condition)
Assertion macro suitable for serial or parallel production code.
Definition global.h:68
#define UTIL_THROW(msg)
Macro for throwing an Exception, reporting function, file and line number.
Definition global.h:49
void assign(CT &z, RT const &a, RT const &b)
Create a complex number from real and imaginary parts, z = a + ib.
bool isThread()
Is the thread model in use ?
bool isBead()
Is the bead 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