12#include "Propagator.h"
14#include <prdc/cpu/WaveList.h>
15#include <prdc/cpu/FFT.h>
16#include <prdc/crystal/UnitCell.h>
17#include <prdc/crystal/shiftToMinimum.h>
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>
25#include <util/containers/DMatrix.h>
26#include <util/containers/DArray.h>
27#include <util/containers/FSArray.h>
44 unitCellPtr_(nullptr),
45 waveListPtr_(nullptr),
82 waveListPtr_ = &waveList;
99 UTIL_CHECK(mesh().dimensions() == fft().meshDimensions());
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());
116 expWInv_.allocate(mesh().dimensions());
120 cField().allocate(mesh().dimensions());
130 tempNs = floor(
length / (2.0 *
ds) + 0.5);
135 ds_ =
length/double(ns_-1);
166 int tempNs = floor(
length / (2.0 *dsTarget_) + 0.5 );
171 ds_ =
length / double(ns_-1);
207 void Block<D>::computeExpKsq()
213 const double b = BlockTmplT::kuhn();
214 double bSqFactor = -1.0 * b * b / 6.0;
220 if (!waveList().hasKSq()) {
221 waveList().computeKSq();
223 RField<D> const & kSq = waveList().kSq();
231 arg = kSq[i]*bSqFactor;
232 expKsq_[i] = exp(arg);
233 expKsq2_[i] = exp(0.5*arg);
247 int nx = mesh().size();
255 for (
int i = 0; i < nx; ++i) {
258 expW2_[i] = exp(0.5*arg);
262 for (
int i = 0; i < nx; ++i) {
265 expWInv_[i] = 1.0/expW_[i];
285 int nx = mesh().size();
288 UTIL_CHECK(mesh().dimensions() == fft().meshDimensions());
292 int nk = qk_.capacity();
311 for (i = 0; i < nx; ++i) {
312 qr_[i] = q[i]*expW_[i];
313 qr2_[i] = q[i]*expW2_[i];
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];
323 fft().inverseTransformUnsafe(qk_, qr_);
324 fft().inverseTransformUnsafe(qk2_, qr2_);
325 for (i = 0; i < nx; ++i) {
326 qr_[i] = qr_[i]*expW_[i];
327 qr2_[i] = qr2_[i]*expW_[i];
335 fft().forwardTransform(qr2_, qk2_);
336 for (i = 0; i < nk; ++i) {
337 qk2_[i][0] *= expKsq2_[i];
338 qk2_[i][1] *= expKsq2_[i];
340 fft().inverseTransformUnsafe(qk2_, qr2_);
341 for (i = 0; i < nx; ++i) {
342 qr2_[i] = qr2_[i]*expW2_[i];
346 for (i = 0; i < nx; ++i) {
347 qout[i] = (4.0*qr2_[i] - qr_[i])/3.0;
372 int nx = mesh().size();
376 int nk = qk_.capacity();
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];
386 fft().inverseTransformUnsafe(qk_, qout);
398 int nx = mesh().size();
402 int nk = qk_.capacity();
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];
412 fft().inverseTransformUnsafe(qk_, qout);
422 int nx = mesh().size();
428 for (
int i = 0; i < nx; ++i) {
441 int nx = mesh().size();
450 for (i = 0; i < nx; ++i) {
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];
468 for (j = 1; j < (ns_ -1); j += 2) {
471 for (i = 0; i < nx; ++i) {
473 cField()[i] += qf[i] * qr[i] * 4.0;
478 for (j = 2; j < (ns_ -2); j += 2) {
481 for (i = 0; i < nx; ++i) {
483 cField()[i] += qf[i] * qr[i] * 2.0;
488 prefactor *= ds_ / 3.0;
489 for (i = 0; i < nx; ++i) {
503 int nx = mesh().size();
512 for (i = 0; i < nx; ++i) {
522 for (j = 1; j < (ns_ -1); ++j) {
525 for (i = 0; i < nx; ++i) {
526 cField()[i] += qf[i] * qr[i] * expWInv_[i];
531 for (i = 0; i < nx; ++i) {
544 int nx = mesh().size();
547 UTIL_CHECK(mesh().dimensions() == fft().meshDimensions());
559 if (!waveList().hasdKSq()) {
560 waveList().computedKSq();
565 const int nParam = unitCell().nParameter();
566 for (
int i = 0; i < nParam; ++i) {
572 const double bSq = b * b / 6.0;
573 double dels, prod, increment;
577 for (
int j = 0; j < ns_ ; ++j) {
580 fft().forwardTransform(qr_, qk_);
582 qr2_ = p1.
q(ns_ - 1 - j);
583 fft().forwardTransform(qr2_, qk2_);
587 if (j != 0 && j != ns_ - 1) {
596 for (n = 0; n < nParam ; ++n) {
600 for (m = 0; m < kSize_ ; ++m) {
601 prod = (qk2_[m][0] * qk_[m][0]) + (qk2_[m][1] * qk_[m][1]);
605 increment *= bSq * dels;
606 dQ[n] = dQ[n] - increment;
613 for (
int n = 0; n < nParam; ++n) {
614 stress_.append(-1.0*prefactor*dQ[n]);
627 int nx = mesh().size();
630 UTIL_CHECK(mesh().dimensions() == fft().meshDimensions());
642 if (!waveList().hasdKSq()) {
643 waveList().computedKSq();
648 int nParam = unitCell().nParameter();
649 for (
int i = 0; i < nParam; ++i) {
654 const double bSq = b * b / 6.0;
655 double increment, prod;
662 fft().forwardTransform(qr_, qk_);
665 qr2_ = p1.
q(ns_ - 2);
666 fft().forwardTransform(qr2_, qk2_);
669 for (
int n = 0; n < nParam ; ++n) {
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];
678 increment *= 0.5*bSq;
679 dQ[n] = dQ[n] - increment;
684 for (
int j = 1; j < ns_ - 2 ; ++j) {
688 fft().forwardTransform(qr_, qk_);
691 qr2_ = p1.
q(ns_ - 2 - j);
692 fft().forwardTransform(qr2_, qk2_);
695 for (
int n = 0; n < nParam ; ++n) {
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];
705 dQ[n] = dQ[n] - increment;
715 fft().forwardTransform(qr_, qk_);
719 fft().forwardTransform(qr2_, qk2_);
722 for (
int n = 0; n < nParam ; ++n) {
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];
731 increment *= 0.5*bSq;
732 dQ[n] = dQ[n] - increment;
739 for (
int i = 0; i < nParam; ++i) {
740 stress_.append(-1.0*prefactor*dQ[i]);
virtual void setKuhn(double kuhn)
int nBead() const
Get the number of beads in this block, in the bead model.
virtual void setLength(double length)
Set the length of this block (only valid for thread model).
double length() const
Get the length of this block, in the thread model.
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.
Fourier transform wrapper.
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.
bool isAllocated() const
Return true if the FftwDArray has been allocated, false otherwise.
Field of real double precision values on an FFT mesh.
Class to compute and store properties associated with wavevectors.
Base template for UnitCell<D> classes, D=1, 2 or 3.
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.
A fixed capacity (static) contiguous array with a variable logical size.
void append(Data const &data)
Append data to the end of the array.
#define UTIL_CHECK(condition)
Assertion macro suitable for serial or parallel production code.
bool isThread()
Is the thread model in use ?
bool isBead()
Is the bead model in use ?
Fields and FFTs for periodic boundary conditions (CPU)
Periodic fields and crystallography.
Real periodic fields, SCFT and PS-FTS (CPU).
PSCF package top-level namespace.