13#include <rpc/fts/simulator/Simulator.h>
14#include <rpc/fts/simulator/SimulatorFactory.h>
15#include <rpc/fts/compressor/Compressor.h>
16#include <rpc/scft/sweep/Sweep.h>
17#include <rpc/scft/sweep/SweepFactory.h>
18#include <rpc/scft/iterator/Iterator.h>
19#include <rpc/scft/iterator/IteratorFactory.h>
20#include <rpc/scft/ScftThermo.h>
21#include <rpc/environment/EnvironmentFactory.h>
22#include <rpc/solvers/MixtureModifier.h>
23#include <rpc/solvers/Polymer.h>
24#include <rpc/solvers/Solvent.h>
27#include <prdc/cpu/RField.h>
28#include <prdc/cpu/RFieldDft.h>
29#include <prdc/cpu/RFieldComparison.h>
30#include <prdc/crystal/BFieldComparison.h>
31#include <prdc/environment/Environment.h>
33#include <pscf/inter/Interaction.h>
34#include <pscf/math/IntVec.h>
36#include <util/containers/DArray.h>
37#include <util/containers/FSArray.h>
38#include <util/param/BracketPolicy.h>
39#include <util/param/ParamComponent.h>
40#include <util/signal/Signal.h>
41#include <util/format/Str.h>
42#include <util/format/Int.h>
43#include <util/format/Dbl.h>
44#include <util/misc/ioUtil.h>
68 mixtureModifierPtr_(nullptr),
69 interactionPtr_(nullptr),
70 environmentPtr_(nullptr),
71 environmentFactoryPtr_(nullptr),
73 iteratorPtr_(nullptr),
74 iteratorFactoryPtr_(nullptr),
76 sweepFactoryPtr_(nullptr),
77 simulatorPtr_(nullptr),
78 simulatorFactoryPtr_(nullptr),
80 isAllocatedGrid_(false),
81 isAllocatedBasis_(false),
99 domain_.setFileMaster(fileMaster_);
100 w_.setFieldIo(domain_.fieldIo());
101 w_.setReadUnitCell(domain_.unitCell());
102 w_.setWriteUnitCell(domain_.unitCell());
103 h_.setFieldIo(domain_.fieldIo());
104 h_.setReadUnitCell(tmpUnitCell_);
105 h_.setWriteUnitCell(domain_.unitCell());
106 mask_.setFieldIo(domain_.fieldIo());
107 mask_.setReadUnitCell(tmpUnitCell_);
108 mask_.setWriteUnitCell(domain_.unitCell());
109 c_.setFieldIo(domain_.fieldIo());
110 c_.setWriteUnitCell(domain_.unitCell());
141 basisSignal.
addObserver(*
this, &System<D>::allocateFieldsBasis);
159 if (interactionPtr_) {
160 delete interactionPtr_;
162 if (environmentPtr_) {
163 delete environmentPtr_;
165 if (environmentFactoryPtr_) {
166 delete environmentFactoryPtr_;
174 if (iteratorFactoryPtr_) {
175 delete iteratorFactoryPtr_;
180 if (sweepFactoryPtr_) {
181 delete sweepFactoryPtr_;
184 delete simulatorPtr_;
186 if (simulatorFactoryPtr_) {
187 delete simulatorFactoryPtr_;
216 while ((
c = getopt(argc, argv,
"ed:p:c:i:o:t:")) != -1) {
246 Log::file() <<
"Unknown option -" << optopt << std::endl;
262 fileMaster_.setParamFileName(std::string(pArg));
264 UTIL_THROW(
"Missing required -p option - no parameter file");
269 fileMaster_.setCommandFileName(std::string(cArg));
271 UTIL_THROW(
"Missing required -c option - no command file");
281 fileMaster_.setInputPrefix(std::string(iArg));
286 fileMaster_.setOutputPrefix(std::string(oArg));
292 UTIL_THROW(
"Error: Non-positive thread count -t option");
307 polymerModel_ = PolymerModel::Thread;
324 int nm = mixture_.nMonomer();
325 int np = mixture_.nPolymer();
326 int ns = mixture_.nSolvent();
339 UTIL_CHECK(domain_.unitCell().nParameter() > 0);
341 domain_.fieldIo().setNMonomer(nm);
344 mixture_.associate(domain_.mesh(), domain_.fft(),
345 domain_.unitCell(), domain_.waveList());
346 mixture_.setFieldIo(domain_.fieldIo());
350 allocateFieldsGrid();
356 environmentFactoryPtr_->readObjectOptional(in, *
this,
className,
361 if (environmentPtr_) {
362 environment().setNParams(domain_.unitCell().nParameter());
368 iteratorFactoryPtr_->readObjectOptional(in, *
this,
className,
378 sweepFactoryPtr_->readObjectOptional(in, *
this,
className,
388 simulatorFactoryPtr_->readObjectOptional(in, *
this,
424 std::string command, filename, inFileName, outFileName;
425 FieldIo<D> const & fieldIo = domain_.fieldIo();
427 bool readNext =
true;
438 if (command ==
"FINISH") {
442 if (command ==
"READ_W_BASIS") {
443 readEcho(in, filename);
444 w().readBasis(filename);
445 UTIL_CHECK(domain_.unitCell().isInitialized());
452 if (command ==
"READ_W_RGRID") {
453 readEcho(in, filename);
454 w().readRGrid(filename);
455 UTIL_CHECK(domain_.unitCell().isInitialized());
460 if (command ==
"SET_UNIT_CELL") {
463 Log::file() <<
" " << unitCell << std::endl;
465 UTIL_CHECK(domain_.unitCell().isInitialized());
470 if (command ==
"COMPUTE") {
474 if (command ==
"ITERATE") {
476 bool isContinuation =
false;
477 int fail =
iterate(isContinuation);
482 if (command ==
"SWEEP") {
487 if (command ==
"COMPRESS") {
492 if (command ==
"SIMULATE") {
499 if (command ==
"ANALYZE" || command ==
"ANALYZE_TRAJECTORY") {
506 std::string classname;
507 readEcho(in, classname);
508 readEcho(in, filename);
509 simulator().analyze(min, max, classname, filename);
511 if (command ==
"WRITE_PARAM") {
512 readEcho(in, filename);
514 fileMaster_.openOutputFile(filename, file);
518 if (command ==
"WRITE_THERMO") {
519 readEcho(in, filename);
521 fileMaster_.openOutputFile(filename, file,
526 if (command ==
"WRITE_STRESS") {
527 readEcho(in, filename);
532 fileMaster_.openOutputFile(filename, file,
540 if (command ==
"WRITE_W_BASIS") {
541 readEcho(in, filename);
542 w().writeBasis(filename);
544 if (command ==
"WRITE_W_RGRID") {
545 readEcho(in, filename);
546 w().writeRGrid(filename);
548 if (command ==
"WRITE_C_BASIS") {
549 readEcho(in, filename);
550 c().writeBasis(filename);
552 if (command ==
"WRITE_C_RGRID") {
553 readEcho(in, filename);
554 c().writeRGrid(filename);
556 if (command ==
"WRITE_BLOCK_C_RGRID") {
557 readEcho(in, filename);
558 mixture_.writeBlockCRGrid(filename);
560 if (command ==
"WRITE_Q_SLICE") {
561 int polymerId, blockId, directionId, segmentId;
562 readEcho(in, filename);
567 Log::file() <<
Str(
"polymer ID ", 21) << polymerId <<
"\n"
568 <<
Str(
"block ID ", 21) << blockId <<
"\n"
569 <<
Str(
"direction ID ", 21) << directionId
571 <<
Str(
"segment ID ", 21) << segmentId
573 mixture_.writeQSlice(filename, polymerId, blockId,
574 directionId, segmentId);
576 if (command ==
"WRITE_Q_TAIL") {
577 readEcho(in, filename);
578 int polymerId, blockId, directionId;
582 Log::file() <<
Str(
"polymer ID ", 21) << polymerId <<
"\n"
583 <<
Str(
"block ID ", 21) << blockId <<
"\n"
584 <<
Str(
"direction ID ", 21) << directionId
586 mixture_.writeQTail(filename, polymerId, blockId, directionId);
588 if (command ==
"WRITE_Q") {
589 readEcho(in, filename);
590 int polymerId, blockId, directionId;
594 Log::file() <<
Str(
"polymer ID ", 21) << polymerId <<
"\n"
595 <<
Str(
"block ID ", 21) << blockId <<
"\n"
596 <<
Str(
"direction ID ", 21) << directionId
598 mixture_.writeQ(filename, polymerId, blockId, directionId);
600 if (command ==
"WRITE_Q_ALL") {
601 readEcho(in, filename);
602 mixture_.writeQAll(filename);
604 if (command ==
"WRITE_STARS") {
605 readEcho(in, filename);
606 domain_.writeStars(filename);
608 if (command ==
"WRITE_WAVES") {
609 readEcho(in, filename);
610 domain_.writeWaves(filename);
612 if (command ==
"WRITE_GROUP") {
613 readEcho(in, filename);
614 domain_.writeGroup(filename);
616 if (command ==
"BASIS_TO_RGRID") {
617 readEcho(in, inFileName);
618 readEcho(in, outFileName);
621 if (command ==
"RGRID_TO_BASIS") {
622 readEcho(in, inFileName);
623 readEcho(in, outFileName);
626 if (command ==
"KGRID_TO_RGRID") {
627 readEcho(in, inFileName);
628 readEcho(in, outFileName);
631 if (command ==
"RGRID_TO_KGRID") {
632 readEcho(in, inFileName);
633 readEcho(in, outFileName);
636 if (command ==
"BASIS_TO_KGRID") {
637 readEcho(in, inFileName);
638 readEcho(in, outFileName);
641 if (command ==
"KGRID_TO_BASIS") {
642 readEcho(in, inFileName);
643 readEcho(in, outFileName);
646 if (command ==
"CHECK_RGRID_SYMMETRY") {
648 readEcho(in, inFileName);
649 readEcho(in, epsilon);
654 <<
"Symmetry of r-grid file matches this space group"
655 << std::endl << std::endl;
658 <<
"Symmetry of r-grid file does not match this\n"
659 <<
"space group to within error threshold of "
660 <<
Dbl(epsilon) <<
" ." << std::endl << std::endl;
663 if (command ==
"COMPARE_BASIS") {
664 std::string filecompare1, filecompare2;
665 readEcho(in, filecompare1);
666 readEcho(in, filecompare2);
669 if (command ==
"COMPARE_RGRID") {
670 std::string filecompare1, filecompare2;
671 readEcho(in, filecompare1);
672 readEcho(in, filecompare2);
675 if (command ==
"SCALE_BASIS") {
677 readEcho(in, inFileName);
678 readEcho(in, outFileName);
679 readEcho(in, factor);
682 if (command ==
"SCALE_RGRID") {
684 readEcho(in, inFileName);
685 readEcho(in, outFileName);
686 readEcho(in, factor);
689 if (command ==
"EXPAND_RGRID_DIMENSION") {
690 readEcho(in, inFileName);
691 readEcho(in, outFileName);
697 Log::file() <<
Str(
"Expand dimension to: ") << d <<
"\n";
702 for (
int i = 0; i < d-D; i++) {
703 in >> newGridDimensions[i];
706 <<
Str(
"Numbers of grid points in added dimensions : ");
707 for (
int i = 0; i < d-D; i++) {
708 Log::file() << newGridDimensions[i] <<
" ";
713 d, newGridDimensions);
716 if (command ==
"REPLICATE_UNIT_CELL") {
717 readEcho(in, inFileName);
718 readEcho(in, outFileName);
722 for (
int i = 0; i < D; i++){
725 for (
int i = 0; i < D; i++){
726 Log::file() <<
"Replicate unit cell in direction "
734 if (command ==
"ESTIMATE_W_BASIS") {
735 readEcho(in, inFileName);
736 readEcho(in, outFileName);
740 if (command ==
"READ_H_BASIS") {
741 readEcho(in, filename);
742 h().readBasis(filename);
745 if (command ==
"READ_H_RGRID") {
746 readEcho(in, filename);
747 h().readRGrid(filename);
750 if (command ==
"WRITE_H_BASIS") {
751 readEcho(in, filename);
752 h().writeBasis(filename);
754 if (command ==
"WRITE_H_RGRID") {
755 readEcho(in, filename);
756 h().writeRGrid(filename);
758 if (command ==
"READ_MASK_BASIS") {
759 readEcho(in, filename);
760 mask().readBasis(filename);
762 if (command ==
"READ_MASK_RGRID") {
763 readEcho(in, filename);
764 mask().readRGrid(filename);
766 if (command ==
"WRITE_MASK_BASIS") {
767 readEcho(in, filename);
768 mask().writeBasis(filename);
770 if (command ==
"WRITE_MASK_RGRID") {
771 readEcho(in, filename);
772 mask().writeRGrid(filename);
774 if (command ==
"WRITE_TIMERS") {
775 readEcho(in, filename);
777 fileMaster_.openOutputFile(filename, file);
781 if (command ==
"CLEAR_TIMERS") {
785 << command << std::endl;
797 if (fileMaster_.commandFileName().empty()) {
826 mixture_.compute(w_.rgrid(), c_.rgrid(), mask_.phiTot());
827 mixture_.setIsSymmetric(w_.isSymmetric());
832 if (w_.isSymmetric()) {
834 domain_.fieldIo().convertRGridToBasis(c_.rgrid(), c_.basis(),
836 c_.setIsSymmetric(
true);
852 if (!mixture_.hasStress()) {
853 mixture_.computeStress(
mask().phiTot());
891 int error =
iterator().solve(isContinuation);
953 c_.setHasData(
false);
967 UTIL_CHECK(domain_.lattice() == unitCell.lattice());
970 domain_.unitCell() = unitCell;
973 if (domain_.hasGroup() && !domain_.basis().isInitialized()) {
978 UTIL_CHECK(domain_.unitCell().isInitialized());
979 UTIL_CHECK(domain_.unitCell().lattice() == domain_.lattice());
980 if (domain_.hasGroup()) {
998 domain_.unitCell().set(domain_.lattice(), parameters);
1000 domain_.unitCell().setParameters(parameters);
1004 if (domain_.hasGroup() && !domain_.basis().isInitialized()) {
1005 domain_.makeBasis();
1009 UTIL_CHECK(domain_.unitCell().isInitialized());
1010 UTIL_CHECK(domain_.unitCell().lattice() == domain_.lattice());
1011 if (domain_.hasGroup()) {
1025 mixture_.clearUnitCellData();
1026 domain_.waveList().clearUnitCellData();
1040 out <<
"System{" << std::endl;
1041 mixture_.writeParam(out);
1043 domain_.writeParam(out);
1050 out <<
"}" << std::endl;
1091 void System<D>::allocateFieldsGrid()
1095 int nMonomer = mixture_.nMonomer();
1101 IntVec<D> const & dimensions = domain_.mesh().dimensions();
1104 w_.setNMonomer(nMonomer);
1105 w_.allocateRGrid(dimensions);
1108 c_.setNMonomer(nMonomer);
1109 c_.allocateRGrid(dimensions);
1112 h_.setNMonomer(nMonomer);
1115 if (hasEnvironment()) {
1116 if (environment().generatesMask()) {
1117 mask_.allocateRGrid(dimensions);
1119 if (environment().generatesExternalFields()) {
1120 h_.allocateRGrid(dimensions);
1124 isAllocatedGrid_ =
true;
1131 void System<D>::allocateFieldsBasis()
1135 const int nMonomer = mixture_.nMonomer();
1140 const int nBasis = domain_.basis().nBasis();
1146 w_.allocateBasis(nBasis);
1147 c_.allocateBasis(nBasis);
1150 if (hasEnvironment()) {
1151 if (environment().generatesMask()) {
1152 mask_.allocateBasis(nBasis);
1154 if (environment().generatesExternalFields()) {
1155 h_.allocateBasis(nBasis);
1159 isAllocatedBasis_ =
true;
1166 void System<D>::readEcho(std::istream& in, std::string&
string)
const
1170 UTIL_THROW(
"Unable to read a string parameter.");
1179 void System<D>::readEcho(std::istream& in,
double& value)
const
1183 UTIL_THROW(
"Unable to read floating point parameter.");
An IntVec<D, T> is a D-component vector of elements of integer type T.
Flory-Huggins excess free energy model.
Base template for UnitCell<D> classes, D=1, 2 or 3.
Factory for subclasses of Environment.
File input/output operations and format conversions for fields.
void expandRGridDimension(std::ostream &out, DArray< RField< D > > const &fields, UnitCell< D > const &unitCell, int d, DArray< int > const &newGridDimensions) const override
Expand spatial dimension of an array of r-grid fields.
void convertKGridToRGrid(DArray< RFieldDft< D > > const &in, DArray< RField< D > > &out) const
Convert an array of field from k-grid to r-grid format.
void convertRGridToBasis(RField< D > const &in, DArray< double > &out, bool checkSymmetry=true, double epsilon=1.0e-8) const
Convert a single field from r-grid to basis form.
void scaleFieldsBasis(DArray< DArray< double > > &fields, double factor) const
Multiply an array of fields in basis format by a real scalar.
void replicateUnitCell(std::ostream &out, DArray< RField< D > > const &fields, UnitCell< D > const &unitCell, IntVec< D > const &replicas) const override
Write r-grid fields in a replicated unit cell to std::ostream.
bool hasSymmetry(RFieldDft< D > const &in, double epsilon=1.0e-8, bool verbose=true) const override
Check if a k-grid field has the declared space group symmetry.
void compareFieldsRGrid(DArray< RField< D > > const &field1, DArray< RField< D > > const &field2) const override
Compare two fields in r-grid format, output a report.
void compareFieldsBasis(DArray< DArray< double > > const &field1, DArray< DArray< double > > const &field2) const
Compare array of fields in basis form, write a report to Log file.
void convertBasisToKGrid(DArray< double > const &components, RFieldDft< D > &dft) const override
Convert a field from symmetrized basis to Fourier grid (k-grid).
void convertRGridToKGrid(DArray< RField< D > > const &in, DArray< RFieldDft< D > > &out) const
Convert an array of fields from r-grid to k-grid (Fourier) format.
void estimateWBasis(DMatrix< double > const &chi, DArray< DArray< double > > &fields) const
Convert c fields to estimated w fields, in basis format.
void convertKGridToBasis(RFieldDft< D > const &in, DArray< double > &out, bool checkSymmetry=true, double epsilon=1.0e-8) const override
Convert a field from Fourier (k-grid) to symmetrized basis form.
void convertBasisToRGrid(DArray< double > const &in, RField< D > &out) const
Convert a single field from basis to r-grid format.
void scaleFieldsRGrid(DArray< RField< D > > &fields, double factor) const
Scale an array of r-grid fields by a scalar.
Factory for subclasses of Iterator.
Parameter modifier for an associated Mixture.
Computes SCFT free energies.
Factory for subclasses of Simulator.
Default Factory for subclasses of Sweep.
Mask< D > & mask()
Get the mask (non-const).
int iterate(bool isContinuation=false)
Iteratively solve a SCFT problem.
void compute(bool needStress=false)
Solve the modified diffusion equation once, without iteration.
void clearCFields()
Mark c-fields and free energy as outdated or invalid.
void setOptions(int argc, char **argv)
Process command line options.
Simulator< D > & simulator()
Get the Simulator (non-const).
void writeTimers(std::ostream &out) const
Write timer information to an output stream.
void readCommands()
Read and process commands from the default command file.
void simulate(int nStep)
Perform a field theoretic simulation (PS-FTS).
MixtureModifier< D > & mixtureModifier()
Get the MixtureModifier (non-const).
Iterator< D > & iterator()
Get the Iterator (non-const).
bool hasIterator() const
Does this system have an Iterator?
ScftThermo< D > & scft()
Get the ScftThermo object (non-const).
void setUnitCell(UnitCell< D > const &unitCell)
Set parameters of the associated unit cell.
CFieldContainer< D > const & c() const
Get the monomer concentration (c) fields (const).
void clearTimers()
Clear timers.
bool hasSimulator() const
Does this system have a Simulator?
WFieldContainer< D > & w()
Get the chemical potential (w) fields (non-const).
virtual void readParameters(std::istream &in)
Read body of parameter block (without opening and closing lines).
void writeParamNoSweep(std::ostream &out) const
Write partial parameter file to an ostream.
void sweep()
Sweep in parameter space, solving an SCF problem at each point.
void computeStress()
Compute SCFT stress.
bool hasSweep() const
Does this system have a Sweep?
void clearUnitCellData()
Notify System members that unit cell parameters have been modified.
bool hasEnvironment() const
Does this system have an Environment?
Environment & environment()
Get the Environment (non-const).
void readCommands(std::istream &in)
Read and process commands from an input stream.
void readParam()
Read input parameters from default param file.
WFieldContainer< D > & h()
Get the external potential (h) fields (non-const).
Interaction & interaction()
Get the Interaction (non-const).
virtual void readParam(std::istream &in)
Read input parameters (with opening and closing lines).
Mixture< D > const & mixture() const
Get the Mixture (const).
Dynamically allocatable contiguous array template.
void allocate(int capacity)
Allocate the underlying C array.
Wrapper for a double precision number, for formatted ostream output.
A fixed capacity (static) contiguous array with a variable logical size.
static std::ostream & file()
Get log ostream by reference.
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.
void addObserver(Observer &observer, void(Observer::*methodPtr)(const T &))
Register an observer.
Wrapper for a std::string, for formatted ostream output.
#define UTIL_CHECK(condition)
Assertion macro suitable for serial or parallel production code.
#define UTIL_THROW(msg)
Macro for throwing an Exception, reporting function, file and line number.
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) ?
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.
void set(BracketPolicy::Type policy)
Set policy regarding use of bracket delimiters on arrays.