PSCF v1.4.0
rpc/environment/FilmFieldGenMask.tpp
1#ifndef RPC_MASK_GEN_FILM_TPP
2#define RPC_MASK_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 "FilmFieldGenMask.h"
12#include <rpc/solvers/Mixture.h>
13#include <rpc/scft/iterator/Iterator.h>
14#include <rpc/scft/ScftThermo.h>
15#include <rpc/field/Domain.h>
16#include <rpc/field/FieldIo.h>
17#include <rpc/field/WFields.h>
18#include <rpc/field/CFields.h>
19#include <rpc/field/Mask.h>
20
21#include <prdc/cpu/RField.h>
22#include <prdc/crystal/UnitCell.h>
23#include <prdc/crystal/Basis.h>
24#include <prdc/crystal/paramIdConversions.h>
25#include <pscf/interaction/Interaction.h>
26#include <pscf/math/IntVec.h>
27#include <cmath>
28
29namespace Pscf {
30namespace Rpc
31{
32
33 using namespace Util;
34 using namespace Pscf::Prdc;
35 using namespace Pscf::Prdc::Cpu;
36
37 /*
38 * Default constructor
39 */
40 template <int D>
43 sysPtr_(nullptr)
44 { setClassName("FilmFieldGenMask"); }
45
46 /*
47 * Constructor
48 */
49 template <int D>
52 sysPtr_(&sys)
53 { setClassName("FilmFieldGenMask"); }
54
55 /*
56 * Destructor
57 */
58 template <int D>
61
62 /*
63 * Get contribution to the stress from this mask
64 */
65 template <int D>
66 double FilmFieldGenMask<D>::stress(int paramId) const
67 {
68 UTIL_CHECK(sysPtr_);
69 Domain<D> const & domain = system().domain();
70 Mesh<D> const & mesh = domain.mesh();
71
72 int normalVecParamId = convertFullParamIdToReduced<D>(normalVecId(),
73 domain.lattice());
74
75 // If paramId is not normalVecId, there is no stress contribution
76 if (normalVecParamId != paramId) return 0.0;
77
78 // If this point is reached, stress contribution must be calculated
79 UTIL_CHECK(system().mask().hasData());
80
81 // Get the length of the lattice basis vector normal to the walls
82 double nvLength = domain.unitCell().parameter(paramId);
83
84 // Get the volume fraction of the unit cell occupied by polymers
85 double phiTot = system().mask().phiTot();
86
87 // Create a 3 element vector 'dim' that contains the grid dimensions.
88 // If system is 2D (1D), then the z (y & z) dimensions are set to 1.
89 IntVec<3> dim;
90 for (int ind = 0; ind < 3; ind++) {
91 if (ind < D) {
92 dim[ind] = mesh.dimensions()[ind];
93 } else {
94 dim[ind] = 1;
95 }
96 }
97
98 // Create the derivative field in rgrid format
99 RField<D> deriv;
100 IntVec<3> coords;
101 int x, y, z;
102 int counter = 0;
103 double d, maskVal;
104
105 deriv.allocate(mesh.dimensions());
106 RField<D> const & maskRGrid = system().mask().rgrid();
107
108 for (x = 0; x < dim[0]; x++) {
109 coords[0] = x;
110 for (y = 0; y < dim[1]; y++) {
111 coords[1] = y;
112 for (z = 0; z < dim[2]; z++) {
113 coords[2] = z;
114 maskVal = maskRGrid[counter];
115
116 // Get the distance 'd' traveled along the lattice basis
117 // vector normal to the walls, in reduced coordinates
118 d = (double)coords[normalVecId()] /
119 (double)dim[normalVecId()];
120
121 deriv[counter] = maskVal * (maskVal - 1) * 8.0
122 * (std::abs(d - 0.5) - 0.5)
124 counter++;
125 }
126 }
127 }
128
129 // Get xi, the Lagrange multiplier field, in rgrid format
130 int nMonomer = system().mixture().nMonomer();
131 int nx = mesh.size();
132 double chi;
133 RField<D> xi;
134 xi.allocate(mesh.dimensions());
135
136 for (int i = 0; i < nx; i++) {
137 xi[i] = system().w().rgrid(0)[i];
138 }
139
140 for (int in = 0; in < nMonomer; in++) {
141 chi = system().interaction().chi(0,in);
142 if (fabs(chi) > 1e-6) { // if chi is nonzero
143 RField<D> const & cfield = system().c().rgrid(in);
144 for (int i = 0; i < nx; i++) {
145 //xi[i] -= system().c().rgrid(in)[i] * chi;
146 xi[i] -= cfield[i] * chi;
147 }
148 }
149 }
150
151 if (system().h().hasData()) {
152 RField<D> const & hfield = system().h().rgrid(0);
153 for (int i = 0; i < nx; i++) {
154 //xi[i] -= system().h().rgrid(0)[i];
155 xi[i] -= hfield[i];
156 }
157 }
158
159 // Get the integral term in the stress
160 double intTerm = 0.0;
161 for (int i = 0; i < nx; i++) {
162 intTerm += xi[i] * deriv[i];
163 }
164 intTerm /= (phiTot * nx);
165
166 // Get the pressure term in the stress
167 if (!system().scft().hasData()) {
168 sysPtr_->scft().compute();
169 }
170 double pSys = system().scft().pressure();
171 double pTerm = pSys * excludedThickness() /
172 (phiTot * nvLength * nvLength);
173
174 return pTerm - intTerm;
175 }
176
177 template <int D>
178 double FilmFieldGenMask<D>::modifyStress(int paramId, double stress)
179 const
180 {
181 UTIL_CHECK(sysPtr_);
183 system().domain().lattice());
184 if (nvParamId == paramId) {
185 UTIL_CHECK(system().mask().hasData());
186
187 if (!hasFBulk()) {
188 UTIL_THROW("fBulk must be set before calculating this stress.");
189 }
190
191 // Get system free energy
192 if (!system().scft().hasData()) {
193 sysPtr_->scft().compute();
194 }
195 double fSys = system().scft().fHelmholtz();
196
197 // Get the length L of the basis vector normal to the walls
198 double L = system().domain().unitCell().parameter(paramId);
199
200 double modifiedStress = (stress * (L - excludedThickness()))
201 + (fSys - fBulk_);
202
203 return modifiedStress;
204 } else {
205 return stress;
206 }
207 }
208
209 /*
210 * Compute the field and store where the System can access
211 */
212 template <int D>
214 {
215 UTIL_CHECK(sysPtr_);
218 UTIL_CHECK(normalVecId() >= 0);
219 if (system().iterator().isSymmetric()) {
220 UTIL_CHECK(system().domain().basis().isInitialized());
221 }
222
223 // Get the length L of the lattice basis vector normal to the walls
225 system().domain().lattice());
226 double L = system().domain().unitCell().parameter(paramId);
227
228 // Create a 3 element vector 'dim' that contains the grid dimensions.
229 // If system is 2D (1D), then the z (y & z) dimensions are set to 1.
230 IntVec<3> dim;
231 for (int ind = 0; ind < 3; ind++) {
232 if (ind < D) {
233 dim[ind] = system().domain().mesh().dimensions()[ind];
234 } else {
235 dim[ind] = 1;
236 }
237 }
238
239 // Generate an r-grid representation of the walls
240 RField<D> rGrid;
241 rGrid.allocate(system().domain().mesh().dimensions());
242 int x, y, z;
243 int counter = 0;
244 IntVec<3> coords;
245 double d, rhoW;
246
247 for (x = 0; x < dim[0]; x++) {
248 coords[0] = x;
249 for (y = 0; y < dim[1]; y++) {
250 coords[1] = y;
251 for (z = 0; z < dim[2]; z++) {
252 coords[2] = z;
253
254 // Get the distance 'd' traveled along the lattice basis
255 // vector that is normal to the walls
256 d = coords[normalVecId()] * L / dim[normalVecId()];
257
258 // Calculate wall volume fraction (rhoW) at gridpoint (x,y,z)
259 rhoW = 0.5 * (1 + tanh(4 * (((.5 * (excludedThickness()-L)) +
260 fabs(d - (L/2))) / interfaceThickness())));
261 rGrid[counter++] = 1-rhoW;
262 }
263 }
264 }
265
266 // Store this mask in System
267 system().mask().setRGrid(rGrid, system().iterator().isSymmetric());
268
269 // Store lattice vector normal to film used to construct this mask
271
272 }
273
274 /*
275 * Sets flexible lattice parameters to be compatible with the mask.
276 */
277 template <int D>
279 {
280 UTIL_CHECK(sysPtr_);
281 if (system().iterator().isFlexible()) {
282 FSArray<bool,6> updated;
283 updated = modifyFlexibleParams(system().iterator().flexibleParams(),
284 system().domain().unitCell());
285 sysPtr_->iterator().setFlexibleParams(updated);
286 }
287 }
288
289} // namespace Rpc
290} // namespace Pscf
291#endif
An IntVec<D, T> is a D-component vector of elements of integer type T.
Definition IntVec.h:27
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
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:27
void allocate(IntVec< D > const &meshDimensions)
Allocate the underlying C array for an FFT grid.
RealVec< D > normalVecCurrent_
The lattice vector normal to the film used to generate these fields.
int normalVecId() const
Get value of normalVecId.
double fBulk_
Reference free energy used to calculate stress normal to the film.
bool hasFBulk() const
Check whether a value of fBulk was provided.
FSArray< bool, 6 > modifyFlexibleParams(FSArray< bool, 6 > current, UnitCell< D > const &cell) const
Modifies a flexibleParams array to be compatible with this mask.
double interfaceThickness() const
Get value of interfaceThickness.
double excludedThickness() const
Get value of excludedThickness.
UnitCell< D > & unitCell()
Get the UnitCell by non-const reference.
UnitCell< D >::LatticeSystem lattice() const
Get the lattice type (enumeration value).
Mesh< D > & mesh()
Get the Mesh by non-const reference.
Spatial domain for a periodic structure with real fields, on a CPU.
void setFlexibleParams() const
Modifies iterator().flexibleParams_ to be compatible with the mask.
void setClassName(const char *className)
Set class name string.
double modifyStress(int paramId, double stress) const
Modify stress value in direction normal to the film.
RealVec< D > systemLatticeVector(int id) const
Get one of the lattice vectors for this system.
System< D > & system()
Get the parent System by non-const reference.
double stress(int paramId) const
Get contribution to the stress from this mask.
void compute()
Compute the field and store where the System can access.
A complete physical system.
A fixed capacity (static) contiguous array with a variable logical size.
Definition FSArray.h:38
#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
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.