-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpotentials.cpp
207 lines (184 loc) · 5.96 KB
/
potentials.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
// Coulombo Ⓒ 2023
// [Computer Physics Communications] Różański & Zieliński:
// Exploiting underlying crystal lattice for efficient computation of Coulomb matrix elements in multi-million atoms nanostructures
#ifdef _OPENMP
#include <omp.h>
#endif
#include <fftw3-mpi.h>
#include <list>
#include <map>
#include <string>
#include <utility>
#include "base.hpp"
#include "mpi.hpp"
#include "throwf.hpp"
#include "Broadcaster.hpp"
#include "Domain.hpp"
#include "CoulombCalculator.hpp"
#include "FunctionCollection.hpp"
#include "Graph.hpp"
#include "Parser.hpp"
#include "Pattern.hpp"
#include "Planner.hpp"
#include "Product.hpp"
#include "Timer.hpp"
#define VERSION "2.0"
//----------------------------------------------------------------------
void coulombo(const ParseResults& pr)
{
Timer timer;
std::string value;
// initialize FFTW
#ifdef _OPENMP
int threadsPerNode = 1;
if (pr.hasValue("threads-per-node", value)) {
threadsPerNode = atoi(value.c_str());
if (threadsPerNode <= 0) {
throwfr("invalid value for threads-per-node");
}
}
omp_set_num_threads(threadsPerNode);
if (threadsPerNode > 1) {
fftw_init_threads();
}
#endif
fftw_mpi_init();
#ifdef _OPENMP
if (threadsPerNode > 1) {
fftw_plan_with_nthreads(threadsPerNode);
}
#endif
timer.start("Reading atom positions");
// initialize input type
int orbitalCount = 20;
if (pr.hasValue("orbitals", value)) {
orbitalCount = atoi(value.c_str());
if (orbitalCount <= 0) {
throwfr("invalid value for orbitals");
}
}
int headerLinesToSkip = 0;
if (pr.hasValue("skip-lines", value)) {
headerLinesToSkip = atoi(value.c_str());
if (headerLinesToSkip <= 0) {
throwfr("invalid value for skip-lines");
}
}
std::shared_ptr<FunctionCollection> functions;
functions.reset(new FunctionCollection(pr.getValue("atoms"), orbitalCount, headerLinesToSkip));
// parse various settings
double dielectric = 1.0;
if (pr.hasValue("dielectric", value)) {
dielectric = atof(value.c_str());
}
std::string outputDir;
if (pr.hasValue("output-dir", outputDir) && !outputDir.empty()) {
outputDir += '/';
}
timer.start("Reading wavefunctions");
// read input files
int inputCount = pr.getArgCount();
if (inputCount >= std::numeric_limits<short>::max()) {
throwfr("too many input files");
}
std::vector<std::string> fileNames;
for (int input = 0; input<inputCount; ++input) {
const std::string arg = pr.getArg(input);
const char* basename = arg.c_str();
auto last_slash = arg.find_last_of('/');
if (last_slash != std::string::npos) {
basename += last_slash + 1;
}
functions->appendFile(pr.getArg(input));
fileNames.push_back(basename);
}
Dimension dimension = functions->getPaddedDimension();
timer.start("Initializing calculator");
// get onsite value
double onsite = 0.0;
if (pr.hasValue("onsite", value)) {
onsite = atof(value.c_str());
}
// initialize dielectric screening model
Vector3D<double> stepXYZ = functions->getStepValues();
std::unique_ptr<Interaction> interaction;
if (pr.hasValue("tf-lattice", value)) {
double latticeConstant = atof(value.c_str());
if (!std::isgreater(latticeConstant, 0.0)) {
throwfr("--tf-lattice parameter must be positive");
}
if (!std::isgreater(dielectric, 1.0)) {
throwfr("dielectric constant must be >1 to use Thomas-Fermi model");
}
interaction.reset( new InteractionThomasFermi(stepXYZ, onsite, dielectric, latticeConstant) );
} else {
interaction.reset( new InteractionSimple(stepXYZ, onsite, dielectric) );
}
// initialize buffers
CoulombCalculator calculator(dimension);
calculator.initialize(*interaction);
timer.start("Computing all quasi-potentials");
// perform the actual computation
ProductCollection products = functions->createSelfProducts();
auto fileNameIterator = fileNames.begin();
for (const auto& product : products) {
product->map(calculator.input, false);
calculator.prepare();
std::vector<complex> fullPotentialValues = functions->extractAtomCellValues(calculator.potential());
if (mpi::root()) {
std::string outputFilePath = outputDir + "potential-" + *fileNameIterator;
FILE* file = fopen(outputFilePath.c_str(), "w");
if (!file) {
throwfr("cannot open file %s for writing", outputFilePath.c_str());
}
for (complex x : fullPotentialValues) {
fprintf(file, "%.12le\n", x.real());
}
++fileNameIterator;
}
}
}
int main(int argc, char** argv)
{
try {
mpi::init(argc, argv);
Parser cmd;
cmd.allowValue("atoms");
cmd.allowValue("dielectric");
cmd.allowValue("onsite");
cmd.allowValue("orbitals");
cmd.allowValue("output-dir");
cmd.allowValue("skip-lines");
#ifdef _OPENMP
cmd.allowValue("threads-per-node");
#endif
cmd.allowValue("tf-lattice");
ParseResults pr = cmd.process(argc, argv);
if (!pr.getArgCount()) {
fprintf(stderr,
"Coulombo v" VERSION " (c) 2023 [Computer Physics Communications] Rozanski & Zielinski:\n"
"Exploiting underlying crystal lattice for efficient computation of Coulomb matrix elements in multi-million atoms nanostructures\n"
"\nUSAGE:\n"
" potentials [FLAGS/OPTIONS] data files ...\n"
"\nOPTIONS:\n"
" --atoms=PATH path to *.3d file with atoms' positions\n"
" --dielectric=VALUE dielectric constant, default: 1\n"
" --onsite=ENERGY energy for on-site contribution, default: 0 (eV)\n"
" --orbitals=N number of (spin-)orbitals per atom, default: 20\n"
" --output-dir=DIR directory for output files, default: current\n"
" --skip-lines=N number of lines to be skipped on top of each LCAO file, default: 0\n"
#ifdef _OPENMP
" --threads-per-node=N number of OpenMP threads per node, default: 1\n"
#endif
" --tf-lattice=VALUE lattice constant (Å) for Thomas-Fermi-Resta model,\n"
" default: model not applied\n"
"\n");
exit(EXIT_FAILURE);
}
coulombo(pr);
mpi::finalize();
} catch (std::exception& ex) {
fprintf(stderr, "ERROR: %s\n", ex.what());
exit(EXIT_FAILURE);
}
}