PSCF v1.3
rpg/solvers/Propagator.tpp
1#ifndef RPG_PROPAGATOR_TPP
2#define RPG_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#include <prdc/cuda/resources.h>
14#include <pscf/mesh/Mesh.h>
15#include <util/containers/DArray.h>
16
17namespace Pscf {
18namespace Rpg {
19
20 using namespace Util;
21
22 /*
23 * Constructor.
24 */
25 template <int D>
27 : blockPtr_(0),
28 meshPtr_(0),
29 ns_(0),
30 isAllocated_(false)
31 {}
32
33 /*
34 * Destructor.
35 */
36 template <int D>
39
40 /*
41 * Allocate memory used by this propagator.
42 */
43 template <int D>
44 void Propagator<D>::allocate(int ns, const Mesh<D>& mesh)
45 {
46 ns_ = ns;
47 meshPtr_ = &mesh;
48
49 // Allocate memory in qFieldsAll_ using value of ns
50 int meshSize = meshPtr_->size();
51 qFieldsAll_.allocate(ns * meshSize);
52
53 // Set up array of associated RField<D> arrays
54 qFields_.allocate(ns);
55 for (int i = 0; i < ns; ++i) {
56 qFields_[i].associate(qFieldsAll_, i*meshSize, meshPtr_->dimensions());
57 }
58 isAllocated_ = true;
59 }
60
61 /*
62 * Reallocate memory used by this propagator using new ns value.
63 */
64 template <int D>
66 {
67 // Preconditions
68 UTIL_CHECK(meshPtr_);
69 UTIL_CHECK(isAllocated_);
70 UTIL_CHECK(ns_ != ns);
71 ns_ = ns;
72
73 // Deallocate memory previously used by this propagator.
74 qFields_.deallocate(); // Destroys associated RField<D> objects
75 // but not the underlying data
76 qFieldsAll_.deallocate(); // Destroy actual propagator data
77
78 // Allocate memory in qFieldsAll_ using new value of ns
79 int meshSize = meshPtr_->size();
80 qFieldsAll_.allocate(ns * meshSize);
81
82 // Set up array of associated RField<D> arrays
83 qFields_.allocate(ns);
84 for (int i = 0; i < ns; ++i) {
85 qFields_[i].associate(qFieldsAll_, i*meshSize,
86 meshPtr_->dimensions());
87 }
88
89 setIsSolved(false);
90 }
91
92 /*
93 * Compute initial head q-field from final tail q-fields of sources.
94 */
95 template <int D>
96 void Propagator<D>::computeHead()
97 {
98 UTIL_CHECK(meshPtr_);
99 int nx = meshPtr_->size();
100
101 // Initialize head field (s=0) to 1.0 at all grid points
102 VecOp::eqS(qFields_[0], 1.0);
103
104 // Multiply head q-field by tail q-fields of all sources
105 if (nSource() > 0) {
106 DArray<DeviceArray<cudaReal> const *> tails;
107 tails.allocate(nSource()+1);
108 tails[0] = &qFields_[0];
109 for (int is = 0; is < nSource(); ++is) {
110 if (!source(is).isSolved()) {
111 UTIL_THROW("Source not solved in computeHeadThread");
112 }
113 tails[is+1] = &(source(is).tail());
114 }
115 VecOp::mulVMany(qFields_[0], tails);
116 }
117 }
118
119 /*
120 * Solve the modified diffusion equation for this block.
121 */
122 template <int D>
124 {
125 UTIL_CHECK(blockPtr_);
127
128 // Initialize head, starting with product of source propagators
129 computeHead();
130
132
133 // MDE step loop for thread model
134 for (int iStep = 0; iStep < ns_ - 1; ++iStep) {
135 block().stepThread(qFields_[iStep], qFields_[iStep + 1]);
136 }
137
138 } else
139 if (PolymerModel::isBead()) {
140
141 // Half-bond and bead weight for first bead
142 if (isHeadEnd()) {
143 VecOp::eqV(qFields_[1], qFields_[0]);
144 } else {
145 block().stepHalfBondBead(qFields_[0], qFields_[1]);
146 }
147 block().stepFieldBead(qFields_[1]);
148
149 // MDE step loop for bead model (stop before tail vertex)
150 int iStep;
151 for (iStep = 1; iStep < ns_ - 2; ++iStep) {
152 block().stepBead(qFields_[iStep], qFields_[iStep + 1]);
153 }
154
155 // Half-bond for tail slice
156 if (isTailEnd()) {
157 VecOp::eqV(qFields_[ns_-2], qFields_[ns_-2]);
158 } else {
159 block().stepHalfBondBead(qFields_[ns_-2], qFields_[ns_-1]);
160 }
161
162 } else {
163 // This should be impossible
164 UTIL_THROW("Unexpected PolymerModel type");
165 }
166
167 setIsSolved(true);
168 }
169
170 /*
171 * Solve the modified diffusion equation with specified initial field.
172 */
173 template <int D>
175 {
177
178 // Initialize head slice (index 0)
179 VecOp::eqV(qFields_[0], head);
180
182
183 // MDE step loop for thread model
184 for (int iStep = 0; iStep < ns_ - 1; ++iStep) {
185 block().stepThread(qFields_[iStep], qFields_[iStep + 1]);
186 }
187
188 } else
189 if (PolymerModel::isBead()) {
190
191 // Half-bond and bead weight for first bead
192 if (isHeadEnd()) {
193 VecOp::eqV(qFields_[1], qFields_[0]);
194 } else {
195 block().stepHalfBondBead(qFields_[0], qFields_[1]);
196 }
197 block().stepFieldBead(qFields_[1]);
198
199 // MDE step loop for bead model (stop before tail vertex)
200 int iStep;
201 for (iStep = 1; iStep < ns_ - 2; ++iStep) {
202 block().stepBead(qFields_[iStep], qFields_[iStep + 1]);
203 }
204
205 // Half-bond for tail slice
206 if (!isTailEnd()) {
207 VecOp::eqV(qFields_[ns_-2], qFields_[ns_-2]);
208 } else {
209 block().stepHalfBondBead(qFields_[ns_-2], qFields_[ns_-1]);
210 }
211
212 } else {
213 // This should be impossible
214 UTIL_THROW("Unexpected PolymerModel type");
215 }
216 setIsSolved(true);
217 }
218
219 /*
220 * Integrate to calculate monomer concentration for this block
221 */
222 template <int D>
224 {
225 // Preconditions
226 UTIL_CHECK(meshPtr_);
227 UTIL_CHECK(isAllocated_);
228 if (!isSolved()) {
229 UTIL_THROW("Propagator is not solved.");
230 }
231 if (!hasPartner()) {
232 UTIL_THROW("Propagator has no partner set.");
233 }
234 if (!partner().isSolved()) {
235 UTIL_THROW("Partner propagator is not solved");
236 }
238
239 double Q = 0.0;
240 if (PolymerModel::isBead() && isHeadEnd()) {
241 // Compute average of q for last bead of partner
242 RField<D> const & qt = partner().q(ns_-2);
243 Q = Reduce::sum(qt);
244 } else {
245 // Compute average product of head slice and partner tail slice
246 RField<D> const & qh = head();
247 RField<D> const & qt = partner().tail();
248 Q = Reduce::innerProduct(qh, qt);
249 }
250 Q /= double(meshPtr_->size());
251 return Q;
252 }
253
254}
255}
256#endif
257
Description of a regular grid of points in a periodic domain.
Definition Mesh.h:61
int size() const
Get total number of grid points.
Definition Mesh.h:229
Field of real double precision values on an FFT mesh.
Definition cpu/RField.h:29
Block< D > & block()
Get the associated Block object by reference.
int ns() const
Get the number of values of s (or slices), including head and tail.
const Propagator< D > & partner() const
Get partner propagator.
void solve()
Solve the modified diffusion equation (MDE) for this block.
bool isHeadEnd() const
Is the head vertex a chain end?
double computeQ()
Compute and return partition function for the molecule.
void allocate(int ns, const Mesh< D > &mesh)
Allocate propagator arrays.
RField< D > const & head()
Return q-field at initial (head) vertex.
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?
bool hasPartner() const
Does this have a partner propagator?
void reallocate(int ns)
Reallocate memory used by this propagator.
Dynamically allocatable contiguous array template.
Definition DArray.h:32
void allocate(int capacity)
Allocate the underlying C array.
Definition DArray.h:199
#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
bool isThread()
Is the thread model in use ?
bool isBead()
Is the bead model in use ?
void eqV(DeviceArray< cudaReal > &a, DeviceArray< cudaReal > const &b, const int beginIdA, const int beginIdB, const int n)
Vector assignment, a[i] = b[i], kernel wrapper (cudaReal).
Definition VecOp.cu:1039
void eqS(DeviceArray< cudaReal > &a, const cudaReal b, const int beginIdA, const int n)
Vector assignment, a[i] = b, kernel wrapper (cudaReal).
Definition VecOp.cu:1073
void mulVMany(DeviceArray< cudaReal > &a, DArray< DeviceArray< cudaReal > > const &vecs)
Multiply an undefined number of vectors pointwise, kernel wrapper.
Definition VecOpMisc.cu:525
SCFT and PS-FTS with real periodic fields (GPU)
PSCF package top-level namespace.
Definition param_pc.dox:1