PSCF v1.1
fd1d/System.cpp
1/*
2* PSCF - Polymer Self-Consistent Field Theory
3*
4* Copyright 2016 - 2022, The Regents of the University of Minnesota
5* Distributed under the terms of the GNU General Public License.
6*/
7
8#include "System.h"
9
10#include <fd1d/iterator/Iterator.h>
11#include <fd1d/iterator/IteratorFactory.h>
12#include <fd1d/sweep/Sweep.h>
13#include <fd1d/sweep/SweepFactory.h>
14#include <fd1d/iterator/NrIterator.h>
15#include <fd1d/misc/HomogeneousComparison.h>
16#include <fd1d/misc/FieldIo.h>
17
18#include <pscf/inter/Interaction.h>
19#include <pscf/inter/Interaction.h>
20#include <pscf/homogeneous/Clump.h>
21
22#include <util/format/Str.h>
23#include <util/format/Int.h>
24#include <util/format/Dbl.h>
25#include <util/param/BracketPolicy.h>
26#include <util/misc/ioUtil.h>
27
28#include <string>
29#include <unistd.h>
30
31namespace Pscf {
32namespace Fd1d
33{
34
35 using namespace Util;
36
37 /*
38 * Constructor.
39 */
41 : mixture_(),
42 domain_(),
43 fileMaster_(),
44 fieldIo_(),
45 homogeneous_(),
46 interactionPtr_(0),
47 iteratorPtr_(0),
48 iteratorFactoryPtr_(0),
49 sweepPtr_(0),
50 sweepFactoryPtr_(0),
51 wFields_(),
52 cFields_(),
53 f_(),
54 c_(),
55 fHelmholtz_(0.0),
56 fIdeal_(0.0),
57 fInter_(0.0),
58 pressure_(0.0),
59 hasMixture_(0),
60 hasDomain_(0),
61 hasFields_(0),
62 hasSweep_(0)
63 {
64 setClassName("System");
65
66 fieldIo_.associate(domain_, fileMaster_);
67 interactionPtr_ = new Interaction();
68 iteratorFactoryPtr_ = new IteratorFactory(*this);
69 sweepFactoryPtr_ = new SweepFactory(*this);
70
71 BracketPolicy::set(BracketPolicy::Optional);
72 }
73
74 /*
75 * Destructor.
76 */
78 {
79 if (interactionPtr_) {
80 delete interactionPtr_;
81 }
82 if (iteratorPtr_) {
83 delete iteratorPtr_;
84 }
85 if (iteratorFactoryPtr_) {
86 delete iteratorFactoryPtr_;
87 }
88 if (sweepPtr_) {
89 delete sweepPtr_;
90 }
91 if (sweepFactoryPtr_) {
92 delete sweepFactoryPtr_;
93 }
94 }
95
96 /*
97 * Process command line options.
98 */
99 void System::setOptions(int argc, char **argv)
100 {
101 bool eflag = false; // echo
102 bool pFlag = false; // param file
103 bool cFlag = false; // command file
104 bool iFlag = false; // input prefix
105 bool oFlag = false; // output prefix
106 char* pArg = 0;
107 char* cArg = 0;
108 char* iArg = 0;
109 char* oArg = 0;
110
111 // Read program arguments
112 int c;
113 opterr = 0;
114 while ((c = getopt(argc, argv, "er:p:c:i:o:f")) != -1) {
115 switch (c) {
116 case 'e':
117 eflag = true;
118 break;
119 case 'p': // parameter file
120 pFlag = true;
121 pArg = optarg;
122 break;
123 case 'c': // command file
124 cFlag = true;
125 cArg = optarg;
126 break;
127 case 'i': // input prefix
128 iFlag = true;
129 iArg = optarg;
130 break;
131 case 'o': // output prefix
132 oFlag = true;
133 oArg = optarg;
134 break;
135 case '?':
136 Log::file() << "Unknown option -" << optopt << std::endl;
137 UTIL_THROW("Invalid command line option");
138 }
139 }
140
141 // Set flag to echo parameters as they are read.
142 if (eflag) {
144 }
145
146 // If option -p, set parameter file name
147 if (pFlag) {
148 fileMaster().setParamFileName(std::string(pArg));
149 }
150
151 // If option -c, set command file name
152 if (cFlag) {
153 fileMaster().setCommandFileName(std::string(cArg));
154 }
155
156 // If option -i, set path prefix for input files
157 if (iFlag) {
158 fileMaster().setInputPrefix(std::string(iArg));
159 }
160
161 // If option -o, set path prefix for output files
162 if (oFlag) {
163 fileMaster().setOutputPrefix(std::string(oArg));
164 }
165
166 }
167
168 /*
169 * Read parameters and initialize.
170 */
171 void System::readParameters(std::istream& in)
172 {
174 hasMixture_ = true;
175
176 // Initialize homogeneous object
177 int nm = mixture().nMonomer();
178 int np = mixture().nPolymer();
179 int ns = mixture().nSolvent();
180 homogeneous_.setNMolecule(np+ns);
181 homogeneous_.setNMonomer(nm);
182 initHomogeneous();
183
184 interaction().setNMonomer(mixture().nMonomer());
186
188 hasDomain_ = true;
189 allocateFields();
190
191 // Instantiate and initialize an Iterator
192 std::string className;
193 bool isEnd;
194 iteratorPtr_ = iteratorFactoryPtr_->readObject(in, *this,
195 className, isEnd);
196 if (!iteratorPtr_) {
197 std::string msg = "Unrecognized Iterator subclass name ";
198 msg += className;
199 UTIL_THROW(msg.c_str());
200 }
201
202 // Optionally instantiate and initialize a Sweep object
203 sweepPtr_ =
204 sweepFactoryPtr_->readObjectOptional(in, *this, className, isEnd);
205 if (sweepPtr_) {
206 hasSweep_ = true;
207 sweepPtr_->setSystem(*this);
208 } else {
209 hasSweep_ = false;
210 }
211 }
212
213 /*
214 * Read default parameter file.
215 */
216 void System::readParam(std::istream& in)
217 {
218 readBegin(in, className().c_str());
219 readParameters(in);
220 readEnd(in);
221 }
222
223 /*
224 * Read default parameter file.
225 */
227 { readParam(fileMaster().paramFile()); }
228
229 /*
230 * Write parameter file, omitting the sweep block.
231 */
232 void System::writeParamNoSweep(std::ostream& out) const
233 {
234 out << "System{" << std::endl;
235 mixture_.writeParam(out);
236 interactionPtr_->writeParam(out);
237 domain_.writeParam(out);
238 iteratorPtr_->writeParam(out);
239 out << "}" << std::endl;
240 }
241
242 /*
243 * Allocate memory for fields.
244 */
245 void System::allocateFields()
246 {
247 // Preconditions
248 UTIL_CHECK(hasMixture_);
249 UTIL_CHECK(hasDomain_);
250
251 // Allocate memory in mixture
253
254 // Allocate wFields and cFields
255 int nMonomer = mixture().nMonomer();
256 wFields_.allocate(nMonomer);
257 cFields_.allocate(nMonomer);
258 int nx = domain().nx();
259 for (int i = 0; i < nMonomer; ++i) {
260 wField(i).allocate(nx);
261 cField(i).allocate(nx);
262 }
263 hasFields_ = true;
264 }
265
266 /*
267 * Read and execute commands from a specified command file.
268 */
269 void System::readCommands(std::istream &in)
270 {
271 UTIL_CHECK(hasMixture_);
272 UTIL_CHECK(hasDomain_);
273
274 std::string command;
275 std::string filename;
276
277 std::istream& inBuffer = in;
278
279 bool readNext = true;
280 while (readNext) {
281
282 inBuffer >> command;
283
284 if (inBuffer.eof()) {
285 break;
286 } else {
287 Log::file() << command;
288 }
289
290 if (command == "FINISH") {
291 Log::file() << std::endl;
292 readNext = false;
293 } else
294 if (command == "READ_W") {
295 readEcho(inBuffer, filename);
296 fieldIo_.readFields(wFields(), filename);
297 } else
298 if (command == "COMPUTE") {
299 // Solve the modified diffusion equation, without iteration
300 Log::file() << std::endl;
301 compute();
302 } else
303 if (command == "ITERATE") {
304 // Attempt iteratively solve a single SCFT problem
305 bool isContinuation = false;
306 int fail = iterate(isContinuation);
307 if (fail) {
308 readNext = false;
309 }
310 } else
311 if (command == "SWEEP") {
312 // Attempt to solve a sequence of SCFT problems along a line
313 // through parameter space.
314 sweep();
315 } else
316 if (command == "WRITE_PARAM") {
317 readEcho(inBuffer, filename);
318 std::ofstream file;
319 fileMaster().openOutputFile(filename, file);
320 writeParam(file);
321 file.close();
322 } else
323 if (command == "WRITE_THERMO") {
324 readEcho(inBuffer, filename);
325 std::ofstream file;
326 fileMaster().openOutputFile(filename, file, std::ios_base::app);
327 writeThermo(file);
328 file.close();
329 } else
330 if (command == "COMPARE_HOMOGENEOUS") {
331 int mode;
332 inBuffer >> mode;
333 Log::file() << std::endl;
334 Log::file() << "mode = " << mode << std::endl;
335
336 HomogeneousComparison comparison(*this);
337 comparison.compute(mode);
338 comparison.output(mode, Log::file());
339 } else
340 if (command == "WRITE_W") {
341 readEcho(inBuffer, filename);
342 fieldIo_.writeFields(wFields(), filename);
343 } else
344 if (command == "WRITE_C") {
345 readEcho(inBuffer, filename);
346 fieldIo_.writeFields(cFields(), filename);
347 } else
348 if (command == "WRITE_BLOCK_C") {
349 readEcho(inBuffer, filename);
350 fieldIo_.writeBlockCFields(mixture_, filename);
351 } else
352 if (command == "WRITE_Q_SLICE") {
353 int polymerId, blockId, directionId, segmentId;
354 readEcho(inBuffer, filename);
355 inBuffer >> polymerId;
356 inBuffer >> blockId;
357 inBuffer >> directionId;
358 inBuffer >> segmentId;
359 Log::file() << Str("polymer ID ", 21) << polymerId << "\n"
360 << Str("block ID ", 21) << blockId << "\n"
361 << Str("direction ID ", 21) << directionId << "\n"
362 << Str("segment ID ", 21) << segmentId << std::endl;
363 writeQSlice(filename, polymerId, blockId, directionId,
364 segmentId);
365 } else
366 if (command == "WRITE_Q_TAIL") {
367 readEcho(inBuffer, filename);
368 int polymerId, blockId, directionId;
369 inBuffer >> polymerId;
370 inBuffer >> blockId;
371 inBuffer >> directionId;
372 Log::file() << Str("polymer ID ", 21) << polymerId << "\n"
373 << Str("block ID ", 21) << blockId << "\n"
374 << Str("direction ID ", 21) << directionId << "\n";
375 writeQTail(filename, polymerId, blockId, directionId);
376 } else
377 if (command == "WRITE_Q_VERTEX") {
378 int polymerId, vertexId;
379 inBuffer >> polymerId;
380 Log::file() << std::endl;
381 Log::file() << "polymerId = "
382 << Int(polymerId, 5) << std::endl;
383 inBuffer >> vertexId;
384 Log::file() << "vertexId = "
385 << Int(vertexId, 5) << std::endl;
386 inBuffer >> filename;
387 Log::file() << "outfile = "
388 << Str(filename, 20) << std::endl;
389 fieldIo_.writeVertexQ(mixture_, polymerId, vertexId, filename);
390 } else
391 if (command == "WRITE_Q") {
392 readEcho(inBuffer, filename);
393 int polymerId, blockId, directionId;
394 inBuffer >> polymerId;
395 inBuffer >> blockId;
396 inBuffer >> directionId;
397 Log::file() << Str("polymer ID ", 21) << polymerId << "\n"
398 << Str("block ID ", 21) << blockId << "\n"
399 << Str("direction ID ", 21) << directionId << "\n";
400 writeQ(filename, polymerId, blockId, directionId);
401 } else
402 if (command == "WRITE_Q_ALL") {
403 readEcho(inBuffer, filename);
404 writeQAll(filename);
405 } else
406 if (command == "REMESH_W") {
407 int nx;
408 inBuffer >> nx;
409 Log::file() << std::endl;
410 Log::file() << "nx = " << Int(nx, 20) << std::endl;
411 inBuffer >> filename;
412 Log::file() << "outfile = " << Str(filename, 20) << std::endl;
413 fieldIo_.remesh(wFields(), nx, filename);
414 } else
415 if (command == "EXTEND_W") {
416 int m;
417 inBuffer >> m;
418 Log::file() << std::endl;
419 Log::file() << "m = " << Int(m, 20) << std::endl;
420 inBuffer >> filename;
421 Log::file() << "outfile = " << Str(filename, 20) << std::endl;
422 fieldIo_.extend(wFields(), m, filename);
423 } else {
424 Log::file() << " Error: Unknown command "
425 << command << std::endl;
426 readNext = false;
427 }
428
429 }
430 }
431
432 /*
433 * Read and execute commands from the default command file.
434 */
436 {
437 if (fileMaster().commandFileName().empty()) {
438 UTIL_THROW("Empty command file name");
439 }
440 readCommands(fileMaster().commandFile());
441 }
442
443 /*
444 * Read a string (e.g., a filename) and echo to the log file.
445 */
446 void System::readEcho(std::istream& in, std::string& string) const
447 {
448 in >> string;
449 Log::file() << " " << Str(string, 20) << std::endl;
450 }
451
452 // Primary SCFT Computations
453
454 /*
455 * Solve MDE for current w-fields, without iteration.
456 */
458 {
459 //UTIL_CHECK(hasWFields_);
460
461 // Solve the modified diffusion equation (without iteration)
462 mixture_.compute(wFields(), cFields_);
463
464 //hasCFields_ = true;
465 }
466
467 /*
468 * Iteratively solve a SCFT problem for specified parameters.
469 */
470 int System::iterate(bool isContinuation)
471 {
472 // UTIL_CHECK(hasWFields_);
473 // hasCFields_ = false;
474
475 Log::file() << std::endl;
476
477 // Call iterator (return 0 for convergence, 1 for failure)
478 int error = iterator().solve(isContinuation);
479
480 //hasCFields_ = true;
481
482 // If converged, compute related properties
483 if (!error) {
486 }
487 return error;
488 }
489
490 /*
491 * Perform sweep along a line in parameter space.
492 */
494 {
495 //UTIL_CHECK(hasWFields_);
496 UTIL_CHECK(sweepPtr_);
497 Log::file() << std::endl;
498 Log::file() << std::endl;
499
500 sweepPtr_->sweep();
501 }
502
503 // Thermodynamic properties
504
505 /*
506 * Compute Helmholtz free energy and pressure
507 */
509 {
510 fHelmholtz_ = 0.0;
511 int np = mixture().nPolymer();
512 int ns = mixture().nSolvent();
513 int nm = mixture().nMonomer();
514 double phi, mu;
515
516 // Polymeric ideal gas contributions to fHelhmoltz_
517 if (np > 0) {
518 Polymer* polymerPtr;
519 double length;
520 for (int i = 0; i < np; ++i) {
521 polymerPtr = &mixture().polymer(i);
522 phi = polymerPtr->phi();
523 mu = polymerPtr->mu();
524 // Recall: mu = ln(phi/q)
525 length = polymerPtr->length();
526 if (phi > 1E-08) {
527 fHelmholtz_ += phi*( mu - 1.0 )/length;
528 }
529 }
530 }
531
532 // Solvent ideal gas contributions to fHelhmoltz_
533 if (ns > 0) {
534 Solvent* solventPtr;
535 double size;
536 for (int i = 0; i < ns; ++i) {
537 solventPtr = &mixture().solvent(i);
538 phi = solventPtr->phi();
539 mu = solventPtr->mu();
540 // Recall: mu = ln(phi/q)
541 size = solventPtr->size();
542 if (phi > 1E-08) {
543 fHelmholtz_ += phi*( mu - 1.0 )/size;
544 }
545 }
546 }
547
548 // Apply Legendre transform subtraction
549 for (int i = 0; i < nm; ++i) {
550 fHelmholtz_ -=
551 domain().innerProduct(wFields_[i], cFields_[i]);
552 }
553 fIdeal_ = fHelmholtz_;
554
555 // Add average interaction free energy density per monomer
556 int nx = domain().nx();
557 if (!f_.isAllocated()) f_.allocate(nx);
558 if (!c_.isAllocated()) c_.allocate(nm);
559 int j;
560 for (int i = 0; i < nx; ++i) {
561 // Store c_[j] = local concentration of species j
562 for (j = 0; j < nm; ++j) {
563 c_[j] = cFields_[j][i];
564 }
565 // Compute f_[i] = excess free eenrgy at grid point i
566 f_[i] = interaction().fHelmholtz(c_);
567 }
568 fHelmholtz_ += domain().spatialAverage(f_);
569 fInter_ = fHelmholtz_ - fIdeal_;
570
571 // Compute pressure
572 pressure_ = -fHelmholtz_;
573 if (np > 0) {
574 double length;
575 Polymer* polymerPtr;
576 for (int i = 0; i < np; ++i) {
577 polymerPtr = & mixture().polymer(i);
578 phi = polymerPtr->phi();
579 mu = polymerPtr->mu();
580 length = polymerPtr->length();
581 if (phi > 1E-08) {
582 pressure_ += phi*mu/length;
583 }
584 }
585 }
586 if (ns > 0) {
587 double size;
588 Solvent* solventPtr;
589 for (int i = 0; i < ns; ++i) {
590 solventPtr = & mixture().solvent(i);
591 phi = solventPtr->phi();
592 mu = solventPtr->mu();
593 size = solventPtr->size();
594 if (phi > 1E-08) {
595 pressure_ += phi*mu/size;
596 }
597 }
598 }
599
600 }
601
602 void System::initHomogeneous()
603 {
604
605 // Set number of molecular species and monomers
606 int nm = mixture().nMonomer();
607 int np = mixture().nPolymer();
608 int ns = mixture().nSolvent();
609 UTIL_CHECK(homogeneous_.nMolecule() == np + ns);
610 UTIL_CHECK(homogeneous_.nMonomer() == nm);
611
612 // Allocate c_ work array, if necessary
613 if (c_.isAllocated()) {
614 UTIL_CHECK(c_.capacity() == nm);
615 } else {
616 c_.allocate(nm);
617 }
618
619 int i; // molecule index
620 int j; // monomer index
621 int k; // block or clump index
622 int nb; // number of blocks
623 int nc; // number of clumps
624
625 // Loop over polymer molecule species
626 if (np > 0) {
627 for (i = 0; i < np; ++i) {
628
629 // Initial array of clump sizes
630 for (j = 0; j < nm; ++j) {
631 c_[j] = 0.0;
632 }
633
634 // Compute clump sizes for all monomer types.
635 nb = mixture().polymer(i).nBlock();
636 for (k = 0; k < nb; ++k) {
637 Block& block = mixture().polymer(i).block(k);
638 j = block.monomerId();
639 c_[j] += block.length();
640 }
641
642 // Count the number of clumps of nonzero size
643 nc = 0;
644 for (j = 0; j < nm; ++j) {
645 if (c_[j] > 1.0E-8) {
646 ++nc;
647 }
648 }
649 homogeneous_.molecule(i).setNClump(nc);
650
651 // Set clump properties for this Homogeneous::Molecule
652 k = 0; // Clump index
653 for (j = 0; j < nm; ++j) {
654 if (c_[j] > 1.0E-8) {
655 homogeneous_.molecule(i).clump(k).setMonomerId(j);
656 homogeneous_.molecule(i).clump(k).setSize(c_[j]);
657 ++k;
658 }
659 }
660 homogeneous_.molecule(i).computeSize();
661
662 }
663 }
664
665 // Add solvent contributions
666 if (np > 0) {
667 double size;
668 int monomerId;
669 for (int is = 0; is < ns; ++is) {
670 i = is + np;
671 monomerId = mixture().solvent(is).monomerId();
672 size = mixture().solvent(is).size();
673 homogeneous_.molecule(i).setNClump(1);
674 homogeneous_.molecule(i).clump(0).setMonomerId(monomerId);
675 homogeneous_.molecule(i).clump(0).setSize(size);
676 homogeneous_.molecule(i).computeSize();
677 }
678 }
679
680 }
681
682 void System::writeThermo(std::ostream& out)
683 {
684 out << std::endl;
685 out << "fHelmholtz " << Dbl(fHelmholtz(), 18, 11) << std::endl;
686 out << "pressure " << Dbl(pressure(), 18, 11) << std::endl;
687 out << std::endl;
688 out << "fIdeal " << Dbl(fIdeal_, 18, 11) << std::endl;
689 out << "fInter " << Dbl(fInter_, 18, 11) << std::endl;
690 out << std::endl;
691
692 // Polymers
693 int np = mixture().nPolymer();
694 if (np > 0) {
695 out << "polymers:" << std::endl;
696 out << " "
697 << " phi "
698 << " mu "
699 << std::endl;
700 for (int i = 0; i < np; ++i) {
701 out << Int(i, 5)
702 << " " << Dbl(mixture().polymer(i).phi(),18, 11)
703 << " " << Dbl(mixture().polymer(i).mu(), 18, 11)
704 << std::endl;
705 }
706 out << std::endl;
707 }
708
709 // Solvents
710 int ns = mixture().nSolvent();
711 if (ns > 0) {
712 out << "solvents:" << std::endl;
713 out << " "
714 << " phi "
715 << " mu "
716 << std::endl;
717 for (int i = 0; i < ns; ++i) {
718 out << Int(i, 5)
719 << " " << Dbl(mixture().solvent(i).phi(),18, 11)
720 << " " << Dbl(mixture().solvent(i).mu(), 18, 11)
721 << std::endl;
722 }
723 out << std::endl;
724 }
725
726 }
727
728 // Output operations (correspond to command file commands)
729
730 /*
731 * Write w-fields in symmetry-adapted basis format.
732 */
733 void System::writeW(std::string const & filename)
734 {
735 //UTIL_CHECK(hasWFields_);
736 fieldIo_.writeFields(wFields(), filename);
737 }
738
739 /*
740 * Write all concentration fields in symmetry-adapted basis format.
741 */
742 void System::writeC(std::string const & filename)
743 {
744 //UTIL_CHECK(hasCFields_);
745 fieldIo_.writeFields(cFields(), filename);
746 }
747
748 /*
749 * Write all concentration fields in real space (r-grid) format, for
750 * each block (or solvent) individually rather than for each species.
751 */
752 void System::writeBlockC(std::string const & filename)
753 {
754 //UTIL_CHECK(hasCFields_);
755 fieldIo_.writeBlockCFields(mixture_, filename);
756 }
757
758 /*
759 * Write the last time slice of the propagator in r-grid format.
760 */
761 void System::writeQSlice(const std::string & filename,
762 int polymerId, int blockId,
763 int directionId, int segmentId)
764 const
765 {
766 UTIL_CHECK(polymerId >= 0);
767 UTIL_CHECK(polymerId < mixture_.nPolymer());
768 Polymer const& polymer = mixture_.polymer(polymerId);
769 UTIL_CHECK(blockId >= 0);
770 UTIL_CHECK(blockId < polymer.nBlock());
771 UTIL_CHECK(directionId >= 0);
772 UTIL_CHECK(directionId <= 1);
773 Propagator const &
774 propagator = polymer.propagator(blockId, directionId);
775 Field const& field = propagator.q(segmentId);
776 fieldIo_.writeField(field, filename);
777 }
778
779 /*
780 * Write the last time slice of the propagator in r-grid format.
781 */
782 void System::writeQTail(const std::string & filename,
783 int polymerId, int blockId, int directionId)
784 const
785 {
786 UTIL_CHECK(polymerId >= 0);
787 UTIL_CHECK(polymerId < mixture_.nPolymer());
788 Polymer const& polymer = mixture_.polymer(polymerId);
789 UTIL_CHECK(blockId >= 0);
790 UTIL_CHECK(blockId < polymer.nBlock());
791 UTIL_CHECK(directionId >= 0);
792 UTIL_CHECK(directionId <= 1);
793 Field const&
794 field = polymer.propagator(blockId, directionId).tail();
795 fieldIo_.writeField(field, filename);
796 }
797
798 /*
799 * Write the propagator for a block and direction.
800 */
801 void System::writeQ(const std::string & filename,
802 int polymerId, int blockId, int directionId)
803 const
804 {
805 UTIL_CHECK(polymerId >= 0);
806 UTIL_CHECK(polymerId < mixture_.nPolymer());
807 Polymer const& polymer = mixture_.polymer(polymerId);
808 UTIL_CHECK(blockId >= 0);
809 UTIL_CHECK(blockId < polymer.nBlock());
810 UTIL_CHECK(directionId >= 0);
811 UTIL_CHECK(directionId <= 1);
812 Propagator const& propagator
813 = polymer.propagator(blockId, directionId);
814 int nslice = propagator.ns();
815
816 // Open file
817 std::ofstream file;
818 fileMaster_.openOutputFile(filename, file);
819
820 // Write header
821 file << "ngrid" << std::endl
822 << " " << domain_.nx() << std::endl
823 << "nslice" << std::endl
824 << " " << nslice << std::endl;
825
826 // Write data
827 bool hasHeader = false;
828 for (int i = 0; i < nslice; ++i) {
829 file << "slice " << i << std::endl;
830 Field const& field = propagator.q(i);
831 fieldIo_.writeField(field, file, hasHeader);
832 }
833 file.close();
834 }
835
836 /*
837 * Write propagators for all blocks of all polymers to files.
838 */
839 void System::writeQAll(std::string const & basename)
840 {
841 std::string filename;
842 int np, nb, ip, ib, id;
843 np = mixture_.nPolymer();
844 for (ip = 0; ip < np; ++ip) {
845 nb = mixture_.polymer(ip).nBlock();
846 for (ib = 0; ib < nb; ++ib) {
847 for (id = 0; id < 2; ++id) {
848 filename = basename;
849 filename += "_";
850 filename += toString(ip);
851 filename += "_";
852 filename += toString(ib);
853 filename += "_";
854 filename += toString(id);
855 //filename += ".q";
856 writeQ(filename, ip, ib, id);
857 }
858 }
859 }
860 }
861
862} // namespace Fd1d
863} // namespace Pscf
double spatialAverage(Field const &f) const
Compute spatial average of a field.
int nx() const
Get number of spatial grid points, including both endpoints.
double innerProduct(Field const &f, Field const &g) const
Compute inner product of two real fields.
void writeField(Field const &field, std::ostream &out, bool writeHeader=true) const
Write a single field to an output stream.
void writeVertexQ(Mixture const &mixture, int polymerId, int vertexId, std::ostream &out)
Write product of incoming q fields for one vertex to stream.
void remesh(DArray< Field > const &fields, int nx, std::ostream &out)
Interpolate an array of fields onto a new mesh and write to stream.
void associate(Domain const &domain, FileMaster const &fileMaster)
Get and store addresses of associated objects.
void writeFields(DArray< Field > const &fields, std::ostream &out, bool writeHeader=true)
Write a set of fields, one per monomer type, to an output stream.
void extend(DArray< Field > const &fields, int m, std::ostream &out)
Add points to the end of a field mesh and write to stream.
void writeBlockCFields(Mixture const &mixture, std::ostream &out)
Write block concentration fields for all blocks to an output stream.
void readFields(DArray< Field > &fields, std::istream &in)
Read a set of fields, one per monomer type.
Command to compute properties of homogeneous reference system.
void compute(int mode)
Compute properties of a homogeneous reference system.
void output(int mode, std::ostream &out)
Output comparison to a homogeneous reference system.
Factory for subclasses of Iterator.
virtual int solve(bool isContinuation=false)=0
Iterate to solution.
void setDomain(Domain const &domain)
Create an association with the domain and allocate memory.
void compute(DArray< WField > const &wFields, DArray< CField > &cFields)
Compute concentrations.
Descriptor and solver for a branched polymer species.
MDE solver for one-direction of one block.
int ns() const
Number of values of s (or slices), including head and tail.
QField const & q(int i) const
Return q-field at specified step.
Solver and descriptor for a solvent species.
Default Factory for subclasses of Sweep.
virtual void setSystem(System &system)
Set the system after construction.
void writeThermo(std::ostream &out)
Write thermodynamic properties to a file.
WField & wField(int monomerId)
Get chemical potential field for a specific monomer type.
Definition: fd1d/System.h:603
Iterator & iterator()
Get the Iterator by reference.
Definition: fd1d/System.h:580
int iterate(bool isContinuation=false)
Iteratively solve a SCFT problem.
void computeFreeEnergy()
Compute free energy density and pressure for current fields.
DArray< WField > & wFields()
Get array of all chemical potential fields.
Definition: fd1d/System.h:596
void compute()
Solve the modified diffusion equation once, without iteration.
~System()
Destructor.
Definition: fd1d/System.cpp:77
void writeQSlice(std::string const &filename, int polymerId, int blockId, int directionId, int segmentId) const
Write slice of a propagator at fixed s in r-grid format.
void readCommands()
Read commands from default command file.
Domain & domain()
Get spatial domain (including grid info) by reference.
Definition: fd1d/System.h:567
virtual void readParameters(std::istream &in)
Read input parameters (without opening and closing lines).
void sweep()
Sweep in parameter space, solving an SCF problem at each point.
Mixture & mixture()
Get Mixture by reference.
Definition: fd1d/System.h:537
DArray< CField > & cFields()
Get array of all chemical potential fields.
Definition: fd1d/System.h:610
double fHelmholtz() const
Get precomputed Helmholtz free energy per monomer / kT.
Definition: fd1d/System.h:622
System()
Constructor.
Definition: fd1d/System.cpp:40
void setOptions(int argc, char **argv)
Process command line options.
Definition: fd1d/System.cpp:99
void writeBlockC(std::string const &filename)
Write c-fields for all blocks and solvents in r-grid format.
void writeQAll(std::string const &basename)
Write all propagators of all blocks, each to a separate file.
void readParam()
Read input parameters from default param file.
void writeC(std::string const &filename)
Write concentration fields in symmetrized basis format.
void writeParamNoSweep(std::ostream &out) const
Write parameter file to an ostream, omitting any Sweep block.
double pressure() const
Get precomputed pressure x monomer volume kT.
Definition: fd1d/System.h:628
Interaction & interaction()
Get interaction (i.e., excess free energy) by reference.
Definition: fd1d/System.h:549
void writeQ(std::string const &filename, int polymerId, int blockId, int directionId) const
Write one propagator for one block, in r-grid format.
void writeW(std::string const &filename)
Write chemical potential fields in symmetrized basis format.
void writeQTail(std::string const &filename, int polymerId, int blockId, int directionId) const
Write the final slice of a propagator in r-grid format.
CField & cField(int monomerId)
Get chemical potential field for a specific monomer type.
Definition: fd1d/System.h:616
FileMaster & fileMaster()
Get FileMaster by reference.
Definition: fd1d/System.h:589
void setSize(double size)
Set the size of this block.
Definition: Clump.cpp:30
void setMonomerId(int monomerId)
Set the monomer id.
Definition: Clump.cpp:24
Molecule & molecule(int id)
Get a molecule object (non-const reference).
int nMonomer() const
Get number of monomer types.
int nMolecule() const
Get number of molecule species (polymer + solvent).
void setNMonomer(int nMonomer)
Set the number of monomer types.
void setNMolecule(int nMolecule)
Set the number of molecular species and allocate memory.
Clump & clump(int id)
Get a specified Clump.
Definition: Molecule.h:141
void setNClump(int nClump)
Set the number of clumps, and allocate memory.
Definition: Molecule.cpp:47
void computeSize()
Compute total molecule size by adding clump sizes.
Definition: Molecule.cpp:58
Flory-Huggins excess free energy model.
Definition: Interaction.h:26
virtual double fHelmholtz(Array< double > const &c) const
Compute excess Helmholtz free energy per monomer.
Definition: Interaction.cpp:92
void setNMonomer(int nMonomer)
Set the number of monomer types.
Definition: Interaction.cpp:31
Polymer & polymer(int id)
Get a polymer object.
Definition: MixtureTmpl.h:220
int nSolvent() const
Get number of solvent (point particle) species.
Definition: MixtureTmpl.h:198
int nMonomer() const
Get number of monomer types.
Definition: MixtureTmpl.h:190
Solvent & solvent(int id)
Set a solvent solver object.
Definition: MixtureTmpl.h:234
int nPolymer() const
Get number of polymer species.
Definition: MixtureTmpl.h:194
int nBlock() const
Number of blocks.
Definition: PolymerTmpl.h:241
Propagator & propagator(int blockId, int directionId)
Get propagator for a specific block and direction.
Definition: PolymerTmpl.h:304
double length() const
Sum of the lengths of all blocks in the polymer.
Definition: PolymerTmpl.h:255
double size() const
Get the size (number of monomers) in this solvent.
double phi() const
Get the overall volume fraction for this species.
Definition: Species.h:90
double mu() const
Get the chemical potential for this species (units kT=1).
Definition: Species.h:96
virtual void sweep()
Iterate to solution.
Definition: SweepTmpl.tpp:62
int capacity() const
Return allocated size.
Definition: Array.h:159
void allocate(int capacity)
Allocate the underlying C array.
Definition: DArray.h:199
bool isAllocated() const
Return true if this DArray has been allocated, false otherwise.
Definition: DArray.h:247
Wrapper for a double precision number, for formatted ostream output.
Definition: Dbl.h:40
Data * readObject(std::istream &in, ParamComposite &parent, std::string &className, bool &isEnd, bool isRequired=true)
Read a class name, instantiate an object, and read its parameters.
Definition: Factory.h:247
Data * readObjectOptional(std::istream &in, ParamComposite &parent, std::string &className, bool &isEnd)
Read an optional class name, instantiate an object, and read its parameters.
Definition: Factory.h:378
void openOutputFile(const std::string &filename, std::ofstream &out, std::ios_base::openmode mode=std::ios_base::out) const
Open an output file.
Definition: FileMaster.cpp:290
void setParamFileName(const std::string &paramFileName)
Set the parameter file name.
Definition: FileMaster.cpp:106
void setOutputPrefix(const std::string &outputPrefix)
Set the output file prefix string.
Definition: FileMaster.cpp:100
void setCommandFileName(const std::string &commandFileName)
Set the command file name.
Definition: FileMaster.cpp:112
void setInputPrefix(const std::string &inputPrefix)
Set the input file prefix string.
Definition: FileMaster.cpp:94
Wrapper for an int, for formatted ostream output.
Definition: Int.h:37
static std::ostream & file()
Get log ostream by reference.
Definition: Log.cpp:57
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.
virtual void writeParam(std::ostream &out) const
Write all parameters to an output stream.
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.
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:51
std::string toString(int n)
Return string representation of an integer.
Definition: ioUtil.cpp:52
C++ namespace for polymer self-consistent field theory (PSCF).
void set(BracketPolicy::Type policy)
Set policy regarding use of bracket delimiters on arrays.
Utility classes for scientific computation.
Definition: accumulators.mod:1