PSCF v1.4.0
rpc/solvers/Block.tpp
1#ifndef RPC_BLOCK_TPP
2#define RPC_BLOCK_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 "Block.h"
12#include "Propagator.h"
13
14#include <prdc/cpu/WaveList.h>
15#include <prdc/cpu/FFT.h>
16#include <prdc/crystal/UnitCell.h>
17#include <prdc/crystal/shiftToMinimum.h>
18
19#include <pscf/chem/Edge.h>
20#include <pscf/mesh/Mesh.h>
21#include <pscf/mesh/MeshIterator.h>
22#include <pscf/math/IntVec.h>
23#include <pscf/solvers/BlockTmpl.tpp>
24
25#include <util/containers/DMatrix.h>
26#include <util/containers/DArray.h>
27#include <util/containers/FSArray.h>
28
29namespace Pscf {
30namespace Rpc {
31
32 // Namespaces from which names may be used without qualification
33 using namespace Util;
34 using namespace Pscf::Prdc;
35 using namespace Pscf::Prdc::Cpu;
36
37 /*
38 * Constructor.
39 */
40 template <int D>
42 : meshPtr_(nullptr),
43 fftPtr_(nullptr),
44 unitCellPtr_(nullptr),
45 waveListPtr_(nullptr),
46 kMeshDimensions_(-1),
47 kSize_(-1),
48 ds_(-1.0),
49 dsTarget_(-1.0),
50 ns_(-1),
51 nParams_(0),
52 isAllocated_(false),
53 hasExpKsq_(false)
54 {
55 propagator(0).setBlock(*this);
56 propagator(1).setBlock(*this);
57 }
58
59 /*
60 * Destructor.
61 */
62 template <int D>
65
66 /*
67 * Store addresses of mesh, FFT and unit cell.
68 */
69 template <int D>
70 void Block<D>::associate(Mesh<D> const & mesh,
71 FFT<D> const& fft,
72 UnitCell<D> const& cell,
73 WaveList<D>& waveList)
74 {
75 // Preconditions
76 UTIL_CHECK(!isAllocated_);
77
78 // Set pointers to mesh and fft
79 meshPtr_ = &mesh;
80 fftPtr_ = &fft;
81 unitCellPtr_ = &cell;
82 waveListPtr_ = &waveList;
83
84 hasExpKsq_ = false;
85 }
86
87 /*
88 * Compute number of contour steps and allocate all memory.
89 */
90 template <int D>
92 {
93 UTIL_CHECK(ds > 0.0);
94 UTIL_CHECK(meshPtr_);
95 UTIL_CHECK(fftPtr_);
96 UTIL_CHECK(unitCellPtr_);
97 UTIL_CHECK(waveListPtr_);
98 UTIL_CHECK(mesh().size() > 1);
99 UTIL_CHECK(mesh().dimensions() == fft().meshDimensions());
100 UTIL_CHECK(!isAllocated_);
101
102 // Compute DFT grid dimensions kMeshDimensions_ and size kSize_
103 FFT<D>::computeKMesh(mesh().dimensions(), kMeshDimensions_, kSize_);
104
105 // Allocate work arrays for MDE solution
106 expKsq_.allocate(kMeshDimensions_);
107 expKsq2_.allocate(kMeshDimensions_);
108 expW_.allocate(mesh().dimensions());
109 qr_.allocate(mesh().dimensions());
110 qk_.allocate(mesh().dimensions());
111 qr2_.allocate(mesh().dimensions());
112 qk2_.allocate(mesh().dimensions());
114 expW2_.allocate(mesh().dimensions());
115 } else {
116 expWInv_.allocate(mesh().dimensions());
117 }
118
119 // Allocate block concentration field
120 cField().allocate(mesh().dimensions());
121
122 dsTarget_ = ds;
123
124 // Compute ns_
126 // Set contour length discretization for this block
127 const double length = Edge::length();
128 UTIL_CHECK(length > 0.0);
129 int tempNs;
130 tempNs = floor(length / (2.0 *ds) + 0.5);
131 if (tempNs == 0) {
132 tempNs = 1; // ensure ns_ >= 3
133 }
134 ns_ = 2*tempNs + 1;
135 ds_ = length/double(ns_-1);
136 } else
137 if (PolymerModel::isBead()) {
138 ds_ = 1.0;
139 ns_ = Edge::nBead() + 2;
140 }
141
142 // Allocate memory for solutions to MDE (requires ns_)
143 propagator(0).allocate(ns_, mesh());
144 propagator(1).allocate(ns_, mesh());
145
146 isAllocated_ = true;
147 hasExpKsq_ = false;
148 }
149
150 /*
151 * Set or reset the the block length.
152 */
153 template <int D>
154 void Block<D>::setLength(double newLength)
155 {
157 Edge::setLength(newLength);
158
159 if (isAllocated_) {
160
161 int oldNs = ns_;
162
163 // Reset contour length discretization
164 UTIL_CHECK(dsTarget_ > 0);
165 const double length = Edge::length();
166 int tempNs = floor( length / (2.0 *dsTarget_) + 0.5 );
167 if (tempNs == 0) {
168 tempNs = 1;
169 }
170 ns_ = 2*tempNs + 1;
171 ds_ = length / double(ns_-1);
172
173 // Reallocate propagators if ns_ has changed
174 if (oldNs != ns_) {
175 propagator(0).reallocate(ns_);
176 propagator(1).reallocate(ns_);
177 }
178
179 }
180 hasExpKsq_ = false;
181 }
182
183 /*
184 * Set or reset the the block length.
185 */
186 template <int D>
188 {
190 hasExpKsq_ = false;
191 }
192
193 /*
194 * Clear all internal data that depends on the unit cell parameters.
195 */
196 template <int D>
198 {
199 hasExpKsq_ = false;
200 stress_.clear();
201 }
202
203 /*
204 * Compute all elements of expKsq_ and expKsq2_ arrays
205 */
206 template <int D>
207 void Block<D>::computeExpKsq()
208 {
209 UTIL_CHECK(isAllocated_);
210 UTIL_CHECK(waveListPtr_);
211
212 bool isThread = PolymerModel::isThread();
213 const double b = BlockTmplT::kuhn();
214 double bSqFactor = -1.0 * b * b / 6.0;
215 if (isThread) {
216 bSqFactor *= ds_;
217 }
218
219 // Calculate KSq if necessary
220 if (!waveList().hasKSq()) {
221 waveList().computeKSq();
222 }
223 RField<D> const & kSq = waveList().kSq();
224
225 MeshIterator<D> iter;
226 iter.setDimensions(kMeshDimensions_);
227 double arg;
228 int i;
229 for (iter.begin(); !iter.atEnd(); ++iter) {
230 i = iter.rank();
231 arg = kSq[i]*bSqFactor;
232 expKsq_[i] = exp(arg);
233 expKsq2_[i] = exp(0.5*arg);
234 }
235
236 hasExpKsq_ = true;
237 }
238
239 /*
240 * Setup the the step algorithm for a specific field configuration.
241 */
242 template <int D>
243 void
245 {
246 // Preconditions
247 int nx = mesh().size();
248 UTIL_CHECK(nx > 0);
249 UTIL_CHECK(isAllocated_);
250
251 // Compute expW arrays
252 double arg;
254 double c = -0.5*ds_;
255 for (int i = 0; i < nx; ++i) {
256 arg = c*w[i];
257 expW_[i] = exp(arg);
258 expW2_[i] = exp(0.5*arg);
259 }
260 } else
261 if (PolymerModel::isBead()) {
262 for (int i = 0; i < nx; ++i) {
263 arg = -w[i];
264 expW_[i] = exp(arg);
265 expWInv_[i] = 1.0/expW_[i];
266 }
267 }
268
269 // Compute expKsq arrays if necessary
270 if (!hasExpKsq_) {
271 computeExpKsq();
272 }
273
274 }
275
276 /*
277 * Propagate solution by one step for the thread model.
278 */
279 template <int D>
280 void Block<D>::stepThread(RField<D> const & q, RField<D>& qout) const
281 {
283
284 // Preconditions on mesh and fft
285 int nx = mesh().size();
286 UTIL_CHECK(nx > 0);
287 UTIL_CHECK(fft().isSetup());
288 UTIL_CHECK(mesh().dimensions() == fft().meshDimensions());
289
290 // Internal preconditions
291 UTIL_CHECK(isAllocated_);
292 int nk = qk_.capacity();
293 UTIL_CHECK(nk > 0);
294 UTIL_CHECK(qr_.capacity() == nx);
295 UTIL_CHECK(expW_.capacity() == nx);
296 UTIL_CHECK(expW2_.capacity() == nx);
297 UTIL_CHECK(expKsq_.capacity() == nk);
298 UTIL_CHECK(expKsq2_.capacity() == nk);
299 UTIL_CHECK(hasExpKsq_);
300
301 // Preconditions on parameters
303 UTIL_CHECK(q.capacity() == nx);
304 UTIL_CHECK(qout.isAllocated());
305 UTIL_CHECK(qout.capacity() == nx);
306
307 // Apply pseudo-spectral algorithm
308
309 // Step by ds/2 for qr_, step by ds/4 for qr2_
310 int i;
311 for (i = 0; i < nx; ++i) {
312 qr_[i] = q[i]*expW_[i];
313 qr2_[i] = q[i]*expW2_[i];
314 }
315 fft().forwardTransform(qr_, qk_);
316 fft().forwardTransform(qr2_, qk2_);
317 for (i = 0; i < nk; ++i) {
318 qk_[i][0] *= expKsq_[i];
319 qk_[i][1] *= expKsq_[i];
320 qk2_[i][0] *= expKsq2_[i];
321 qk2_[i][1] *= expKsq2_[i];
322 }
323 fft().inverseTransformUnsafe(qk_, qr_); // overwrites qk_
324 fft().inverseTransformUnsafe(qk2_, qr2_); // overwrites qk2_
325 for (i = 0; i < nx; ++i) {
326 qr_[i] = qr_[i]*expW_[i];
327 qr2_[i] = qr2_[i]*expW_[i];
328 }
329
330 // Above, multiplying qr2_ by expW_, rather than by expW2_, combines
331 // required multiplications by expW2_ at the end of first half-step
332 // and at the beginning of the second.
333
334 // Finish second half-step of ds/2 for qr2_
335 fft().forwardTransform(qr2_, qk2_);
336 for (i = 0; i < nk; ++i) {
337 qk2_[i][0] *= expKsq2_[i];
338 qk2_[i][1] *= expKsq2_[i];
339 }
340 fft().inverseTransformUnsafe(qk2_, qr2_); // overwrites qk2_
341 for (i = 0; i < nx; ++i) {
342 qr2_[i] = qr2_[i]*expW2_[i];
343 }
344
345 // Richardson extrapolation
346 for (i = 0; i < nx; ++i) {
347 qout[i] = (4.0*qr2_[i] - qr_[i])/3.0;
348 }
349
350 }
351
352 /*
353 * Apply one step of MDE solution for the bead model.
354 */
355 template <int D>
356 void Block<D>::stepBead(RField<D> const & q, RField<D>& qout) const
357 {
359 stepBondBead(q, qout);
360 stepFieldBead(qout);
361 }
362
363 /*
364 * Apply the bond operator for the bead model.
365 */
366 template <int D>
367 void Block<D>::stepBondBead(RField<D> const & q, RField<D>& qout) const
368 {
369 // Prereconditions
370 UTIL_CHECK(isAllocated_);
371 UTIL_CHECK(hasExpKsq_);
372 int nx = mesh().size();
373 UTIL_CHECK(nx > 0);
374 UTIL_CHECK(q.capacity() == nx);
375 UTIL_CHECK(qout.capacity() == nx);
376 int nk = qk_.capacity();
377 UTIL_CHECK(nk > 0);
378 UTIL_CHECK(expKsq_.capacity() == nk);
379
380 // Apply bond operator
381 fft().forwardTransform(q, qk_);
382 for (int i = 0; i < nk; ++i) {
383 qk_[i][0] *= expKsq_[i];
384 qk_[i][1] *= expKsq_[i];
385 }
386 fft().inverseTransformUnsafe(qk_, qout); // destroys qk_
387 }
388
389 /*
390 * Apply the half-bond operator for the bead model.
391 */
392 template <int D>
393 void Block<D>::stepHalfBondBead(RField<D> const & q, RField<D>& qout) const
394 {
395 // Preconditions
396 UTIL_CHECK(isAllocated_);
397 UTIL_CHECK(hasExpKsq_);
398 int nx = mesh().size();
399 UTIL_CHECK(nx > 0);
400 UTIL_CHECK(q.capacity() == nx);
401 UTIL_CHECK(qout.capacity() == nx);
402 int nk = qk_.capacity();
403 UTIL_CHECK(nk > 0);
404 UTIL_CHECK(expKsq_.capacity() == nk);
405
406 // Apply bond operator
407 fft().forwardTransform(q, qk_);
408 for (int i = 0; i < nk; ++i) {
409 qk_[i][0] *= expKsq2_[i];
410 qk_[i][1] *= expKsq2_[i];
411 }
412 fft().inverseTransformUnsafe(qk_, qout); // destroys qk_
413 }
414
415 /*
416 * Apply the local field operator for the bead model.
417 */
418 template <int D>
420 {
421 // Preconditions
422 int nx = mesh().size();
423 UTIL_CHECK(nx > 0);
424 UTIL_CHECK(expW_.capacity() == nx);
425 UTIL_CHECK(q.capacity() == nx);
426
427 // Apply field operator
428 for (int i = 0; i < nx; ++i) {
429 q[i] *= expW_[i];
430 }
431 }
432
433 /*
434 * Integrate to calculate monomer concentration for this block
435 */
436 template <int D>
438 {
439 // Preconditions
440 UTIL_CHECK(isAllocated_);
441 int nx = mesh().size();
442 UTIL_CHECK(nx > 0);
443 UTIL_CHECK(ns_ > 0);
444 UTIL_CHECK(propagator(0).isSolved());
445 UTIL_CHECK(propagator(1).isSolved());
446 UTIL_CHECK(cField().capacity() == nx);
447
448 // Initialize cField to zero at all points
449 int i;
450 for (i = 0; i < nx; ++i) {
451 cField()[i] = 0.0;
452 }
453
454 // References to forward and reverse propagators
455 Propagator<D> const & p0 = propagator(0);
456 Propagator<D> const & p1 = propagator(1);
457
458 // Evaluate unnormalized integral
459
460 // Endpoint contributions
461 for (i = 0; i < nx; ++i) {
462 cField()[i] += p0.q(0)[i]*p1.q(ns_ - 1)[i];
463 cField()[i] += p0.q(ns_ -1)[i]*p1.q(0)[i];
464 }
465
466 // Odd indices
467 int j;
468 for (j = 1; j < (ns_ -1); j += 2) {
469 RField<D> const & qf = p0.q(j);
470 RField<D> const & qr = p1.q(ns_ - 1 - j);
471 for (i = 0; i < nx; ++i) {
472 //cField()[i] += p0.q(j)[i] * p1.q(ns_ - 1 - j)[i] * 4.0;
473 cField()[i] += qf[i] * qr[i] * 4.0;
474 }
475 }
476
477 // Even indices
478 for (j = 2; j < (ns_ -2); j += 2) {
479 RField<D> const & qf = p0.q(j);
480 RField<D> const & qr = p1.q(ns_ - 1 - j);
481 for (i = 0; i < nx; ++i) {
482 // cField()[i] += p0.q(j)[i] * p1.q(ns_ - 1 - j)[i] * 2.0;
483 cField()[i] += qf[i] * qr[i] * 2.0;
484 }
485 }
486
487 // Normalize the integral
488 prefactor *= ds_ / 3.0;
489 for (i = 0; i < nx; ++i) {
490 cField()[i] *= prefactor;
491 }
492
493 }
494
495 /*
496 * Calculate monomer concentration for this block, bead model.
497 */
498 template <int D>
500 {
501 // Preconditions
502 UTIL_CHECK(isAllocated_);
503 int nx = mesh().size();
504 UTIL_CHECK(nx > 0);
505 UTIL_CHECK(ns_ > 0);
506 UTIL_CHECK(propagator(0).isSolved());
507 UTIL_CHECK(propagator(1).isSolved());
508 UTIL_CHECK(cField().capacity() == nx);
509
510 // Initialize cField to zero at all points
511 int i;
512 for (i = 0; i < nx; ++i) {
513 cField()[i] = 0.0;
514 }
515
516 // References to forward and reverse propagators
517 Propagator<D> const & p0 = propagator(0);
518 Propagator<D> const & p1 = propagator(1);
519
520 // Sum over beads (j = 1, ... , ns_ -2)
521 int j;
522 for (j = 1; j < (ns_ -1); ++j) {
523 RField<D> const & qf = p0.q(j);
524 RField<D> const & qr = p1.q(ns_ - 1 - j);
525 for (i = 0; i < nx; ++i) {
526 cField()[i] += qf[i] * qr[i] * expWInv_[i];
527 }
528 }
529
530 // Normalize the integral
531 for (i = 0; i < nx; ++i) {
532 cField()[i] *= prefactor;
533 }
534 }
535
536 /*
537 * Integrate to compute stress exerted by this block (thread).
538 */
539 template <int D>
540 void Block<D>::computeStressThread(double prefactor)
541 {
542 // Preconditions
544 int nx = mesh().size();
545 UTIL_CHECK(nx > 0);
546 UTIL_CHECK(fft().isSetup());
547 UTIL_CHECK(mesh().dimensions() == fft().meshDimensions());
548 UTIL_CHECK(ns_ > 0);
549 UTIL_CHECK(ds_ > 0);
550
551 // References to forward and reverse propagators
552 Propagator<D> const & p0 = propagator(0);
553 Propagator<D> const & p1 = propagator(1);
556
557 // If necessary, update derivatives of |k|^2 in WaveList
558 UTIL_CHECK(waveListPtr_);
559 if (!waveList().hasdKSq()) {
560 waveList().computedKSq();
561 }
562
563 // Initialize dQ work array to zero
565 const int nParam = unitCell().nParameter();
566 for (int i = 0; i < nParam; ++i) {
567 dQ.append(0.0);
568 }
569
570 // Work variables
571 const double b = BlockTmplT::kuhn();
572 const double bSq = b * b / 6.0;
573 double dels, prod, increment;
574 int m, n;
575
576 // Evaluate unnormalized integral over contour
577 for (int j = 0; j < ns_ ; ++j) {
578
579 qr_ = p0.q(j);
580 fft().forwardTransform(qr_, qk_);
581
582 qr2_ = p1.q(ns_ - 1 - j);
583 fft().forwardTransform(qr2_, qk2_);
584
585 // Compute prefactor dels for Simpson's rule
586 dels = ds_ / 3.0;
587 if (j != 0 && j != ns_ - 1) {
588 if (j % 2 == 0) {
589 dels *= 2.0;
590 } else {
591 dels *= 4.0;
592 }
593 }
594
595 // Loop over unit cell parameters
596 for (n = 0; n < nParam ; ++n) {
597 RField<D> dKSq = waveList().dKSq(n);
598 increment = 0.0;
599 // Loop over wavevectors
600 for (m = 0; m < kSize_ ; ++m) {
601 prod = (qk2_[m][0] * qk_[m][0]) + (qk2_[m][1] * qk_[m][1]);
602 prod *= dKSq[m];
603 increment += prod;
604 }
605 increment *= bSq * dels;
606 dQ[n] = dQ[n] - increment;
607 }
608
609 }
610
611 // Compute stress_ from dQ
612 stress_.clear();
613 for (int n = 0; n < nParam; ++n) {
614 stress_.append(-1.0*prefactor*dQ[n]);
615 }
616
617 }
618
619 /*
620 * Compute contribution of this block to stress for bead model.
621 */
622 template <int D>
623 void Block<D>::computeStressBead(double prefactor)
624 {
625 // Preconditions
627 int nx = mesh().size();
628 UTIL_CHECK(nx > 0);
629 UTIL_CHECK(fft().isSetup());
630 UTIL_CHECK(mesh().dimensions() == fft().meshDimensions());
631 UTIL_CHECK(ns_ > 0);
632
633 // References to forward to reverse propagators
634 Propagator<D> const & p0 = propagator(0);
635 Propagator<D> const & p1 = propagator(1);
636 UTIL_CHECK(p0.isSolved());
637 UTIL_CHECK(p1.isSolved());
638
639
640 // If necessary, update derivatives of |k|^2 in WaveList
641 UTIL_CHECK(waveListPtr_);
642 if (!waveList().hasdKSq()) {
643 waveList().computedKSq();
644 }
645
646 // Initialize dQ work array to zero
648 int nParam = unitCell().nParameter();
649 for (int i = 0; i < nParam; ++i) {
650 dQ.append(0.0);
651 }
652
653 const double b = BlockTmplT::kuhn();
654 const double bSq = b * b / 6.0;
655 double increment, prod;
656
657 // Half-bond from head junction to first bead, if not a chain end
658 if (!p0.isHeadEnd()) {
659
660 // Bead j = 0, forward propagator
661 qr_ = p0.q(0);
662 fft().forwardTransform(qr_, qk_);
663
664 // Next bead (ns_ - 2), reverse propagator
665 qr2_ = p1.q(ns_ - 2);
666 fft().forwardTransform(qr2_, qk2_);
667
668 // Loop over unit cell parameters
669 for (int n = 0; n < nParam ; ++n) {
670 RField<D> dKSq = waveList().dKSq(n);
671 increment = 0.0;
672 // Loop over wavevectors
673 for (int m = 0; m < kSize_ ; ++m) {
674 prod = (qk2_[m][0] * qk_[m][0]) + (qk2_[m][1] * qk_[m][1]);
675 prod *= dKSq[m]*expKsq2_[m];
676 increment += prod;
677 }
678 increment *= 0.5*bSq;
679 dQ[n] = dQ[n] - increment;
680 }
681 }
682
683 // Loop over nBead - 1 full bonds within this block
684 for (int j = 1; j < ns_ - 2 ; ++j) {
685
686 // Bead j, forward propagator
687 qr_ = p0.q(j);
688 fft().forwardTransform(qr_, qk_);
689
690 // Next bead (ns_- 2 - j), reverse propagator
691 qr2_ = p1.q(ns_ - 2 - j);
692 fft().forwardTransform(qr2_, qk2_);
693
694 // Loop over unit cell parameters
695 for (int n = 0; n < nParam ; ++n) {
696 RField<D> dKSq = waveList().dKSq(n);
697 increment = 0.0;
698 // Loop over wavevectors
699 for (int m = 0; m < kSize_ ; ++m) {
700 prod = (qk2_[m][0] * qk_[m][0]) + (qk2_[m][1] * qk_[m][1]);
701 prod *= dKSq[m]*expKsq_[m];
702 increment += prod;
703 }
704 increment *= bSq;
705 dQ[n] = dQ[n] - increment;
706 }
707
708 }
709
710 // Half-bond from last bead to tail junction, if not a chain end
711 if (!p0.isTailEnd()) {
712
713 // Second-to-last bead, j = ns_ - 2, forward propagator
714 qr_ = p0.q(ns_-2);
715 fft().forwardTransform(qr_, qk_);
716
717 // Last bead, j=0, reverse propagator
718 qr2_ = p1.q(0);
719 fft().forwardTransform(qr2_, qk2_);
720
721 // Loop over unit cell parameters
722 for (int n = 0; n < nParam ; ++n) {
723 RField<D> dKSq = waveList().dKSq(n);
724 increment = 0.0;
725 // Loop over wavevectors
726 for (int m = 0; m < kSize_ ; ++m) {
727 prod = (qk2_[m][0] * qk_[m][0]) + (qk2_[m][1] * qk_[m][1]);
728 prod *= dKSq[m]*expKsq2_[m];
729 increment += prod;
730 }
731 increment *= 0.5*bSq;
732 dQ[n] = dQ[n] - increment;
733 }
734
735 }
736
737 // Compute stress_ from dQ
738 stress_.clear();
739 for (int i = 0; i < nParam; ++i) {
740 stress_.append(-1.0*prefactor*dQ[i]);
741 }
742
743 }
744
745}
746}
747#endif
int nBead() const
Get the number of beads in this block, in the bead model.
Definition Edge.h:302
virtual void setLength(double length)
Set the length of this block (only valid for thread model).
Definition Edge.cpp:62
double length() const
Get the length of this block, in the thread model.
Definition Edge.h:311
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.
Description of a regular grid of points in a periodic domain.
Definition Mesh.h:61
Fourier transform wrapper.
Definition cpu/FFT.h:39
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:264
bool isAllocated() const
Return true if the FftwDArray has been allocated, false otherwise.
Definition FftwDArray.h:107
Field of real double precision values on an FFT mesh.
Definition cpu/RField.h:27
Class to compute and store properties associated with wavevectors.
Base template for UnitCell<D> classes, D=1, 2 or 3.
Definition UnitCell.h:56
bool isHeadEnd() const
Is the head vertex a chain end?
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 T::RField & q(int i) const
Return q-field at a specified step.
void stepBondBead(RField< D > const &qin, RField< D > &qout) const
Apply a bond operator for the bead model.
void setLength(double newLength)
Set or reset block length (only used in thread model).
void computeConcentrationBead(double prefactor)
Compute the concentration for this block, using the bead model.
void setKuhn(double kuhn)
Set or reset monomer statistical segment length.
void clearUnitCellData()
Clear all internal data that depends on the unit cell parameters.
void setupSolver(RField< D > const &w)
Set up the MDE solver for this block.
void allocate(double ds)
Allocate memory and set contour step size.
void computeStressBead(double prefactor)
Compute stress contribution for this block, using bead model.
Propagator< D > & propagator(int directionId)
Get a Propagator for a specified direction.
void associate(Mesh< D > const &mesh, FFT< D > const &fft, UnitCell< D > const &cell, WaveList< D > &waveList)
Create permanent associations with related objects.
void computeConcentrationThread(double prefactor)
Compute the concentration for this block, for the thread model.
void stepThread(RField< D > const &qin, RField< D > &qout) const
Compute one step of solution of MDE for the thread model.
void computeStressThread(double prefactor)
Compute stress contribution for this block, using thread model.
double ds() const
Get contour length step size.
void stepFieldBead(RField< D > &q) const
Apply the exponential field operator for the bead model.
void stepHalfBondBead(RField< D > const &qin, RField< D > &qout) const
Apply a half-bond operator for the bead model.
RField< D > & cField()
Get the associated monomer concentration field.
void stepBead(RField< D > const &qin, RField< D > &qout) const
Compute one step of solution of MDE for the bead model.
MDE solver for one direction of one block.
int capacity() const
Return allocated size.
Definition Array.h:144
A fixed capacity (static) contiguous array with a variable logical size.
Definition FSArray.h:38
void append(Data const &data)
Append data to the end of the array.
Definition FSArray.h:258
#define UTIL_CHECK(condition)
Assertion macro suitable for serial or parallel production code.
Definition global.h:68
bool isThread()
Is the thread model in use ?
bool isBead()
Is the bead model in use ?
Fields and FFTs for periodic boundary conditions (CPU)
Definition complex.cpp:12
Periodic fields and crystallography.
Definition complex.cpp:11
Real periodic fields, SCFT and PS-FTS (CPU).
Definition param_pc.dox:2
PSCF package top-level namespace.