PSCF v1.4.0
rpc/environment/FilmFieldGenExt.tpp
1#ifndef RPC_EXT_GEN_FILM_TPP
2#define RPC_EXT_GEN_FILM_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 "FilmFieldGenExt.h"
12#include <rpc/solvers/Mixture.h>
13#include <rpc/field/Domain.h>
14#include <rpc/field/FieldIo.h>
15#include <rpc/field/CFields.h>
16#include <rpc/field/WFields.h>
17#include <rpc/field/Mask.h>
18#include <rpc/scft/iterator/Iterator.h>
19
20#include <prdc/cpu/RField.h>
21#include <prdc/crystal/Basis.h>
22#include <prdc/crystal/paramIdConversions.h>
23#include <pscf/math/IntVec.h>
24#include <cmath>
25
26namespace Pscf {
27namespace Rpc {
28
29 using namespace Util;
30 using namespace Pscf::Prdc;
31 using namespace Pscf::Prdc::Cpu;
32
33 /*
34 * Default constructor
35 */
36 template <int D>
39 sysPtr_(nullptr)
40 { setClassName("FilmFieldGenExt"); }
41
42 /*
43 * Constructor
44 */
45 template <int D>
48 sysPtr_(&sys)
49 { setClassName("FilmFieldGenExt"); }
50
51 /*
52 * Destructor
53 */
54 template <int D>
57
58 /*
59 * Get contribution to the stress from these external fields
60 */
61 template <int D>
62 double FilmFieldGenExt<D>::stress(int paramId) const
63 {
64 // If walls are athermal then there is no external field, so no
65 // contribution to the stress.
66 if (isAthermal()) return 0.0;
67
68 // If paramId is not normalVecId, there is no stress contribution
69 UTIL_CHECK(normalVecId() >= 0); // normalVecId has been set
71 system().domain().lattice());
72 if (nvParamId != paramId) return 0.0;
73
74 // If this point is reached, calculate the stress contribution
75 // from the external fields.
77 UTIL_CHECK(system().mask().hasData());
78 UTIL_CHECK(system().h().hasData());
79
80 // Setup
81 int nMonomer = system().mixture().nMonomer();
82 int nx = system().domain().mesh().size();
83 RField<D> const & maskRGrid = system().mask().rgrid();
84 RField<D> maskDeriv, hDeriv;
85 maskDeriv.allocate(system().domain().mesh().dimensions());
86 hDeriv.allocate(system().domain().mesh().dimensions());
87 IntVec<3> coords;
88 int x, y, z;
89 int counter = 0;
90 double d, maskVal;
91 double term = 0.0;
92
93 // Create a 3 element vector 'dim' that contains the grid dimensions.
94 // If system is 2D (1D), then the z (y & z) dimensions are set to 1.
95 IntVec<3> dim;
96 for (int ind = 0; ind < 3; ind++) {
97 if (ind < D) {
98 dim[ind] = system().domain().mesh().dimensions()[ind];
99 } else {
100 dim[ind] = 1;
101 }
102 }
103
104 // Compute the derivative of the mask with respect to film thickness
105 for (x = 0; x < dim[0]; x++) {
106 coords[0] = x;
107 for (y = 0; y < dim[1]; y++) {
108 coords[1] = y;
109 for (z = 0; z < dim[2]; z++) {
110 coords[2] = z;
111 maskVal = maskRGrid[counter];
112
113 // Get the distance 'd' traveled along the lattice basis
114 // vector normal to the walls, in reduced coordinates
115 d = (double)coords[normalVecId()] /
116 (double)dim[normalVecId()];
117
118 maskDeriv[counter] = maskVal * (maskVal - 1) * 8.0
119 * (std::abs(d - 0.5) - 0.5)
121 counter++;
122 }
123 }
124 }
125
126 for (int i = 0; i < nMonomer; i++) {
127 // Compute the h field derivative with respect to film thickness
128 counter = 0;
129 for (x = 0; x < dim[0]; x++) {
130 coords[0] = x;
131 for (y = 0; y < dim[1]; y++) {
132 coords[1] = y;
133 for (z = 0; z < dim[2]; z++) {
134 coords[2] = z;
135 if (coords[normalVecId()] < (dim[normalVecId()] / 2)) {
136 hDeriv[counter] = -1.0 * maskDeriv[counter] * chiBottom(i);
137 } else {
138 hDeriv[counter] = -1.0 * maskDeriv[counter] * chiTop(i);
139 }
140 counter++;
141 }
142 }
143 }
144
145 // Get the integral term in the stress
146 RField<D> const & c = system().c().rgrid(i);
147 for (int i = 0; i < nx; i++) {
148 term += c[i] * hDeriv[i];
149 }
150 }
151 term /= (system().mask().phiTot() * nx);
152 return term;
153 }
154
158 template <int D>
160 {
161 // Set chiBottomCurrent_, chiTopCurrent_, and parametersCurrent_
165
166 // If walls are athermal then there is no external field needed.
167 // If external fields already exist in System, clear them, then return.
168 if (isAthermal()) {
169 system().h().clear();
170 return;
171 }
172
173 // If this point is reached, external field must be computed
174 UTIL_CHECK(normalVecId() >= 0);
175 UTIL_CHECK(system().domain().unitCell().isInitialized());
176 UTIL_CHECK(system().mask().hasData());
177 if (system().iterator().isSymmetric()) {
178 UTIL_CHECK(system().domain().basis().isInitialized());
179 }
180
181 int nm = systemNMonomer();
182
183 // Create a 3 element vector 'dim' that contains the grid dimensions.
184 // If system is 2D (1D), then the z (y & z) dimensions are set to 1.
185 IntVec<3> dim;
186 for (int ind = 0; ind < 3; ind++) {
187 if (ind < D) {
188 dim[ind] = system().domain().mesh().dimension(ind);
189 } else {
190 dim[ind] = 1;
191 }
192 }
193
194 // Get pointer to mask RField
195 RField<D> const & maskPtr = system().mask().rgrid();
196
197 // Generate an r-grid representation of the external fields
198 DArray< RField<D> > hRGrid;
199 hRGrid.allocate(nm);
200 for (int i = 0; i < nm; i++) {
201 hRGrid[i].allocate(system().domain().mesh().dimensions());
202 }
203
204 int i, x, y, z;
205 int counter = 0;
206 IntVec<3> coords;
207 double rhoW;
208
209 for (i = 0; i < nm; i++) {
210 for (x = 0; x < dim[0]; x++) {
211 coords[0] = x;
212 for (y = 0; y < dim[1]; y++) {
213 coords[1] = y;
214 for (z = 0; z < dim[2]; z++) {
215 coords[2] = z;
216
217 // Calculate wall volume fraction (rho_w) at gridpoint
218 // (x,y,z)
219 rhoW = maskPtr[counter];
220 if (coords[normalVecId()] < (dim[normalVecId()]/2)) {
221 hRGrid[i][counter++] = (1.0-rhoW) * chiBottom(i);
222 } else {
223 hRGrid[i][counter++] = (1.0-rhoW) * chiTop(i);
224 }
225 }
226 }
227 }
228 counter = 0;
229 }
230
231 // Pass h into the System
232 system().h().setRGrid(hRGrid, system().iterator().isSymmetric());
233 }
234
235 /*
236 * Get space group name for this system.
237 */
238 template <int D>
240 { return system().domain().groupName(); }
241
242 /*
243 * Get one of the lattice vectors for this system.
244 */
245 template <int D>
247 { return system().domain().unitCell().rBasis(id); }
248
249 /*
250 * Get the number of monomer species for this system.
251 */
252 template <int D>
254 { return system().mixture().nMonomer(); }
255
256}
257}
258
259#endif
An IntVec<D, T> is a D-component vector of elements of integer type T.
Definition IntVec.h:27
Field of real double precision values on an FFT mesh.
Definition cpu/RField.h:27
void allocate(IntVec< D > const &meshDimensions)
Allocate the underlying C array for an FFT grid.
DArray< double > chiTopCurrent_
The chiTop array used to generate the current external fields.
DArray< double > const & chiTop() const
Get const chiTop array by reference.
DArray< double > chiBottomCurrent_
The chiBottom array used to generate the current external fields.
DArray< double > const & chiBottom() const
Get const chiBottom matrix by reference.
bool isAthermal() const
Are the walls athermal?
double interfaceThickness() const
Get value of interfaceThickness.
RealVec< D > normalVecCurrent_
The lattice vector normal to the film used to generate these fields.
int normalVecId() const
Get value of normalVecId.
A RealVec<D, T> is D-component vector with elements of floating type T.
Definition RealVec.h:28
double stress(int paramId) const
Get contribution to the stress from the external fields.
System< D > & system()
Get the parent System by non-const reference.
void compute()
Compute the fields and store where the System can access.
void setClassName(const char *className)
Set class name string.
int systemNMonomer() const
Get the number of monomer species for this system.
std::string systemSpaceGroup() const
Get the space group name for this system.
RealVec< D > systemLatticeVector(int id) const
Get one of the lattice vectors for this system.
A complete physical system.
Dynamically allocatable contiguous array template.
Definition DArray.h:32
void allocate(int capacity)
Allocate the underlying C array.
Definition DArray.h:269
#define UTIL_CHECK(condition)
Assertion macro suitable for serial or parallel production code.
Definition global.h:68
int convertFullParamIdToReduced(const int fullId, const typename UnitCell< D >::LatticeSystem lattice)
Convert full lattice parameter index to a reduced index.
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.