PSCF v1.1
pspg/System.tpp
1#ifndef PSPG_SYSTEM_TPP
2#define PSPG_SYSTEM_TPP
3
4/*
5* PSCF - Polymer Self-Consistent Field Theory
6*
7* Copyright 2016 - 2022, The Regents of the University of Minnesota
8* Distributed under the terms of the GNU General Public License.
9*/
10
11#include "System.h"
12#include <pspg/sweep/Sweep.h>
13#include <pspg/sweep/SweepFactory.h>
14#include <pspg/iterator/Iterator.h>
15#include <pspg/iterator/IteratorFactory.h>
16#include <pspg/field/RDField.h>
17#include <pspg/math/GpuResources.h>
18
19#include <pscf/inter/Interaction.h>
20#include <pscf/math/IntVec.h>
21#include <pscf/homogeneous/Clump.h>
22
23#include <util/param/BracketPolicy.h>
24#include <util/format/Str.h>
25#include <util/format/Int.h>
26#include <util/format/Dbl.h>
27#include <util/misc/ioUtil.h>
28
29#include <string>
30#include <unistd.h>
31//#include <getopt.h>
32
33namespace Pscf {
34namespace Pspg
35{
36
37 using namespace Util;
38
39 /*
40 * Constructor.
41 */
42 template <int D>
44 : mixture_(),
45 domain_(),
46 fileMaster_(),
47 homogeneous_(),
48 interactionPtr_(0),
49 iteratorPtr_(0),
50 iteratorFactoryPtr_(0),
51 sweepPtr_(0),
52 sweepFactoryPtr_(0),
53 w_(),
54 c_(),
55 fHelmholtz_(0.0),
56 fIdeal_(0.0),
57 fInter_(0.0),
58 pressure_(0.0),
59 hasMixture_(false),
60 isAllocatedGrid_(false),
61 isAllocatedBasis_(false),
62 hasCFields_(false)
63 {
64 setClassName("System");
65 domain_.setFileMaster(fileMaster_);
66 w_.setFieldIo(domain_.fieldIo());
67
68 interactionPtr_ = new Interaction();
69 iteratorFactoryPtr_ = new IteratorFactory<D>(*this);
70 sweepFactoryPtr_ = new SweepFactory<D>(*this);
71
72 BracketPolicy::set(BracketPolicy::Optional);
74 }
75
76 /*
77 * Destructor.
78 */
79 template <int D>
81 {
82 if (interactionPtr_) {
83 delete interactionPtr_;
84 }
85 if (iteratorPtr_) {
86 delete iteratorPtr_;
87 }
88 if (iteratorFactoryPtr_) {
89 delete iteratorFactoryPtr_;
90 }
91 if (sweepPtr_) {
92 delete sweepPtr_;
93 }
94 if (sweepFactoryPtr_) {
95 delete sweepFactoryPtr_;
96 }
97 }
98
99 /*
100 * Process command line options.
101 */
102 template <int D>
103 void System<D>::setOptions(int argc, char **argv)
104 {
105 bool eflag = false; // echo
106 bool pFlag = false; // param file
107 bool cFlag = false; // command file
108 bool iFlag = false; // input prefix
109 bool oFlag = false; // output prefix
110 bool tFlag = false; // GPU input threads (max. # of threads per block)
111 char* pArg = 0;
112 char* cArg = 0;
113 char* iArg = 0;
114 char* oArg = 0;
115 int tArg = 0;
116
117 // Read program arguments
118 int c;
119 opterr = 0;
120 while ((c = getopt(argc, argv, "er:p:c:i:o:t:")) != -1) {
121 switch (c) {
122 case 'e':
123 eflag = true;
124 break;
125 case 'p': // parameter file
126 pFlag = true;
127 pArg = optarg;
128 break;
129 case 'c': // command file
130 cFlag = true;
131 cArg = optarg;
132 break;
133 case 'i': // input prefix
134 iFlag = true;
135 iArg = optarg;
136 break;
137 case 'o': // output prefix
138 oFlag = true;
139 oArg = optarg;
140 break;
141 case 't': //number of threads per block, user set
142 tArg = atoi(optarg);
143 tFlag = true;
144 break;
145 case '?':
146 Log::file() << "Unknown option -" << optopt << std::endl;
147 UTIL_THROW("Invalid command line option");
148 }
149 }
150
151 // Set flag to echo parameters as they are read.
152 if (eflag) {
154 }
155
156 // If option -p, set parameter file name
157 if (pFlag) {
158 fileMaster().setParamFileName(std::string(pArg));
159 }
160
161 // If option -c, set command file name
162 if (cFlag) {
163 fileMaster().setCommandFileName(std::string(cArg));
164 }
165
166 // If option -i, set path prefix for input files
167 if (iFlag) {
168 fileMaster().setInputPrefix(std::string(iArg));
169 }
170
171 // If option -o, set path prefix for output files
172 if (oFlag) {
173 fileMaster().setOutputPrefix(std::string(oArg));
174 }
175
176 // If option -t, set the threads per block.
177 if (tFlag) {
179 }
180
181 }
182
183 /*
184 * Read parameter file (including open and closing brackets).
185 */
186 template <int D>
187 void System<D>::readParam(std::istream& in)
188 {
189 readBegin(in, className().c_str());
190 readParameters(in);
191 readEnd(in);
192 }
193
194 /*
195 * Read default parameter file.
196 */
197 template <int D>
199 { readParam(fileMaster().paramFile()); }
200 /*
201 * Read parameters and initialize.
202 */
203 template <int D>
204 void System<D>::readParameters(std::istream& in)
205 {
206
207 // Read the Mixture{ ... } block
208 readParamComposite(in, mixture());
209 hasMixture_ = true;
210
211 int nm = mixture().nMonomer();
212 int np = mixture().nPolymer();
213 int ns = mixture().nSolvent();
214 UTIL_CHECK(nm > 0);
215 UTIL_CHECK(np >= 0);
216 UTIL_CHECK(ns >= 0);
217 UTIL_CHECK(np + ns > 0);
218
219 // Read the Interaction{ ... } block
220 interaction().setNMonomer(mixture().nMonomer());
221 readParamComposite(in, interaction());
222
223 // Read the Domain{ ... } block
224 readParamComposite(in, domain_);
225
226 mixture().setMesh(mesh());
227 UTIL_CHECK(domain_.mesh().size() > 0);
228 UTIL_CHECK(domain_.unitCell().nParameter() > 0);
229 UTIL_CHECK(domain_.unitCell().lattice() != UnitCell<D>::Null);
230
231 // Allocate memory for w and c fields
232 allocateFieldsGrid();
233 if (domain_.basis().isInitialized()) {
234 allocateFieldsBasis();
235 }
236
237 // Optionally instantiate an Iterator object
238 std::string className;
239 bool isEnd;
240 iteratorPtr_ =
241 iteratorFactoryPtr_->readObjectOptional(in, *this, className,
242 isEnd);
243 if (!iteratorPtr_) {
244 Log::file() << "Notification: No iterator was constructed\n";
245 }
246
247 // Optionally instantiate a Sweep object (if an iterator exists)
248 if (iteratorPtr_) {
249 sweepPtr_ =
250 sweepFactoryPtr_->readObjectOptional(in, *this, className,
251 isEnd);
252 }
253
254 #if 0
255 // Initialize iterator
256 std::string className;
257 bool isEnd;
258 iteratorPtr_
259 = iteratorFactoryPtr_->readObject(in, *this, className, isEnd);
260 if (!iteratorPtr_) {
261 std::string msg = "Unrecognized Iterator subclass name ";
262 msg += className;
263 UTIL_THROW(msg.c_str());
264 }
265
266 // Optionally instantiate a Sweep object
267 sweepPtr_ =
268 sweepFactoryPtr_->readObjectOptional(in, *this, className, isEnd);
269 if (sweepPtr_) {
270 sweepPtr_->setSystem(*this);
271 }
272 #endif
273
274 // Initialize homogeneous object
275 homogeneous_.setNMolecule(np+ns);
276 homogeneous_.setNMonomer(nm);
277 initHomogeneous();
278
279 }
280
281 /*
282 * Read and execute commands from a specified command file.
283 */
284 template <int D>
285 void System<D>::readCommands(std::istream &in)
286 {
287 UTIL_CHECK(isAllocatedGrid_);
288 std::string command, filename, inFileName, outFileName;
289
290 bool readNext = true;
291 while (readNext) {
292
293 in >> command;
294
295 if (in.eof()) {
296 break;
297 } else {
298 Log::file() << command << std::endl;
299 }
300
301 if (command == "FINISH") {
302 Log::file() << std::endl;
303 readNext = false;
304 } else
305 if (command == "READ_W_BASIS") {
306 readEcho(in, filename);
307 readWBasis(filename);
308 } else
309 if (command == "READ_W_RGRID") {
310 readEcho(in, filename);
311 readWRGrid(filename);
312 } else
313 if (command == "ESTIMATE_W_FROM_C") {
314 // Read c field file in r-grid format
315 readEcho(in, inFileName);
316 estimateWfromC(inFileName);
317 } else
318 if (command == "SET_UNIT_CELL") {
319 UnitCell<D> unitCell;
320 in >> unitCell;
321 Log::file() << " " << unitCell << std::endl;
322 setUnitCell(unitCell);
323 } else
324 if (command == "COMPUTE") {
325 // Solve the modified diffusion equation for current w fields
326 compute();
327 } else
328 if (command == "ITERATE") {
329 // Attempt to iteratively solve a SCFT problem
330 int error = iterate();
331 if (error) {
332 readNext = false;
333 }
334 } else
335 if (command == "SWEEP") {
336 // Attempt to solve a sequence of SCFT problems along a path
337 // through parameter space
338 sweep();
339 } else
340 if (command == "WRITE_PARAM") {
341 readEcho(in, filename);
342 std::ofstream file;
343 fileMaster().openOutputFile(filename, file);
344 writeParamNoSweep(file);
345 file.close();
346 } else
347 if (command == "WRITE_THERMO") {
348 readEcho(in, filename);
349 std::ofstream file;
350 fileMaster().openOutputFile(filename, file,
351 std::ios_base::app);
352 writeThermo(file);
353 file.close();
354 } else
355 if (command == "WRITE_W_BASIS") {
356 UTIL_CHECK(w_.hasData());
357 UTIL_CHECK(w_.isSymmetric());
358 readEcho(in, filename);
359 fieldIo().writeFieldsBasis(filename, w_.basis(),
360 domain_.unitCell());
361 } else
362 if (command == "WRITE_W_RGRID") {
363 UTIL_CHECK(w_.hasData());
364 readEcho(in, filename);
365 fieldIo().writeFieldsRGrid(filename, w_.rgrid(),
366 domain_.unitCell());
367 } else
368 if (command == "WRITE_C_BASIS") {
369 readEcho(in, filename);
370 UTIL_CHECK(hasCFields_);
371 UTIL_CHECK(w_.isSymmetric());
372 fieldIo().writeFieldsBasis(filename, c_.basis(),
373 domain_.unitCell());
374 } else
375 if (command == "WRITE_C_RGRID") {
376 UTIL_CHECK(hasCFields_);
377 readEcho(in, filename);
378 fieldIo().writeFieldsRGrid(filename, c_.rgrid(),
379 domain_.unitCell());
380 } else
381 if (command == "WRITE_BLOCK_C_RGRID") {
382 readEcho(in, filename);
383 writeBlockCRGrid(filename);
384 } else
385 if (command == "WRITE_Q_SLICE") {
386 int polymerId, blockId, directionId, segmentId;
387 readEcho(in, filename);
388 in >> polymerId;
389 in >> blockId;
390 in >> directionId;
391 in >> segmentId;
392 Log::file() << Str("polymer ID ", 21) << polymerId << "\n"
393 << Str("block ID ", 21) << blockId << "\n"
394 << Str("direction ID ", 21) << directionId << "\n"
395 << Str("segment ID ", 21) << segmentId << std::endl;
396 writeQSlice(filename, polymerId, blockId, directionId,
397 segmentId);
398 } else
399 if (command == "WRITE_Q_TAIL") {
400 int polymerId, blockId, directionId;
401 readEcho(in, filename);
402 in >> polymerId;
403 in >> blockId;
404 in >> directionId;
405 Log::file() << Str("polymer ID ", 21) << polymerId << "\n"
406 << Str("block ID ", 21) << blockId << "\n"
407 << Str("direction ID ", 21) << directionId << "\n";
408 writeQTail(filename, polymerId, blockId, directionId);
409 } else
410 if (command == "WRITE_Q") {
411 int polymerId, blockId, directionId;
412 readEcho(in, filename);
413 in >> polymerId;
414 in >> blockId;
415 in >> directionId;
416 Log::file() << Str("polymer ID ", 21) << polymerId << "\n"
417 << Str("block ID ", 21) << blockId << "\n"
418 << Str("direction ID ", 21) << directionId << "\n";
419 writeQ(filename, polymerId, blockId, directionId);
420 } else
421 if (command == "WRITE_Q_ALL") {
422 readEcho(in, filename);
423 writeQAll(filename);
424 } else
425 if (command == "WRITE_STARS") {
426 readEcho(in, filename);
427 writeStars(filename);
428 } else
429 if (command == "WRITE_WAVES") {
430 readEcho(in, filename);
431 writeWaves(filename);
432 } else
433 if (command == "WRITE_GROUP") {
434 readEcho(in, filename);
435 writeGroup(filename);
436 //writeGroup(filename, domain_.group());
437 } else
438 if (command == "BASIS_TO_RGRID") {
439 readEcho(in, inFileName);
440 readEcho(in, outFileName);
441 basisToRGrid(inFileName, outFileName);
442 } else
443 if (command == "RGRID_TO_BASIS") {
444 readEcho(in, inFileName);
445 readEcho(in, outFileName);
446 rGridToBasis(inFileName, outFileName);
447 } else
448 if (command == "KGRID_TO_RGRID") {
449 readEcho(in, inFileName);
450 readEcho(in, outFileName);
451 kGridToRGrid(inFileName, outFileName);
452 } else
453 if (command == "RGRID_TO_KGRID") {
454 readEcho(in, inFileName);
455 readEcho(in, outFileName);
456 rGridToKGrid(inFileName, outFileName);
457 } else
458 if (command == "KGRID_TO_BASIS") {
459 readEcho(in, inFileName);
460 readEcho(in, outFileName);
461 kGridToBasis(inFileName, outFileName);
462 } else
463 if (command == "BASIS_TO_KGRID") {
464 readEcho(in, inFileName);
465 readEcho(in, outFileName);
466 basisToKGrid(inFileName, outFileName);
467 } else {
468 Log::file() << " Error: Unknown command "
469 << command << std::endl;
470 readNext = false;
471 }
472 }
473 }
474
475 /*
476 * Read and execute commands from the default command file.
477 */
478 template <int D>
480 {
481 if (fileMaster().commandFileName().empty()) {
482 UTIL_THROW("Empty command file name");
483 }
484 readCommands(fileMaster().commandFile());
485 }
486
487 // W-Field Modifier Functions
488
489 /*
490 * Read w-field in symmetry adapted basis format.
491 */
492 template <int D>
493 void System<D>::readWBasis(const std::string & filename)
494 {
495 // If basis fields are not allocated, peek at field file header to
496 // get unit cell parameters, initialize basis and allocate fields.
497 if (!isAllocatedBasis_) {
498 readFieldHeader(filename);
499 allocateFieldsBasis();
500 }
501
502 // Read w fields
503 w_.readBasis(filename, domain_.unitCell());
504 domain_.waveList().computeKSq(domain_.unitCell());
505 domain_.waveList().computedKSq(domain_.unitCell());
506 mixture_.setupUnitCell(domain_.unitCell(), domain_.waveList());
507 hasCFields_ = false;
508 }
509
510 template <int D>
511 void System<D>::readWRGrid(const std::string & filename)
512 {
513 // If basis fields are not allocated, peek at field file header to
514 // get unit cell parameters, initialize basis and allocate fields.
515 if (!isAllocatedBasis_) {
516 readFieldHeader(filename);
517 allocateFieldsBasis();
518 }
519
520 w_.readRGrid(filename, domain_.unitCell());
521 domain_.waveList().computeKSq(domain_.unitCell());
522 domain_.waveList().computedKSq(domain_.unitCell());
523 mixture_.setupUnitCell(domain_.unitCell(), domain_.waveList());
524 hasCFields_ = false;
525 }
526
527 /*
528 * Set new w-field values.
529 */
530 template <int D>
532 {
533 w_.setBasis(fields);
534 hasCFields_ = false;
535 }
536
537 /*
538 * Set new w-field values, using r-grid fields as inputs.
539 */
540 template <int D>
541 void System<D>::setWRGrid(DArray< RDField<D> > const & fields)
542 {
543 w_.setRGrid(fields);
544 hasCFields_ = false;
545 }
546
547 /*
548 * Set new w-field values, using unfoldeded array of r-grid fields.
549 */
550 template <int D>
552 {
553 w_.setRGrid(fields);
554 hasCFields_ = false;
555 }
556
557 /*
558 * Construct estimate for w-fields from c-fields.
559 *
560 * Modifies wFields and wFieldsRGrid.
561 */
562 template <int D>
563 void System<D>::estimateWfromC(std::string const & filename)
564 {
565 UTIL_CHECK(hasMixture_);
566 const int nMonomer = mixture_.nMonomer();
567 UTIL_CHECK(nMonomer > 0);
568
569 // If basis fields are not allocated, peek at field file header to
570 // get unit cell parameters, initialize basis and allocate fields.
571 if (!isAllocatedBasis_) {
572 readFieldHeader(filename);
573 allocateFieldsBasis();
574 }
575 UTIL_CHECK(domain_.basis().isInitialized());
576 const int nBasis = domain_.basis().nBasis();
577 UTIL_CHECK(nBasis > 0);
578
579 // Allocate temporary storage
580 DArray< DArray<double> > tmpCFieldsBasis;
581 tmpCFieldsBasis.allocate(nMonomer);
582 for (int i = 0; i < nMonomer; ++i) {
583 tmpCFieldsBasis[i].allocate(nBasis);
584 }
585
586 // Read c fields from input file
587 fieldIo().readFieldsBasis(filename, tmpCFieldsBasis,
588 domain_.unitCell());
589
590 // Compute w fields from c fields
591 for (int i = 0; i < nBasis; ++i) {
592 for (int j = 0; j < nMonomer; ++j) {
593 tmpFieldsBasis_[j][i] = 0.0;
594 for (int k = 0; k < nMonomer; ++k) {
595 tmpFieldsBasis_[j][i] += interaction().chi(j,k)
596 * tmpCFieldsBasis[k][i];
597 }
598 }
599 }
600
601 // Store estimated w fields in System w container
602 w_.setBasis(tmpFieldsBasis_);
603
604 hasCFields_ = false;
605 }
606
607 /*
608 * Set new w-field values, using array of r-grid fields as input.
609 */
610 template <int D>
612 { w_.symmetrize(); }
613
614 // Unit Cell Modifiers
615
616 /*
617 * Set the associated unit cell.
618 */
619 template <int D>
620 void System<D>::setUnitCell(UnitCell<D> const & unitCell)
621 {
622 domain_.setUnitCell(unitCell);
623 mixture_.setupUnitCell(unitCell, domain_.waveList());
624 if (!isAllocatedBasis_) {
625 allocateFieldsBasis();
626 }
627 }
628
629 /*
630 * Set the associated unit cell.
631 */
632 template <int D>
633 void
635 FSArray<double, 6> const & parameters)
636 {
637 domain_.setUnitCell(lattice, parameters);
638 mixture_.setupUnitCell(domain_.unitCell(), domain_.waveList());
639 if (!isAllocatedBasis_) {
640 allocateFieldsBasis();
641 }
642 }
643
644 /*
645 * Set parameters of the associated unit cell.
646 */
647 template <int D>
649 {
650 domain_.setUnitCell(parameters);
651 mixture_.setupUnitCell(domain_.unitCell(), domain_.waveList());
652 if (!isAllocatedBasis_) {
653 allocateFieldsBasis();
654 }
655 }
656
657 // Primary SCFT Computations
658
659 /*
660 * Solve MDE for current w-fields, without iteration.
661 */
662 template <int D>
663 void System<D>::compute(bool needStress)
664 {
665 UTIL_CHECK(w_.hasData());
666
667 // Solve the modified diffusion equation (without iteration)
668 mixture().compute(w_.rgrid(), c_.rgrid());
669 hasCFields_ = true;
670
671 // Convert c fields from r-grid to basis format
672 if (w_.isSymmetric()) {
673 fieldIo().convertRGridToBasis(c_.rgrid(), c_.basis());
674 }
675
676 if (needStress) {
677 mixture().computeStress(domain_.waveList());
678 }
679 }
680
681 /*
682 * Iteratively solve a SCFT problem for specified parameters.
683 */
684 template <int D>
685 int System<D>::iterate(bool isContinuation)
686 {
687 UTIL_CHECK(w_.hasData());
688 hasCFields_ = false;
689
690 Log::file() << std::endl;
691 Log::file() << std::endl;
692
693 // Call iterator
694 int error = iterator().solve(isContinuation);
695
696 hasCFields_ = true;
697
698 if (w_.isSymmetric()) {
699 fieldIo().convertRGridToBasis(c_.rgrid(), c_.basis());
700 }
701
702 if (!error) {
703 if (!iterator().isFlexible()) {
704 mixture().computeStress(domain_.waveList());
705 }
706 computeFreeEnergy();
707 writeThermo(Log::file());
708 }
709 return error;
710 }
711
712 /*
713 * Perform sweep along a line in parameter space.
714 */
715 template <int D>
717 {
718 UTIL_CHECK(w_.hasData());
719 UTIL_CHECK(w_.isSymmetric());
720 UTIL_CHECK(sweepPtr_);
721 UTIL_CHECK(hasSweep());
722 Log::file() << std::endl;
723 Log::file() << std::endl;
724
725 // Perform sweep
726 sweepPtr_->sweep();
727 }
728
729 // Thermodynamic Properties
730
731 /*
732 * Compute Helmholtz free energy and pressure
733 */
734 template <int D>
736 {
737 UTIL_CHECK(w_.hasData());
738 UTIL_CHECK(hasCFields_);
739
740 // Initialize to zero
741 fHelmholtz_ = 0.0;
742
743 double phi, mu;
744 int np = mixture_.nPolymer();
745 int ns = mixture_.nSolvent();
746
747 // Compute polymer ideal gas contributions to fHelhmoltz_
748 if (np > 0) {
749 Polymer<D>* polymerPtr;
750 double phi, mu, length;
751 int np = mixture().nPolymer();
752 for (int i = 0; i < np; ++i) {
753 polymerPtr = &mixture().polymer(i);
754 phi = polymerPtr->phi();
755 mu = polymerPtr->mu();
756 // Recall: mu = ln(phi/q)
757 length = polymerPtr->length();
758 if (phi > 1E-08) {
759 fHelmholtz_ += phi*( mu - 1.0 )/length;
760 }
761 }
762 }
763
764 // Compute solvent ideal gas contributions to fHelhmoltz_
765 if (ns > 0) {
766 Solvent<D>* solventPtr;
767 double size;
768 for (int i = 0; i < ns; ++i) {
769 solventPtr = &mixture_.solvent(i);
770 phi = solventPtr->phi();
771 mu = solventPtr->mu();
772 size = solventPtr->size();
773 if (phi > 1E-08) {
774 fHelmholtz_ += phi*( mu - 1.0 )/size;
775 }
776 }
777 }
778
779 int nm = mixture().nMonomer();
780 int nx = mesh().size();
781
782 // GPU resources
783 int nBlocks, nThreads;
784 ThreadGrid::setThreadsLogical(nx, nBlocks, nThreads);
785
786 // Compute Legendre transform subtraction
787 double temp = 0.0;
788 for (int i = 0; i < nm; i++) {
789 pointWiseBinaryMultiply<<<nBlocks,nThreads>>>
790 (w_.rgrid(i).cDField(), c_.rgrid()[i].cDField(),
791 workArray_.cDField(), nx);
792 temp += gpuSum(workArray_.cDField(),nx) / double(nx);
793 }
794 fHelmholtz_ -= temp;
795 fIdeal_ = fHelmholtz_;
796
797 // Compute excess interaction free energy
798 for (int i = 0; i < nm; ++i) {
799 for (int j = i + 1; j < nm; ++j) {
800 assignUniformReal<<<nBlocks, nThreads>>>
801 (workArray_.cDField(), interaction().chi(i, j), nx);
802 inPlacePointwiseMul<<<nBlocks, nThreads>>>
803 (workArray_.cDField(), c_.rgrid()[i].cDField(), nx);
804 inPlacePointwiseMul<<<nBlocks, nThreads>>>
805 (workArray_.cDField(), c_.rgrid()[j].cDField(), nx);
806 fHelmholtz_ += gpuSum(workArray_.cDField(), nx) / double(nx);
807 }
808 }
809 fInter_ = fHelmholtz_ - fIdeal_;
810
811 // Initialize pressure
812 pressure_ = -fHelmholtz_;
813
814 // Polymer corrections to pressure
815 if (np > 0) {
816 Polymer<D>* polymerPtr;
817 double length;
818 for (int i = 0; i < np; ++i) {
819 polymerPtr = &mixture_.polymer(i);
820 phi = polymerPtr->phi();
821 mu = polymerPtr->mu();
822 length = polymerPtr->length();
823 if (phi > 1E-08) {
824 pressure_ += mu * phi /length;
825 }
826 }
827 }
828
829 // Solvent corrections to pressure
830 if (ns > 0) {
831 Solvent<D>* solventPtr;
832 double size;
833 for (int i = 0; i < ns; ++i) {
834 solventPtr = &mixture_.solvent(i);
835 phi = solventPtr->phi();
836 mu = solventPtr->mu();
837 size = solventPtr->size();
838 if (phi > 1E-08) {
839 pressure_ += mu * phi /size;
840 }
841 }
842 }
843
844 }
845
846 // Output Operations
847
848 /*
849 * Write parameter file, omitting the sweep block.
850 */
851 template <int D>
852 void System<D>::writeParamNoSweep(std::ostream& out) const
853 {
854 out << "System{" << std::endl;
855 mixture_.writeParam(out);
856 interaction().writeParam(out);
857 domain_.writeParam(out);
858 if (iteratorPtr_) {
859 iteratorPtr_->writeParam(out);
860 }
861 out << "}" << std::endl;
862 }
863
864 template <int D>
865 void System<D>::writeThermo(std::ostream& out)
866 {
867 out << std::endl;
868 out << "fHelmholtz " << Dbl(fHelmholtz(), 18, 11) << std::endl;
869 out << "pressure " << Dbl(pressure(), 18, 11) << std::endl;
870 out << std::endl;
871 out << "fIdeal " << Dbl(fIdeal_, 18, 11) << std::endl;
872 out << "fInter " << Dbl(fInter_, 18, 11) << std::endl;
873 out << std::endl;
874
875 int np = mixture_.nPolymer();
876 int ns = mixture_.nSolvent();
877
878 if (np > 0) {
879 out << "polymers:" << std::endl;
880 out << " "
881 << " phi "
882 << " mu "
883 << std::endl;
884 for (int i = 0; i < np; ++i) {
885 out << Int(i, 5)
886 << " " << Dbl(mixture_.polymer(i).phi(),18, 11)
887 << " " << Dbl(mixture_.polymer(i).mu(), 18, 11)
888 << std::endl;
889 }
890 out << std::endl;
891 }
892
893 if (ns > 0) {
894 out << "solvents:" << std::endl;
895 out << " "
896 << " phi "
897 << " mu "
898 << std::endl;
899 for (int i = 0; i < ns; ++i) {
900 out << Int(i, 5)
901 << " " << Dbl(mixture_.solvent(i).phi(),18, 11)
902 << " " << Dbl(mixture_.solvent(i).mu(), 18, 11)
903 << std::endl;
904 }
905 out << std::endl;
906 }
907
908 out << "cellParams:" << std::endl;
909 for (int i = 0; i < unitCell().nParameter(); ++i) {
910 out << Int(i, 5)
911 << " "
912 << Dbl(unitCell().parameter(i), 18, 11)
913 << std::endl;
914 }
915 out << std::endl;
916 }
917
918 /*
919 * Write w-fields in symmetry-adapted basis format.
920 */
921 template <int D>
922 void System<D>::writeWBasis(const std::string & filename)
923 {
924 UTIL_CHECK(w_.hasData());
925 UTIL_CHECK(w_.isSymmetric());
926 fieldIo().writeFieldsBasis(filename, w_.basis(), unitCell());
927 }
928
929 /*
930 * Write w-fields in real space grid file format.
931 */
932 template <int D>
933 void System<D>::writeWRGrid(const std::string & filename) const
934 {
935 UTIL_CHECK(w_.hasData());
936 fieldIo().writeFieldsRGrid(filename, w_.rgrid(), unitCell());
937 }
938
939 /*
940 * Write all concentration fields in symmetry-adapted basis format.
941 */
942 template <int D>
943 void System<D>::writeCBasis(const std::string & filename)
944 {
945 UTIL_CHECK(hasCFields_);
946 UTIL_CHECK(w_.isSymmetric());
947 fieldIo().writeFieldsBasis(filename, c_.basis(), unitCell());
948 }
949
950 /*
951 * Write all concentration fields in real space (r-grid) format.
952 */
953 template <int D>
954 void System<D>::writeCRGrid(const std::string & filename) const
955 {
956 UTIL_CHECK(hasCFields_);
957 fieldIo().writeFieldsRGrid(filename, c_.rgrid(), unitCell());
958 }
959
960 /*
961 * Write all concentration fields in real space (r-grid) format, for each
962 * block (or solvent) individually rather than for each species.
963 */
964 template <int D>
965 void System<D>::writeBlockCRGrid(const std::string & filename) const
966 {
967 UTIL_CHECK(hasCFields_);
968
969 // Create and allocate the DArray of fields to be written
970 DArray< RDField<D> > blockCFields;
971 blockCFields.allocate(mixture_.nSolvent() + mixture_.nBlock());
972 int n = blockCFields.capacity();
973 for (int i = 0; i < n; i++) {
974 blockCFields[i].allocate(mesh().dimensions());
975 }
976
977 // Get data from Mixture and write to file
978 mixture_.createBlockCRGrid(blockCFields);
979 fieldIo().writeFieldsRGrid(filename, blockCFields, unitCell());
980 }
981
982 /*
983 * Write the last time slice of the propagator in r-grid format.
984 */
985 template <int D>
986 void System<D>::writeQSlice(const std::string & filename,
987 int polymerId, int blockId,
988 int directionId, int segmentId)
989 const
990 {
991 UTIL_CHECK(polymerId >= 0);
992 UTIL_CHECK(polymerId < mixture_.nPolymer());
993 Polymer<D> const& polymer = mixture_.polymer(polymerId);
994 UTIL_CHECK(blockId >= 0);
995 UTIL_CHECK(blockId < polymer.nBlock());
996 UTIL_CHECK(directionId >= 0);
997 UTIL_CHECK(directionId <= 1);
998 Propagator<D> const&
999 propagator = polymer.propagator(blockId, directionId);
1000 RDField<D> field;
1001 field.allocate(mesh().size());
1002 cudaMemcpy(field.cDField(), propagator.q(segmentId),
1003 mesh().size() * sizeof(cudaReal), cudaMemcpyDeviceToDevice);
1004 fieldIo().writeFieldRGrid(filename, field, unitCell());
1005 }
1006
1007 /*
1008 * Write the last time slice of the propagator in r-grid format.
1009 */
1010 template <int D>
1011 void System<D>::writeQTail(const std::string & filename,
1012 int polymerId, int blockId, int directionId)
1013 const
1014 {
1015 UTIL_CHECK(polymerId >= 0);
1016 UTIL_CHECK(polymerId < mixture_.nPolymer());
1017 Polymer<D> const& polymer = mixture_.polymer(polymerId);
1018 UTIL_CHECK(blockId >= 0);
1019 UTIL_CHECK(blockId < polymer.nBlock());
1020 UTIL_CHECK(directionId >= 0);
1021 UTIL_CHECK(directionId <= 1);
1022 Propagator<D> const&
1023 propagator = polymer.propagator(blockId, directionId);
1024 RDField<D> field;
1025 field.allocate(mesh().size());
1026 cudaMemcpy(field.cDField(), propagator.tail(),
1027 mesh().size()*sizeof(cudaReal),
1028 cudaMemcpyDeviceToDevice);
1029 fieldIo().writeFieldRGrid(filename, field, unitCell());
1030 }
1031
1032 /*
1033 * Write the propagator for a block and direction.
1034 */
1035 template <int D>
1036 void System<D>::writeQ(const std::string & filename,
1037 int polymerId, int blockId, int directionId)
1038 const
1039 {
1040 UTIL_CHECK(polymerId >= 0);
1041 UTIL_CHECK(polymerId < mixture_.nPolymer());
1042 Polymer<D> const& polymer = mixture_.polymer(polymerId);
1043 UTIL_CHECK(blockId >= 0);
1044 UTIL_CHECK(blockId < polymer.nBlock());
1045 UTIL_CHECK(directionId >= 0);
1046 UTIL_CHECK(directionId <= 1);
1047 Propagator<D> const&
1048 propagator = polymer.propagator(blockId, directionId);
1049 int ns = propagator.ns();
1050
1051 // Open file
1052 std::ofstream file;
1053 fileMaster_.openOutputFile(filename, file);
1054
1055 // Write header
1056 fieldIo().writeFieldHeader(file, 1, unitCell());
1057 file << "ngrid" << std::endl
1058 << " " << mesh().dimensions() << std::endl
1059 << "nslice" << std::endl
1060 << " " << ns << std::endl;
1061
1062 // Write data
1063 RDField<D> field;
1064 field.allocate(mesh().size());
1065 bool hasHeader = false;
1066 for (int i = 0; i < ns; ++i) {
1067 file << "slice " << i << std::endl;
1068 cudaMemcpy(field.cDField(), propagator.q(i),
1069 mesh().size() * sizeof(cudaReal),
1070 cudaMemcpyDeviceToDevice);
1071 fieldIo().writeFieldRGrid(file, field, unitCell(), hasHeader);
1072 }
1073 }
1074
1075 /*
1076 * Write propagators for all blocks of all polymers to files.
1077 */
1078 template <int D>
1079 void System<D>::writeQAll(std::string const & basename)
1080 {
1081 std::string filename;
1082 int np, nb, ip, ib, id;
1083 np = mixture_.nPolymer();
1084 for (ip = 0; ip < np; ++ip) {
1085 //Polymer<D> const * polymerPtr = &mixture_.polymer(ip);
1086 //nb = polymerPtr->nBlock();
1087 nb = mixture_.polymer(ip).nBlock();
1088 for (ib = 0; ib < nb; ++ib) {
1089 for (id = 0; id < 2; ++id) {
1090 filename = basename;
1091 filename += "_";
1092 filename += toString(ip);
1093 filename += "_";
1094 filename += toString(ib);
1095 filename += "_";
1096 filename += toString(id);
1097 filename += ".rq";
1098 writeQ(filename, ip, ib, id);
1099 }
1100 }
1101 }
1102 }
1103
1104 /*
1105 * Write description of symmetry-adapted stars and basis to file.
1106 */
1107 template <int D>
1108 void System<D>::writeStars(const std::string & filename) const
1109 {
1110 UTIL_CHECK(domain_.basis().isInitialized());
1111 std::ofstream outFile;
1112 fileMaster_.openOutputFile(filename, outFile);
1113 fieldIo().writeFieldHeader(outFile, mixture_.nMonomer(),
1114 unitCell());
1115 basis().outputStars(outFile);
1116 }
1117
1118 /*
1119 * Write a list of waves and associated stars to file.
1120 */
1121 template <int D>
1122 void System<D>::writeWaves(const std::string & filename) const
1123 {
1124 UTIL_CHECK(domain_.basis().isInitialized());
1125 std::ofstream outFile;
1126 fileMaster_.openOutputFile(filename, outFile);
1127 fieldIo().writeFieldHeader(outFile, mixture_.nMonomer(),
1128 unitCell());
1129 basis().outputWaves(outFile);
1130 }
1131
1132 /*
1133 * Write all elements of the space group to a file.
1134 */
1135 template <int D>
1136 void System<D>::writeGroup(const std::string & filename) const
1137 {
1138 Pscf::writeGroup(filename, domain_.group());
1139 }
1140
1141 // Field File Operations
1142
1143 /*
1144 * Convert fields from symmetry-adpated basis to real-space grid format.
1145 */
1146 template <int D>
1147 void System<D>::basisToRGrid(const std::string & inFileName,
1148 const std::string & outFileName)
1149 {
1150 // If basis fields are not allocated, peek at field file header to
1151 // get unit cell parameters, initialize basis and allocate fields.
1152 if (!isAllocatedBasis_) {
1153 readFieldHeader(inFileName);
1154 allocateFieldsBasis();
1155 }
1156
1157 // Read, convert and write fields
1158 UnitCell<D> tmpUnitCell;
1159 fieldIo().readFieldsBasis(inFileName, tmpFieldsBasis_, tmpUnitCell);
1160 fieldIo().convertBasisToRGrid(tmpFieldsBasis_, tmpFieldsRGrid_);
1161 fieldIo().writeFieldsRGrid(outFileName, tmpFieldsRGrid_,
1162 tmpUnitCell);
1163 }
1164
1165 /*
1166 * Convert fields from real-space grid to symmetry-adapted basis format.
1167 */
1168 template <int D>
1169 void System<D>::rGridToBasis(const std::string & inFileName,
1170 const std::string & outFileName)
1171 {
1172 // If basis fields are not allocated, peek at field file header to
1173 // get unit cell parameters, initialize basis and allocate fields.
1174 if (!isAllocatedBasis_) {
1175 readFieldHeader(inFileName);
1176 allocateFieldsBasis();
1177 }
1178
1179 // Read, convert and write fields
1180 UnitCell<D> tmpUnitCell;
1181 fieldIo().readFieldsRGrid(inFileName, tmpFieldsRGrid_, tmpUnitCell);
1182 fieldIo().convertRGridToBasis(tmpFieldsRGrid_, tmpFieldsBasis_);
1183 fieldIo().writeFieldsBasis(outFileName, tmpFieldsBasis_,
1184 tmpUnitCell);
1185 }
1186
1187 /*
1188 * Convert fields from Fourier (k-grid) to real-space (r-grid) format.
1189 */
1190 template <int D>
1191 void System<D>::kGridToRGrid(const std::string & inFileName,
1192 const std::string& outFileName)
1193 {
1194 // If basis fields are not allocated, peek at field file header to
1195 // get unit cell parameters, initialize basis and allocate fields.
1196 if (!isAllocatedBasis_) {
1197 readFieldHeader(inFileName);
1198 allocateFieldsBasis();
1199 }
1200
1201 // Read, convert and write fields
1202 UnitCell<D> tmpUnitCell;
1203 fieldIo().readFieldsKGrid(inFileName, tmpFieldsKGrid_, tmpUnitCell);
1204 for (int i = 0; i < mixture_.nMonomer(); ++i) {
1205 fft().inverseTransform(tmpFieldsKGrid_[i], tmpFieldsRGrid_[i]);
1206 }
1207 fieldIo().writeFieldsRGrid(outFileName, tmpFieldsRGrid_,
1208 tmpUnitCell);
1209 }
1210
1211 /*
1212 * Convert fields from real-space (r-grid) to Fourier (k-grid) format.
1213 */
1214 template <int D>
1215 void System<D>::rGridToKGrid(const std::string & inFileName,
1216 const std::string & outFileName)
1217 {
1218 // If basis fields are not allocated, peek at field file header to
1219 // get unit cell parameters, initialize basis and allocate fields.
1220 if (!isAllocatedBasis_) {
1221 readFieldHeader(inFileName);
1222 allocateFieldsBasis();
1223 }
1224
1225 // Read, convert and write fields
1226 UnitCell<D> tmpUnitCell;
1227 fieldIo().readFieldsRGrid(inFileName, tmpFieldsRGrid_,
1228 tmpUnitCell);
1229 for (int i = 0; i < mixture_.nMonomer(); ++i) {
1230 fft().forwardTransform(tmpFieldsRGrid_[i], tmpFieldsKGrid_[i]);
1231 }
1232 fieldIo().writeFieldsKGrid(outFileName, tmpFieldsKGrid_,
1233 tmpUnitCell);
1234 }
1235
1236 /*
1237 * Convert fields from Fourier (k-grid) to symmetry-adapted basis format.
1238 */
1239 template <int D>
1240 void System<D>::kGridToBasis(const std::string & inFileName,
1241 const std::string& outFileName)
1242 {
1243 // If basis fields are not allocated, peek at field file header to
1244 // get unit cell parameters, initialize basis and allocate fields.
1245 if (!isAllocatedBasis_) {
1246 readFieldHeader(inFileName);
1247 allocateFieldsBasis();
1248 }
1249
1250 // Read, convert and write fields
1251 UnitCell<D> tmpUnitCell;
1252 fieldIo().readFieldsKGrid(inFileName, tmpFieldsKGrid_, tmpUnitCell);
1253 fieldIo().convertKGridToBasis(tmpFieldsKGrid_, tmpFieldsBasis_);
1254 fieldIo().writeFieldsBasis(outFileName, tmpFieldsBasis_,
1255 tmpUnitCell);
1256 }
1257
1258 /*
1259 * Convert fields from symmetry-adapted basis to Fourier (k-grid) format.
1260 */
1261 template <int D>
1262 void System<D>::basisToKGrid(const std::string & inFileName,
1263 const std::string & outFileName)
1264 {
1265 // If basis fields are not allocated, peek at field file header to
1266 // get unit cell parameters, initialize basis and allocate fields.
1267 if (!isAllocatedBasis_) {
1268 readFieldHeader(inFileName);
1269 allocateFieldsBasis();
1270 }
1271
1272 // Read, convert and write fields
1273 UnitCell<D> tmpUnitCell;
1274 fieldIo().readFieldsBasis(inFileName, tmpFieldsBasis_, tmpUnitCell);
1275 fieldIo().convertBasisToKGrid(tmpFieldsBasis_, tmpFieldsKGrid_);
1276 fieldIo().writeFieldsKGrid(outFileName, tmpFieldsKGrid_,
1277 tmpUnitCell);
1278 }
1279
1280 // Private member functions
1281
1282 /*
1283 * Allocate memory for fields.
1284 */
1285 template <int D>
1287 {
1288 // Preconditions
1289 UTIL_CHECK(hasMixture_);
1290 int nMonomer = mixture().nMonomer();
1291 UTIL_CHECK(nMonomer > 0);
1292 UTIL_CHECK(domain_.mesh().size() > 0);
1293 UTIL_CHECK(!isAllocatedGrid_);
1294
1295 // Alias for mesh dimensions
1296 IntVec<D> const & dimensions = domain_.mesh().dimensions();
1297
1298 // Allocate W Fields
1299 w_.setNMonomer(nMonomer);
1300 w_.allocateRGrid(dimensions);
1301
1302 // Allocate C Fields
1303 c_.setNMonomer(nMonomer);
1304 c_.allocateRGrid(dimensions);
1305
1306 // Allocate temporary work space
1307 tmpFieldsRGrid_.allocate(nMonomer);
1308 tmpFieldsKGrid_.allocate(nMonomer);
1309 for (int i = 0; i < nMonomer; ++i) {
1310 tmpFieldsRGrid_[i].allocate(dimensions);
1311 tmpFieldsKGrid_[i].allocate(dimensions);
1312 }
1313
1314 workArray_.allocate(mesh().size());
1315 ThreadGrid::setThreadsLogical(mesh().size());
1316
1317 isAllocatedGrid_ = true;
1318 }
1319
1320 /*
1321 * Allocate memory for fields.
1322 */
1323 template <int D>
1324 void System<D>::allocateFieldsBasis()
1325 {
1326 // Preconditions and constants
1327 UTIL_CHECK(hasMixture_);
1328 const int nMonomer = mixture().nMonomer();
1329 UTIL_CHECK(nMonomer > 0);
1330 UTIL_CHECK(isAllocatedGrid_);
1331 UTIL_CHECK(!isAllocatedBasis_);
1332 UTIL_CHECK(domain_.unitCell().nParameter() > 0);
1333 UTIL_CHECK(domain_.mesh().size() > 0);
1334 UTIL_CHECK(domain_.basis().isInitialized());
1335 const int nBasis = basis().nBasis();
1336 UTIL_CHECK(nBasis > 0);
1337
1338 w_.allocateBasis(nBasis);
1339 c_.allocateBasis(nBasis);
1340
1341 // Temporary work space
1342 tmpFieldsBasis_.allocate(nMonomer);
1343 for (int i = 0; i < nMonomer; ++i) {
1344 tmpFieldsBasis_[i].allocate(nBasis);
1345 }
1346
1347 // Allocate memory for waveList
1348 if (!domain_.waveList().hasMinimumImages()) {
1349 domain_.waveList().computeMinimumImages(domain_.mesh(),
1350 domain_.unitCell());
1351 }
1352
1353 isAllocatedBasis_ = true;
1354 }
1355
1356 /*
1357 * Peek at field file header, initialize unit cell parameters and basis.
1358 */
1359 template <int D>
1360 void System<D>::readFieldHeader(std::string filename)
1361 {
1362 UTIL_CHECK(hasMixture_);
1363 UTIL_CHECK(mixture_.nMonomer() > 0);
1364
1365 // Open field file
1366 std::ifstream file;
1367 fileMaster_.openInputFile(filename, file);
1368
1369 // Read field file header, and initialize basis if needed
1370 int nMonomer;
1371 domain_.fieldIo().readFieldHeader(file, nMonomer,
1372 domain_.unitCell());
1373 // FieldIo::readFieldHeader initializes a basis if needed
1374 file.close();
1375
1376 // Postconditions
1377 UTIL_CHECK(mixture_.nMonomer() == nMonomer);
1378 UTIL_CHECK(domain_.unitCell().nParameter() > 0);
1379 UTIL_CHECK(domain_.unitCell().lattice() != UnitCell<D>::Null);
1380 UTIL_CHECK(domain_.unitCell().isInitialized());
1381 UTIL_CHECK(domain_.basis().isInitialized());
1382 UTIL_CHECK(domain_.basis().nBasis() > 0);
1383 }
1384
1385 /*
1386 * Read a filename string and echo to log file (used in readCommands).
1387 */
1388 template <int D>
1389 void System<D>::readEcho(std::istream& in, std::string& string) const
1390 {
1391 in >> string;
1392 Log::file() << " " << Str(string, 20) << std::endl;
1393 }
1394
1395 /*
1396 * Read floating point number, echo to log file (used in readCommands).
1397 */
1398 template <int D>
1399 void System<D>::readEcho(std::istream& in, double& value) const
1400 {
1401 in >> value;
1402 if (in.fail()) {
1403 UTIL_THROW("Unable to read floating point parameter.");
1404 }
1405 Log::file() << " " << Dbl(value, 20) << std::endl;
1406 }
1407
1408 /*
1409 * Initialize Pscf::Homogeneous::Mixture homogeneous_ member.
1410 */
1411 template <int D>
1412 void System<D>::initHomogeneous()
1413 {
1414
1415 // Set number of molecular species and monomers
1416 int nm = mixture().nMonomer();
1417 int np = mixture().nPolymer();
1418 int ns = mixture().nSolvent();
1419
1420 UTIL_CHECK(homogeneous_.nMolecule() == np + ns);
1421 UTIL_CHECK(homogeneous_.nMonomer() == nm);
1422
1423 int i; // molecule index
1424 int j; // monomer index
1425
1426 // Loop over polymer molecule species
1427 if (np > 0) {
1428
1429 DArray<double> cTmp;
1430 cTmp.allocate(nm);
1431
1432 int k; // block or clump index
1433 int nb; // number of blocks
1434 int nc; // number of clumps
1435 for (i = 0; i < np; ++i) {
1436
1437 // Initial array of clump sizes
1438 for (j = 0; j < nm; ++j) {
1439 cTmp[j] = 0.0;
1440 }
1441
1442 // Compute clump sizes for all monomer types.
1443 nb = mixture_.polymer(i).nBlock();
1444 for (k = 0; k < nb; ++k) {
1445 Block<D>& block = mixture_.polymer(i).block(k);
1446 j = block.monomerId();
1447 cTmp[j] += block.length();
1448 }
1449
1450 // Count the number of clumps of nonzero size
1451 nc = 0;
1452 for (j = 0; j < nm; ++j) {
1453 if (cTmp[j] > 1.0E-8) {
1454 ++nc;
1455 }
1456 }
1457 homogeneous_.molecule(i).setNClump(nc);
1458
1459 // Set clump properties for this Homogeneous::Molecule
1460 k = 0; // Clump index
1461 for (j = 0; j < nm; ++j) {
1462 if (cTmp[j] > 1.0E-8) {
1463 homogeneous_.molecule(i).clump(k).setMonomerId(j);
1464 homogeneous_.molecule(i).clump(k).setSize(cTmp[j]);
1465 ++k;
1466 }
1467 }
1468 homogeneous_.molecule(i).computeSize();
1469
1470 }
1471 }
1472
1473 // Add solvent contributions
1474 if (ns > 0) {
1475 double size;
1476 int monomerId;
1477 for (int is = 0; is < ns; ++is) {
1478 i = is + np;
1479 monomerId = mixture_.solvent(is).monomerId();
1480 size = mixture_.solvent(is).size();
1481 homogeneous_.molecule(i).setNClump(1);
1482 homogeneous_.molecule(i).clump(0).setMonomerId(monomerId);
1483 homogeneous_.molecule(i).clump(0).setSize(size);
1484 homogeneous_.molecule(i).computeSize();
1485 }
1486 }
1487
1488 }
1489
1490 #if 0
1491 /*
1492 * Check if fields are symmetric under space group.
1493 */
1494 template <int D>
1495 bool System<D>::checkRGridFieldSymmetry(const std::string & inFileName)
1496 const
1497 {
1498 // If basis fields are not allocated, peek at field file header to
1499 // get unit cell parameters, initialize basis and allocate fields.
1500 if (!isAllocatedBasis_) {
1501 readFieldHeader(inFileName);
1502 allocateFieldsBasis();
1503 }
1504 UTIL_CHECK(domain_.basis().isInitialized());
1505 const int nBasis = domain_.basis().nBasis();
1506 UTIL_CHECK(nBasis > 0);
1507
1508 UnitCell<D> tmpUnitCell;
1509 fieldIo().readFieldsRGrid(inFileName, tmpFieldsRGrid_, tmpUnitCell);
1510 for (int i = 0; i < mixture_.nMonomer(); ++i) {
1511 bool symmetric = fieldIo().hasSymmetry(tmpFieldsRGrid_[i]);
1512 if (!symmetric) {
1513 return false;
1514 }
1515 }
1516 return true;
1517 }
1518 #endif
1519
1520} // namespace Pspg
1521} // namespace Pscf
1522#endif
An IntVec<D, T> is a D-component vector of elements of integer type T.
Definition: IntVec.h:27
Flory-Huggins excess free energy model.
Definition: Interaction.h:26
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
Dynamic array on the GPU with alligned data.
Definition: DField.h:30
Data * cDField()
Return pointer to underlying C array.
Definition: DField.h:119
Factory for subclasses of Iterator.
Descriptor and solver for a branched polymer species.
MDE solver for one-direction of one block.
int ns() const
Get the number of contour grid points.
const cudaReal * tail() const
Return q-field at end of block.
const cudaReal * q(int i) const
Return q-field at specified step.
Field of real single precision values on an FFT mesh on a device.
Definition: RDField.h:34
void allocate(const IntVec< D > &meshDimensions)
Allocate the underlying C array for an FFT grid.
Definition: RDField.h:108
Solver and descriptor for a solvent species.
Default Factory for subclasses of Sweep.
Main class in SCFT simulation of one system.
Definition: pspg/System.h:71
void writeThermo(std::ostream &out)
Write thermodynamic properties to a file.
void readWRGrid(const std::string &filename)
Read chemical potential fields in real space grid (r-grid) format.
void setWRGrid(DArray< RDField< D > > const &fields)
Set new w fields, in real-space (r-grid) format.
void writeQSlice(std::string const &filename, int polymerId, int blockId, int directionId, int segmentId) const
Write specified slice of a propagator at fixed s in r-grid format.
void compute(bool needStress=false)
Solve the modified diffusion equation once, without iteration.
void writeGroup(std::string const &filename) const
Output all elements of the space group.
void symmetrizeWFields()
Symmetrize r-grid w-fields, compute basis components.
void writeCRGrid(const std::string &filename) const
Write concentration fields in real space grid (r-grid) format.
void estimateWfromC(const std::string &filename)
Construct trial w-fields from c-fields.
void writeStars(const std::string &filename) const
Output information about stars and symmetrized basis functions.
void rGridToBasis(const std::string &inFileName, const std::string &outFileName)
Convert a field from real-space grid to symmetrized basis format.
void rGridToKGrid(const std::string &inFileName, const std::string &outFileName)
Convert fields from real-space (r-grid) to Fourier (k-grid) format.
void basisToRGrid(const std::string &inFileName, const std::string &outFileName)
Convert a field from symmetry-adapted basis to r-grid format.
void writeParamNoSweep(std::ostream &out) const
Write parameter file to an ostream, omitting the sweep block.
int iterate(bool isContinuation=false)
Iteratively solve a SCFT problem.
void writeWBasis(const std::string &filename)
Write chemical potential fields in symmetry adapted basis format.
void setUnitCell(UnitCell< D > const &unitCell)
Set parameters of the associated unit cell.
void writeBlockCRGrid(const std::string &filename) const
Write c fields for all blocks and solvents in r-grid format.
void readParam()
Read input parameters from default param file.
~System()
Destructor.
Definition: pspg/System.tpp:80
void writeQTail(std::string const &filename, int polymerId, int blockId, int directionId) const
Write the final slice of a propagator in r-grid format.
void writeQ(std::string const &filename, int polymerId, int blockId, int directionId) const
Write one propagator for one block, in r-grid format.
void writeWRGrid(const std::string &filename) const
Write chemical potential fields in real space grid (r-grid) format.
void kGridToRGrid(const std::string &inFileName, const std::string &outFileName)
Convert fields from Fourier (k-grid) to real-space (r-grid) format.
void writeQAll(std::string const &basename)
Write all propagators of all blocks, each to a separate file.
void readCommands()
Read commands from default command file.
void basisToKGrid(const std::string &inFileName, const std::string &outFileName)
Convert fields from symmetrized basis to Fourier (k-grid) format.
void sweep()
Sweep in parameter space, solving an SCF problem at each point.
void writeCBasis(const std::string &filename)
Write concentrations in symmetry-adapted basis format.
System()
Constructor.
Definition: pspg/System.tpp:43
void setWBasis(DArray< DArray< double > > const &fields)
Set chemical potential fields, in symmetry-adapted basis format.
void writeWaves(const std::string &filename) const
Output information about waves.
void kGridToBasis(const std::string &inFileName, const std::string &outFileName)
Convert fields from Fourier (k-grid) to symmetrized basis format.
void readWBasis(const std::string &filename)
Read chemical potential fields in symmetry adapted basis format.
virtual void readParameters(std::istream &in)
Read body of parameter file (without opening, closing lines).
void setOptions(int argc, char **argv)
Process command line options.
void computeFreeEnergy()
Compute free energy density and pressure for current fields.
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
Base template for UnitCell<D> classes, D=1, 2 or 3.
Definition: UnitCell.h:44
int capacity() const
Return allocated size.
Definition: Array.h:159
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
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.
void setClassName(const char *className)
Set class name string.
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
void setThreadsPerBlock()
Set the number of threads per block to a default value.
Definition: ThreadGrid.cu:48
void setThreadsLogical(int nThreadsLogical)
Set the total number of threads required for execution.
Definition: ThreadGrid.cu:80
void init()
Initialize static variables in Pspg::ThreadGrid namespace.
Definition: ThreadGrid.cu:35
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