PSCF v1.3.1
SystemTmpl.tpp
1#ifndef PRDC_SYSTEM_TMPL_TPP
2#define PRDC_SYSTEM_TMPL_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 "SystemTmpl.h"
12
13#include <pscf/math/IntVec.h>
14
15#include <util/containers/DArray.h>
16#include <util/containers/FSArray.h>
17#include <util/param/BracketPolicy.h>
18#include <util/param/ParamComponent.h>
19#include <util/signal/Signal.h>
20#include <util/format/Str.h>
21#include <util/format/Int.h>
22#include <util/format/Dbl.h>
23#include <util/misc/ioUtil.h>
24
25#include <string>
26#include <unistd.h>
27
28namespace Pscf {
29namespace Prdc {
30
31 using namespace Util;
32
33 /*
34 * Constructor.
35 */
36 template <int D, class T>
37 SystemTmpl<D,T>::SystemTmpl(typename T::System& system)
38 : mixture_(),
39 domain_(),
40 fileMaster_(),
41 w_(),
42 c_(),
43 h_(),
44 mask_(),
45 mixtureModifierPtr_(nullptr),
46 interactionPtr_(nullptr),
47 environmentPtr_(nullptr),
48 environmentFactoryPtr_(nullptr),
49 scftPtr_(nullptr),
50 iteratorPtr_(nullptr),
51 iteratorFactoryPtr_(nullptr),
52 sweepPtr_(nullptr),
53 sweepFactoryPtr_(nullptr),
54 simulatorPtr_(nullptr),
55 simulatorFactoryPtr_(nullptr),
56 systemPtr_(&system),
57 polymerModel_(PolymerModel::Thread),
58 isAllocatedGrid_(false),
59 isAllocatedBasis_(false),
60 hasMixture_(false)
61 {
62 setClassName("SystemTmpl"); // Set block label in parameter file
63 BracketPolicy::set(BracketPolicy::Optional);
64
65 // Create dynamically allocated objects owned by this SystemTmpl
66 mixtureModifierPtr_ = new typename T::MixtureModifier();
67 interactionPtr_ = new typename T::Interaction();
68 scftPtr_ = new typename T::ScftThermo(*systemPtr_);
69 environmentFactoryPtr_
70 = new typename T::EnvironmentFactory(*systemPtr_);
71 iteratorFactoryPtr_ = new typename T::IteratorFactory(*systemPtr_);
72 sweepFactoryPtr_ = new typename T::SweepFactory(*systemPtr_);
73 simulatorFactoryPtr_ = new typename T::SimulatorFactory(*systemPtr_);
74
75 // Create associations among class members
76 mixtureModifier().associate(mixture_);
77 domain_.setFileMaster(fileMaster_);
78 w_.setFieldIo(domain_.fieldIo());
79 w_.setReadUnitCell(domain_.unitCell());
80 w_.setWriteUnitCell(domain_.unitCell());
81 h_.setFieldIo(domain_.fieldIo());
82 h_.setReadUnitCell(tmpUnitCell_);
83 h_.setWriteUnitCell(domain_.unitCell());
84 mask_.setFieldIo(domain_.fieldIo());
85 mask_.setReadUnitCell(tmpUnitCell_);
86 mask_.setWriteUnitCell(domain_.unitCell());
87 c_.setFieldIo(domain_.fieldIo());
88 c_.setWriteUnitCell(domain_.unitCell());
89
90 // Note the arguments of setReadUnitCell functions used above:
91 // When w_ is read from a file in basis or r-grid format, the
92 // parameters of the system unit cell, domain_.unitCell(), are
93 // reset to those in the field file header. When imposed fields h_
94 // and mask_ are read from a file, however, unit cell parameters
95 // from the field file header are read into a mutable workspace
96 // object, tmpUnitCell_, and ultimately discarded.
97
98 // Use of "signals" to maintain data relationships:
99 // Signals are instances of Unit::Signal<void> that are used to
100 // notify "observer" objects of modification of data owned by a
101 // related "notifier" object. Each signal is owned by a notifier
102 // object that maintains data that may be modified. Each signal
103 // maintains a list of observers objects that should be notified
104 // whenever the data owned by the notifier object changes. Each
105 // observer is added by the Signal<void>::addObserver function
106 // template, which takes two arguments: a reference to an observer
107 // object (i.e., an instance of a class) and a pointer to a member
108 // function of that class which will be invoked on that object when
109 // the signal is triggered by modification of associated data.
110
111 // Addition of observers to signals
112
113 // Signal triggered by unit cell modification
114 Signal<void>& cellSignal = domain_.unitCell().signal();
116
117 // Signal triggered by basis construction
118 Signal<void>& basisSignal = domain_.basis().signal();
119 basisSignal.addObserver(*this, &SystemTmpl<D,T>::allocateFieldsBasis);
120
121 // Signal triggered by w-field modification
122 w_.signal().addObserver(*this, &SystemTmpl<D,T>::clearCFields);
123
124 // Signal triggered by h-field modification
125 h_.signal().addObserver(*this, &SystemTmpl<D,T>::clearCFields);
126
127 // Signal triggered by mask modification
128 mask_.signal().addObserver(*this, &SystemTmpl<D,T>::clearCFields);
129 }
130
131 /*
132 * Destructor.
133 */
134 template <int D, class T>
136 {
137 if (interactionPtr_) {
138 delete interactionPtr_;
139 }
140 if (environmentPtr_) {
141 delete environmentPtr_;
142 }
143 if (environmentFactoryPtr_) {
144 delete environmentFactoryPtr_;
145 }
146 if (scftPtr_) {
147 delete scftPtr_;
148 }
149 if (iteratorPtr_) {
150 delete iteratorPtr_;
151 }
152 if (iteratorFactoryPtr_) {
153 delete iteratorFactoryPtr_;
154 }
155 if (sweepPtr_) {
156 delete sweepPtr_;
157 }
158 if (sweepFactoryPtr_) {
159 delete sweepFactoryPtr_;
161 if (simulatorPtr_) {
162 delete simulatorPtr_;
163 }
164 if (simulatorFactoryPtr_) {
165 delete simulatorFactoryPtr_;
166 }
168
169 // Lifetime (called in main program)
170
171 /*
172 * Process command line options.
173 */
174 template <int D, class T>
175 void SystemTmpl<D,T>::setOptions(int argc, char **argv)
176 {
177 bool eFlag = false; // echo
178 bool dFlag = false; // spatial dimension (1, 2, or 3)
179 bool pFlag = false; // param file
180 bool cFlag = false; // command file
181 bool iFlag = false; // input prefix
182 bool oFlag = false; // output prefix
183 bool tFlag = false; // thread count
184 char* pArg = 0;
185 char* cArg = 0;
186 char* iArg = 0;
187 char* oArg = 0;
188 int dArg = 0;
189 int tArg = 0;
190
191 // Read program arguments
192 int c;
193 opterr = 0;
194 while ((c = getopt(argc, argv, "ed:p:c:i:o:t:")) != -1) {
195 switch (c) {
196 case 'e':
197 eFlag = true;
198 break;
199 case 'd':
200 dFlag = true;
201 dArg = atoi(optarg);
202 break;
203 case 'p': // parameter file
204 pFlag = true;
205 pArg = optarg;
206 break;
207 case 'c': // command file
208 cFlag = true;
209 cArg = optarg;
210 break;
211 case 'i': // input prefix
212 iFlag = true;
213 iArg = optarg;
214 break;
215 case 'o': // output prefix
216 oFlag = true;
217 oArg = optarg;
218 break;
219 case 't': // thread count, if set by user
220 tFlag = true;
221 tArg = atoi(optarg);
222 break;
223 case '?':
224 Log::file() << "Unknown option -" << optopt << std::endl;
225 UTIL_THROW("Invalid command line option");
227 }
228
229 // Process program arguments
230
231 // Check required option -d
232 if (dFlag) {
233 UTIL_CHECK(D == dArg);
234 } else {
235 UTIL_THROW("Missing required -d option");
236 }
237
238 // Check required option -p, set parameter file name
239 if (pFlag) {
240 fileMaster_.setParamFileName(std::string(pArg));
241 } else {
242 UTIL_THROW("Missing required -p option - no parameter file");
243 }
244
245 // Check required option -c, set command file name
246 if (cFlag) {
247 fileMaster_.setCommandFileName(std::string(cArg));
248 } else {
249 UTIL_THROW("Missing required -c option - no command file");
250 }
251
252 // If option -e, set to echo parameters as they are read
253 if (eFlag) {
255 }
256
257 // If option -i, set path prefix for input files
258 if (iFlag) {
259 fileMaster_.setInputPrefix(std::string(iArg));
260 }
261
262 // If option -o, set path prefix for output files
263 if (oFlag) {
264 fileMaster_.setOutputPrefix(std::string(oArg));
265 }
266
267 // If option -t, process the thread count
268 if (tFlag) {
269 if (tArg <= 0) {
270 UTIL_THROW("Error: Non-positive thread count -t option");
271 }
272 setThreadCount(tArg);
273 }
274 }
275
276 /*
277 * Read parameters and initialize.
278 */
279 template <int D, class T>
280 void SystemTmpl<D,T>::readParameters(std::istream& in)
281 {
282 // Optionally read polymerModel_ enum value, set the global value
283 if (!PolymerModel::isLocked()) {
284 polymerModel_ = PolymerModel::Thread;
285 readOptional(in, "polymerModel", polymerModel_);
286
287 // Set the global enumeration value
288 PolymerModel::setModel(polymerModel_);
289 }
290
291 // Check number of times the global polymer model has been set.
292 // Retain this value so we can check at the end of this function
293 // that it was not set again within the function.
294
295 int nSetPolymerModel = PolymerModel::nSet();
296
297 // Read the Mixture{ ... } block
298 readParamComposite(in, mixture_);
299 hasMixture_ = true;
300
301 int nm = mixture_.nMonomer();
302 int np = mixture_.nPolymer();
303 int ns = mixture_.nSolvent();
304 UTIL_CHECK(nm > 0);
305 UTIL_CHECK(np >= 0);
306 UTIL_CHECK(ns >= 0);
307 UTIL_CHECK(np + ns > 0);
308
309 // Read the Interaction{ ... } block
310 interaction().setNMonomer(nm);
312
313 // Read the Domain{ ... } block
314 readParamComposite(in, domain_);
315 UTIL_CHECK(domain_.mesh().size() > 0);
316 UTIL_CHECK(domain_.unitCell().nParameter() > 0);
317 UTIL_CHECK(domain_.unitCell().lattice() != UnitCell<D>::Null);
318 domain_.fieldIo().setNMonomer(nm);
319
320 // Setup the mixture
321 mixture_.associate(domain_.mesh(), domain_.fft(),
322 domain_.unitCell(), domain_.waveList());
323 mixture_.setFieldIo(domain_.fieldIo());
324 mixture_.allocate();
325
326 // Allocate memory for field containers in r-grid form
327 allocateFieldsGrid();
328
329 // Optionally construct an Environment object
330 std::string className;
331 bool isEnd;
332 environmentPtr_ =
333 environmentFactoryPtr_->readObjectOptional(in, *this,
334 className, isEnd);
335 if (!environmentPtr_ && ParamComponent::echo()) {
336 Log::file() << indent() << " Environment{ [absent] }\n";
337 }
338 if (environmentPtr_) {
339 environment().setNParams(domain_.unitCell().nParameter());
340 }
341
342 // Optionally construct an Iterator object
343 if (!isEnd) {
344 iteratorPtr_ =
345 iteratorFactoryPtr_->readObjectOptional(in, *this,
346 className, isEnd);
347 if (!iteratorPtr_ && ParamComponent::echo()) {
348 Log::file() << indent() << " Iterator{ [absent] }\n";
349 }
350 }
351
352 // Optionally construct a Sweep object (if an iterator exists)
353 if (hasIterator() && !isEnd) {
354 sweepPtr_ =
355 sweepFactoryPtr_->readObjectOptional(in, *this,
356 className, isEnd);
357 if (!sweepPtr_ && ParamComponent::echo()) {
358 Log::file() << indent() << " Sweep{ [absent] }\n";
359 }
360 }
361
362 // Optionally construct a Simulator object
363 if (!isEnd) {
364 simulatorPtr_ =
365 simulatorFactoryPtr_->readObjectOptional(in, *this,
366 className, isEnd);
367 if (!simulatorPtr_ && ParamComponent::echo()) {
368 Log::file() << indent() << " Simulator{ [absent] }\n";
369 }
370 }
371
372 // Check that the polymer model was not reset after initialization
373 UTIL_CHECK(PolymerModel::nSet() == nSetPolymerModel);
374 }
375
376 /*
377 * Read parameter file (including open and closing brackets).
378 */
379 template <int D, class T>
380 void SystemTmpl<D,T>::readParam(std::istream& in)
381 {
382 readBegin(in, className().c_str());
383 readParameters(in);
384 readEnd(in);
385 }
386
387 /*
388 * Read default parameter file.
389 */
390 template <int D, class T>
392 { readParam(fileMaster_.paramFile()); }
393
394 /*
395 * Read and execute commands from a specified command file.
396 */
397 template <int D, class T>
398 void SystemTmpl<D,T>::readCommands(std::istream &in)
399 {
400 UTIL_CHECK(isAllocatedGrid_);
401 std::string command, filename, inFileName, outFileName;
402 typename T::FieldIo const & fieldIo = domain_.fieldIo();
403
404 bool readNext = true;
405 while (readNext) {
406
407 in >> command;
408
409 if (in.eof()) {
410 break;
411 } else {
412 Log::file() << command << std::endl;
413 }
414
415 if (command == "FINISH") {
416 Log::file() << std::endl;
417 readNext = false;
418 } else
419 if (command == "READ_W_BASIS") {
420 readEcho(in, filename);
421 w().readBasis(filename);
422 UTIL_CHECK(domain_.unitCell().isInitialized());
423 UTIL_CHECK(domain_.basis().isInitialized());
424 UTIL_CHECK(!domain_.waveList().hasKSq());
425 UTIL_CHECK(isAllocatedBasis_);
426 UTIL_CHECK(!c_.hasData());
427 UTIL_CHECK(!scft().hasData());
428 } else
429 if (command == "READ_W_RGRID") {
430 readEcho(in, filename);
431 w().readRGrid(filename);
432 UTIL_CHECK(domain_.unitCell().isInitialized());
433 UTIL_CHECK(!domain_.waveList().hasKSq());
434 UTIL_CHECK(!c_.hasData());
435 UTIL_CHECK(!scft().hasData());
436 } else
437 if (command == "SET_UNIT_CELL") {
438 UnitCell<D> unitCell;
439 in >> unitCell;
440 Log::file() << " " << unitCell << std::endl;
441 setUnitCell(unitCell);
442 UTIL_CHECK(domain_.unitCell().isInitialized());
443 UTIL_CHECK(!domain_.waveList().hasKSq());
444 UTIL_CHECK(!c_.hasData());
445 UTIL_CHECK(!scft().hasData());
446 } else
447 if (command == "COMPUTE") {
448 // Solve the modified diffusion equation, without iteration
449 compute();
450 } else
451 if (command == "ITERATE") {
452 // Attempt to iteratively solve a single SCFT problem
453 bool isContinuation = false;
454 int fail = iterate(isContinuation);
455 if (fail) {
456 readNext = false;
457 }
458 } else
459 if (command == "SWEEP") {
460 // Attempt to solve a sequence of SCFT problems along a path
461 // through parameter space
462 sweep();
463 } else
464 if (command == "COMPRESS") {
465 // Impose incompressibility
467 simulator().compressor().compress();
468 } else
469 if (command == "SIMULATE") {
470 // Perform a field theoretic simulation
471 int nStep;
472 in >> nStep;
473 Log::file() << " " << nStep << "\n";
474 simulate(nStep);
475 } else
476 if (command == "ANALYZE" || command == "ANALYZE_TRAJECTORY") {
477 // Read and analyze a field trajectory file
478 int min, max;
479 in >> min;
480 in >> max;
481 Log::file() << " " << min ;
482 Log::file() << " " << max << "\n";
483 std::string classname;
484 readEcho(in, classname);
485 readEcho(in, filename);
486 simulator().analyze(min, max, classname, filename);
487 } else
488 if (command == "WRITE_PARAM") {
489 readEcho(in, filename);
490 std::ofstream file;
491 fileMaster_.openOutputFile(filename, file);
492 writeParamNoSweep(file);
493 file.close();
494 } else
495 if (command == "WRITE_THERMO") {
496 readEcho(in, filename);
497 std::ofstream file;
498 fileMaster_.openOutputFile(filename, file,
499 std::ios_base::app);
500 scft().write(file);
501 file.close();
502 } else
503 if (command == "WRITE_STRESS") {
504 readEcho(in, filename);
505 std::ofstream file;
506 if (!mixture().hasStress()) {
508 }
509 fileMaster_.openOutputFile(filename, file,
510 std::ios_base::app);
511 mixture().writeStress(file);
512 if (hasEnvironment()) {
513 environment().writeStress(file);
514 }
515 file.close();
516 } else
517 if (command == "WRITE_W_BASIS") {
518 readEcho(in, filename);
519 w().writeBasis(filename);
520 } else
521 if (command == "WRITE_W_RGRID") {
522 readEcho(in, filename);
523 w().writeRGrid(filename);
524 } else
525 if (command == "WRITE_C_BASIS") {
526 readEcho(in, filename);
527 c().writeBasis(filename);
528 } else
529 if (command == "WRITE_C_RGRID") {
530 readEcho(in, filename);
531 c().writeRGrid(filename);
532 } else
533 if (command == "WRITE_BLOCK_C_RGRID") {
534 readEcho(in, filename);
535 mixture_.writeBlockCRGrid(filename);
536 } else
537 if (command == "WRITE_Q_SLICE") {
538 int polymerId, blockId, directionId, segmentId;
539 readEcho(in, filename);
540 in >> polymerId;
541 in >> blockId;
542 in >> directionId;
543 in >> segmentId;
544 Log::file() << Str("polymer ID ", 21) << polymerId << "\n"
545 << Str("block ID ", 21) << blockId << "\n"
546 << Str("direction ID ", 21) << directionId
547 << "\n"
548 << Str("segment ID ", 21) << segmentId
549 << std::endl;
550 mixture_.writeQSlice(filename, polymerId, blockId,
551 directionId, segmentId);
552 } else
553 if (command == "WRITE_Q_TAIL") {
554 readEcho(in, filename);
555 int polymerId, blockId, directionId;
556 in >> polymerId;
557 in >> blockId;
558 in >> directionId;
559 Log::file() << Str("polymer ID ", 21) << polymerId << "\n"
560 << Str("block ID ", 21) << blockId << "\n"
561 << Str("direction ID ", 21) << directionId
562 << "\n";
563 mixture_.writeQTail(filename, polymerId, blockId, directionId);
564 } else
565 if (command == "WRITE_Q") {
566 readEcho(in, filename);
567 int polymerId, blockId, directionId;
568 in >> polymerId;
569 in >> blockId;
570 in >> directionId;
571 Log::file() << Str("polymer ID ", 21) << polymerId << "\n"
572 << Str("block ID ", 21) << blockId << "\n"
573 << Str("direction ID ", 21) << directionId
574 << "\n";
575 mixture_.writeQ(filename, polymerId, blockId, directionId);
576 } else
577 if (command == "WRITE_Q_ALL") {
578 readEcho(in, filename);
579 mixture_.writeQAll(filename);
580 } else
581 if (command == "WRITE_STARS") {
582 readEcho(in, filename);
583 domain_.writeStars(filename);
584 } else
585 if (command == "WRITE_WAVES") {
586 readEcho(in, filename);
587 domain_.writeWaves(filename);
588 } else
589 if (command == "WRITE_GROUP") {
590 readEcho(in, filename);
591 domain_.writeGroup(filename);
592 } else
593 if (command == "BASIS_TO_RGRID") {
594 readEcho(in, inFileName);
595 readEcho(in, outFileName);
596 fieldIo.convertBasisToRGrid(inFileName, outFileName);
597 } else
598 if (command == "RGRID_TO_BASIS") {
599 readEcho(in, inFileName);
600 readEcho(in, outFileName);
601 fieldIo.convertRGridToBasis(inFileName, outFileName);
602 } else
603 if (command == "KGRID_TO_RGRID") {
604 readEcho(in, inFileName);
605 readEcho(in, outFileName);
606 fieldIo.convertKGridToRGrid(inFileName, outFileName);
607 } else
608 if (command == "RGRID_TO_KGRID") {
609 readEcho(in, inFileName);
610 readEcho(in, outFileName);
611 fieldIo.convertRGridToKGrid(inFileName, outFileName);
612 } else
613 if (command == "BASIS_TO_KGRID") {
614 readEcho(in, inFileName);
615 readEcho(in, outFileName);
616 fieldIo.convertBasisToKGrid(inFileName, outFileName);
617 } else
618 if (command == "KGRID_TO_BASIS") {
619 readEcho(in, inFileName);
620 readEcho(in, outFileName);
621 fieldIo.convertKGridToBasis(inFileName, outFileName);
622 } else
623 if (command == "CHECK_RGRID_SYMMETRY") {
624 double epsilon;
625 readEcho(in, inFileName);
626 readEcho(in, epsilon);
627 bool hasSymmetry;
628 hasSymmetry = fieldIo.hasSymmetry(inFileName, epsilon);
629 if (hasSymmetry) {
630 Log::file() << std::endl
631 << "Symmetry of r-grid file matches this space group"
632 << std::endl << std::endl;
633 } else {
634 Log::file() << std::endl
635 << "Symmetry of r-grid file does not match this\n"
636 << "space group to within error threshold of "
637 << Dbl(epsilon) << " ." << std::endl << std::endl;
638 }
639 } else
640 if (command == "COMPARE_BASIS") {
641 std::string filecompare1, filecompare2;
642 readEcho(in, filecompare1);
643 readEcho(in, filecompare2);
644 fieldIo.compareFieldsBasis(filecompare1, filecompare2);
645 } else
646 if (command == "COMPARE_RGRID") {
647 std::string filecompare1, filecompare2;
648 readEcho(in, filecompare1);
649 readEcho(in, filecompare2);
650 fieldIo.compareFieldsRGrid(filecompare1, filecompare2);
651 } else
652 if (command == "SCALE_BASIS") {
653 double factor;
654 readEcho(in, inFileName);
655 readEcho(in, outFileName);
656 readEcho(in, factor);
657 fieldIo.scaleFieldsBasis(inFileName, outFileName, factor);
658 } else
659 if (command == "SCALE_RGRID") {
660 double factor;
661 readEcho(in, inFileName);
662 readEcho(in, outFileName);
663 readEcho(in, factor);
664 fieldIo.scaleFieldsRGrid(inFileName, outFileName, factor);
665 } else
666 if (command == "EXPAND_RGRID_DIMENSION") {
667 readEcho(in, inFileName);
668 readEcho(in, outFileName);
669
670 // Read expanded spatial dimension d
671 int d;
672 in >> d;
673 UTIL_CHECK(d > D);
674 Log::file() << Str("Expand dimension to: ") << d << "\n";
675
676 // Read numbers of grid points along added dimensions
677 DArray<int> newGridDimensions;
678 newGridDimensions.allocate(d-D);
679 for (int i = 0; i < d-D; i++) {
680 in >> newGridDimensions[i];
681 }
682 Log::file()
683 << Str("Numbers of grid points in added dimensions : ");
684 for (int i = 0; i < d-D; i++) {
685 Log::file() << newGridDimensions[i] << " ";
686 }
687 Log::file() << "\n";
688
689 fieldIo.expandRGridDimension(inFileName, outFileName,
690 d, newGridDimensions);
691
692 } else
693 if (command == "REPLICATE_UNIT_CELL") {
694 readEcho(in, inFileName);
695 readEcho(in, outFileName);
696
697 // Read numbers of replicas along each direction
698 IntVec<D> replicas;
699 for (int i = 0; i < D; i++){
700 in >> replicas[i];
701 }
702 for (int i = 0; i < D; i++){
703 Log::file() << "Replicate unit cell in direction "
704 << i << " : ";
705 Log::file() << replicas[i] << " times ";
706 Log::file() << "\n";
707 }
708 fieldIo.replicateUnitCell(inFileName, outFileName, replicas);
709
710 } else
711 if (command == "ESTIMATE_W_BASIS") {
712 readEcho(in, inFileName);
713 readEcho(in, outFileName);
714 fieldIo.estimateWBasis(inFileName, outFileName,
715 interaction().chi());
716 } else
717 if (command == "READ_H_BASIS") {
718 readEcho(in, filename);
719 h().readBasis(filename);
720 UTIL_CHECK(!c_.hasData());
721 } else
722 if (command == "READ_H_RGRID") {
723 readEcho(in, filename);
724 h().readRGrid(filename);
725 UTIL_CHECK(!c_.hasData());
726 } else
727 if (command == "WRITE_H_BASIS") {
728 readEcho(in, filename);
729 h().writeBasis(filename);
730 } else
731 if (command == "WRITE_H_RGRID") {
732 readEcho(in, filename);
733 h().writeRGrid(filename);
734 } else
735 if (command == "READ_MASK_BASIS") {
736 readEcho(in, filename);
737 mask().readBasis(filename);
738 } else
739 if (command == "READ_MASK_RGRID") {
740 readEcho(in, filename);
741 mask().readRGrid(filename);
742 } else
743 if (command == "WRITE_MASK_BASIS") {
744 readEcho(in, filename);
745 mask().writeBasis(filename);
746 } else
747 if (command == "WRITE_MASK_RGRID") {
748 readEcho(in, filename);
749 mask().writeRGrid(filename);
750 } else
751 if (command == "WRITE_TIMERS") {
752 readEcho(in, filename);
753 std::ofstream file;
754 fileMaster_.openOutputFile(filename, file);
755 writeTimers(file);
756 file.close();
757 } else
758 if (command == "CLEAR_TIMERS") {
759 clearTimers();
760 } else {
761 Log::file() << "Error: Unknown command "
762 << command << std::endl;
763 readNext = false;
764 }
765 }
766 }
767
768 /*
769 * Read and execute commands from the default command file.
770 */
771 template <int D, class T>
773 {
774 if (fileMaster_.commandFileName().empty()) {
775 UTIL_THROW("Empty command file name");
776 }
777 readCommands(fileMaster_.commandFile());
778 }
779
780 // Primary Field Theory Computations
781
782 /*
783 * Solve MDE for current w fields, without iteration.
784 */
785 template <int D, class T>
786 void SystemTmpl<D,T>::compute(bool needStress)
787 {
788 // Preconditions
789 UTIL_CHECK(isAllocatedGrid_);
790 UTIL_CHECK(w_.isAllocatedRGrid());
791 UTIL_CHECK(c_.isAllocatedRGrid());
792 UTIL_CHECK(w_.hasData());
793 clearCFields();
794
795 // Make sure Environment is up-to-date
796 if (hasEnvironment()) {
797 if (environment().needsUpdate()) {
798 environment().generate();
799 }
800 }
801
802 // Solve the modified diffusion equation (without iteration)
803 mixture_.compute(w_.rgrid(), c_.rgrid(), mask_.phiTot());
804 mixture_.setIsSymmetric(w_.isSymmetric());
805 c_.setHasData(true);
806 scft().clear();
807
808 // If w fields are symmetric, compute basis components for c fields
809 if (w_.isSymmetric()) {
810 UTIL_CHECK(c_.isAllocatedBasis());
811 domain_.fieldIo().convertRGridToBasis(c_.rgrid(), c_.basis(),
812 false);
813 c_.setIsSymmetric(true);
814 }
815
816 // Compute stress if needed
817 if (needStress) {
819 }
820 }
821
822 /*
823 * Compute SCFT stress for current fields.
824 */
825 template <int D, class T>
827 {
828 // Compute and store standard Mixture stress
829 if (!mixture_.hasStress()) {
830 mixture_.computeStress(mask().phiTot());
831 }
832
833 // If necessary, compute and store Environment stress
834 if (hasEnvironment()) {
835 if (!environment().hasStress()) {
836 environment().computeStress(mixture(),
837 iterator().flexibleParams());
838 }
839 }
840 }
841
842 /*
843 * Iteratively solve a SCFT problem.
844 */
845 template <int D, class T>
846 int SystemTmpl<D,T>::iterate(bool isContinuation)
847 {
848 // Preconditions
850 UTIL_CHECK(w_.hasData());
851 if (iterator().isSymmetric()) {
852 UTIL_CHECK(isAllocatedBasis_);
853 UTIL_CHECK(w_.isSymmetric());
854 }
855 clearCFields();
856
857 Log::file() << std::endl;
858 Log::file() << std::endl;
859
860 // Make sure Environment is up-to-date
861 if (hasEnvironment()) {
862 if (environment().needsUpdate()) {
863 environment().generate();
864 }
865 }
866
867 // Call iterator (return 0 for convergence, 1 for failure)
868 int error = iterator().solve(isContinuation);
869 UTIL_CHECK(c_.hasData());
870
871 // If converged, compute related thermodynamic properties
872 if (!error) {
873 scft().compute();
874 scft().write(Log::file());
875 if (!iterator().isFlexible()) {
876 if (!mixture().hasStress()) {
878 }
879 mixture().writeStress(Log::file());
880 if (hasEnvironment()) {
881 environment().writeStress(Log::file());
882 }
883 }
884 }
885
886 return error;
887 }
888
889 /*
890 * Perform an SCFT sweep along a path in parameter space.
891 */
892 template <int D, class T>
894 {
895 // Preconditions
898 UTIL_CHECK(w_.hasData());
899 if (iterator().isSymmetric()) {
900 UTIL_CHECK(isAllocatedBasis_);
901 UTIL_CHECK(w_.isSymmetric());
902 }
903
904 Log::file() << std::endl;
905 Log::file() << std::endl;
906
907 // Perform sweep
908 sweepPtr_->sweep();
909 }
910
911 /*
912 * Perform a field theoretic simulation of nStep steps.
913 */
914 template <int D, class T>
916 {
917 UTIL_CHECK(nStep > 0);
919 clearCFields();
920
921 simulator().simulate(nStep);
922 }
923
924 /*
925 * Mark c-fields and free energy as outdated/invalid.
926 */
927 template <int D, class T>
929 {
930 c_.setHasData(false);
931 scft().clear();
932 }
933
934 // Unit Cell Modifiers
935
936 /*
937 * Set the system unit cell.
938 */
939 template <int D, class T>
941 {
942 // Preconditions
943 UTIL_CHECK(domain_.lattice() != UnitCell<D>::Null);
944 UTIL_CHECK(domain_.lattice() == unitCell.lattice());
945
946 // Set system unit cell
947 domain_.unitCell() = unitCell;
948
949 // If necessary, make basis
950 if (domain_.hasGroup() && !domain_.basis().isInitialized()) {
951 domain_.makeBasis();
952 }
953
954 // Postconditions
955 UTIL_CHECK(domain_.unitCell().isInitialized());
956 UTIL_CHECK(domain_.unitCell().lattice() == domain_.lattice());
957 if (domain_.hasGroup()) {
958 UTIL_CHECK(domain_.basis().isInitialized());
959 UTIL_CHECK(isAllocatedBasis_);
960 }
961 UTIL_CHECK(!domain_.waveList().hasKSq());
962 }
963
964 /*
965 * Set parameters of the system unit cell.
966 */
967 template <int D, class T>
969 {
970 // Precondition
971 UTIL_CHECK(domain_.lattice() != UnitCell<D>::Null);
972
973 // Set system unit cell
974 if (domain_.unitCell().lattice() == UnitCell<D>::Null) {
975 domain_.unitCell().set(domain_.lattice(), parameters);
976 } else {
977 domain_.unitCell().setParameters(parameters);
978 }
979
980 // If necessary, make basis
981 if (domain_.hasGroup() && !domain_.basis().isInitialized()) {
982 domain_.makeBasis();
983 }
984
985 // Postconditions
986 UTIL_CHECK(domain_.unitCell().isInitialized());
987 UTIL_CHECK(domain_.unitCell().lattice() == domain_.lattice());
988 if (domain_.hasGroup()) {
989 UTIL_CHECK(domain_.basis().isInitialized());
990 UTIL_CHECK(isAllocatedBasis_);
991 }
992 UTIL_CHECK(!domain_.waveList().hasKSq());
993 }
994
995 /*
996 * Notify SystemTmpl members that unit cell parameters have been modified.
997 */
998 template <int D, class T>
1000 {
1001 clearCFields();
1002 mixture_.clearUnitCellData();
1003 domain_.waveList().clearUnitCellData();
1004 if (hasEnvironment()) {
1005 environment().reset();
1006 }
1007 }
1008
1009 // Property Output
1010
1011 /*
1012 * Write parameter file for SCFT, omitting any sweep block.
1013 */
1014 template <int D, class T>
1015 void SystemTmpl<D,T>::writeParamNoSweep(std::ostream& out) const
1016 {
1017 out << "SystemTmpl{" << std::endl;
1018 mixture_.writeParam(out);
1019 interaction().writeParam(out);
1020 domain_.writeParam(out);
1021 if (hasEnvironment()) {
1022 environment().writeParam(out);
1023 }
1024 if (hasIterator()) {
1025 iterator().writeParam(out);
1026 }
1027 out << "}" << std::endl;
1028 }
1029
1030 // Timer Operations
1031
1032 /*
1033 * Write timer values to output stream (computational cost).
1034 */
1035 template <int D, class T>
1036 void SystemTmpl<D,T>::writeTimers(std::ostream& out) const
1037 {
1038 if (hasIterator()) {
1039 iterator().outputTimers(Log::file());
1040 iterator().outputTimers(out);
1041 }
1042 if (hasSimulator()){
1043 simulator().outputTimers(Log::file());
1044 simulator().outputTimers(out);
1045 }
1046 }
1047
1048 /*
1049 * Clear state of all timers.
1050 */
1051 template <int D, class T>
1053 {
1054 if (hasIterator()) {
1055 iterator().clearTimers();
1056 }
1057 if (hasSimulator()){
1058 simulator().clearTimers();
1059 }
1060 }
1061
1062 // Private member functions
1063
1064 /*
1065 * Allocate memory for fields in grid format.
1066 */
1067 template <int D, class T>
1068 void SystemTmpl<D,T>::allocateFieldsGrid()
1069 {
1070 // Preconditions
1071 UTIL_CHECK(hasMixture_);
1072 int nMonomer = mixture_.nMonomer();
1073 UTIL_CHECK(nMonomer > 0);
1074 UTIL_CHECK(domain_.mesh().size() > 0);
1075 UTIL_CHECK(!isAllocatedGrid_);
1076
1077 // Alias for mesh dimensions
1078 IntVec<D> const & dimensions = domain_.mesh().dimensions();
1079
1080 // Allocate w (chemical potential) fields
1081 w_.setNMonomer(nMonomer);
1082 w_.allocateRGrid(dimensions);
1083
1084 // Allocate c (monomer concentration) fields
1085 c_.setNMonomer(nMonomer);
1086 c_.allocateRGrid(dimensions);
1087
1088 // Set nMonomer for external field container
1089 h_.setNMonomer(nMonomer);
1090
1091 // If hasEnvironment(), allocate mask and h fields
1092 if (hasEnvironment()) {
1093 if (environment().generatesMask()) {
1094 mask_.allocateRGrid(dimensions);
1095 }
1096 if (environment().generatesExternalFields()) {
1097 h_.allocateRGrid(dimensions);
1098 }
1099 }
1100
1101 isAllocatedGrid_ = true;
1102 }
1103
1104 /*
1105 * Allocate memory for fields in basis format.
1106 */
1107 template <int D, class T>
1108 void SystemTmpl<D,T>::allocateFieldsBasis()
1109 {
1110 // Preconditions and constants
1111 UTIL_CHECK(hasMixture_);
1112 const int nMonomer = mixture_.nMonomer();
1113 UTIL_CHECK(nMonomer > 0);
1114 UTIL_CHECK(domain_.mesh().size() > 0);
1115 UTIL_CHECK(domain_.hasGroup());
1116 UTIL_CHECK(domain_.basis().isInitialized());
1117 const int nBasis = domain_.basis().nBasis();
1118 UTIL_CHECK(nBasis > 0);
1119 UTIL_CHECK(isAllocatedGrid_);
1120 UTIL_CHECK(!isAllocatedBasis_);
1121
1122 // Allocate basis fields in w and c field containers
1123 w_.allocateBasis(nBasis);
1124 c_.allocateBasis(nBasis);
1125
1126 // If hasEnvironment(), allocate mask and h fields
1127 if (hasEnvironment()) {
1128 if (environment().generatesMask()) {
1129 mask_.allocateBasis(nBasis);
1130 }
1131 if (environment().generatesExternalFields()) {
1132 h_.allocateBasis(nBasis);
1133 }
1134 }
1135
1136 isAllocatedBasis_ = true;
1137 }
1138
1139 /*
1140 * Read a filename string and echo to log file (used in readCommands).
1141 */
1142 template <int D, class T>
1143 void SystemTmpl<D,T>::readEcho(std::istream& in, std::string& string) const
1144 {
1145 in >> string;
1146 if (in.fail()) {
1147 UTIL_THROW("Unable to read a string parameter.");
1148 }
1149 Log::file() << " " << Str(string, 20) << std::endl;
1150 }
1151
1152 /*
1153 * Read floating point number, echo to log file (used in readCommands).
1154 */
1155 template <int D, class T>
1156 void SystemTmpl<D,T>::readEcho(std::istream& in, double& value) const
1157 {
1158 in >> value;
1159 if (in.fail()) {
1160 UTIL_THROW("Unable to read floating point parameter.");
1161 }
1162 Log::file() << " " << Dbl(value, 20) << std::endl;
1163 }
1164
1165} // namespace Prdc
1166} // namespace Pscf
1167#endif
An IntVec<D, T> is a D-component vector of elements of integer type T.
Definition IntVec.h:27
T::Mask & mask()
Get the mask (non-const).
Definition SystemTmpl.h:864
void compute(bool needStress=false)
Solve the modified diffusion equation once, without iteration.
bool hasIterator() const
Does this system have an Iterator?
Definition SystemTmpl.h:782
T::Simulator & simulator()
Get the Simulator (non-const).
Definition SystemTmpl.h:813
Types< D >::Interaction & interaction()
Definition SystemTmpl.h:724
int iterate(bool isContinuation=false)
Iteratively solve a SCFT problem.
virtual void readParameters(std::istream &in)
Read body of parameter block (without opening and closing lines).
T::Environment & environment()
Get the Environment (non-const).
Definition SystemTmpl.h:750
T::ScftThermo & scft()
Get the ScftThermo object (non-const).
Definition SystemTmpl.h:766
void readCommands(std::istream &in)
Read and process commands from an input stream.
void clearCFields()
Mark c-fields and free energy as outdated or invalid.
void readParam()
Read input parameters from default param file.
void setUnitCell(UnitCell< D > const &unitCell)
Set parameters of the associated unit cell.
T::WFields & w()
Get the chemical potential (w) fields (non-const).
Definition SystemTmpl.h:844
void setOptions(int argc, char **argv)
Process command line options.
void simulate(int nStep)
Perform a field theoretic simulation (PS-FTS).
T::MixtureModifier & mixtureModifier()
Get the MixtureModifier (non-const).
Definition SystemTmpl.h:716
bool hasSimulator() const
Does this system have a Simulator?
Definition SystemTmpl.h:808
bool hasSweep() const
Does this system have a Sweep?
Definition SystemTmpl.h:803
Types< D >::Mixture const & mixture() const
Definition SystemTmpl.h:711
void sweep()
Sweep in parameter space, solving an SCF problem at each point.
T::Iterator & iterator()
Get the Iterator (non-const).
Definition SystemTmpl.h:787
void writeTimers(std::ostream &out) const
Write timer information to an output stream.
void clearTimers()
Clear timers.
void readCommands()
Read and process commands from the default command file.
Types< D >::CFields const & c() const
Definition SystemTmpl.h:839
void writeParamNoSweep(std::ostream &out) const
Write partial parameter file to an ostream.
bool hasEnvironment() const
Does this system have an Environment?
Definition SystemTmpl.h:745
void clearUnitCellData()
Notify System members that unit cell parameters have been modified.
SystemTmpl(typename T::System &system)
Constructor.
virtual void readParam(std::istream &in)
Read input parameters (with opening and closing lines).
Base template for UnitCell<D> classes, D=1, 2 or 3.
Definition UnitCell.h:56
Dynamically allocatable contiguous array template.
Definition DArray.h:32
void allocate(int capacity)
Allocate the underlying C array.
Definition DArray.h:199
Wrapper for a double precision number, for formatted ostream output.
Definition Dbl.h:40
A fixed capacity (static) contiguous array with a variable logical size.
Definition FSArray.h:38
static std::ostream & file()
Get log ostream by reference.
Definition Log.cpp:59
std::string indent() const
Return indent string for this object (string of spaces).
static bool echo()
Get echo parameter.
static void setEcho(bool echo=true)
Enable or disable echoing for all subclasses of ParamComponent.
Begin & readBegin(std::istream &in, const char *label, bool isRequired=true)
Add and read a class label and opening bracket.
void setClassName(const char *className)
Set class name string.
ScalarParam< Type > & readOptional(std::istream &in, const char *label, Type &value)
Add and read a new optional ScalarParam < Type > object.
std::string className() const
Get class name string.
void readParamComposite(std::istream &in, ParamComposite &child, bool next=true)
Add and read a required child ParamComposite.
End & readEnd(std::istream &in)
Add and read the closing bracket.
Notifier (or subject) in the Observer design pattern.
Definition Signal.h:39
void addObserver(Observer &observer, void(Observer::*methodPtr)(const T &))
Register an observer.
Definition Signal.h:111
Wrapper for a std::string, for formatted ostream output.
Definition Str.h:37
#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 hasSymmetry(AT const &in, Basis< D > const &basis, IntVec< D > const &dftDimensions, double epsilon=1.0e-8, bool verbose=true)
Check if a k-grid field has the declared space group symmetry.
Enumeration and functions to specify a model for polymer chains.
int nSet()
How many times has setModel been called?
void setModel(Type model)
Set the global polymer model enumeration value.
bool isLocked()
Has the model type been locked (i.e., made immutable) ?
Periodic fields and crystallography.
Definition CField.cpp:11
PSCF package top-level namespace.
Definition param_pc.dox:1
void set(BracketPolicy::Type policy)
Set policy regarding use of bracket delimiters on arrays.