Kindfield
 All Classes Namespaces Files Functions Variables Enumerations Enumerator Properties Friends Pages
main.cpp
Go to the documentation of this file.
5 #include <math/vector3.h>
6 
7 #include <iomanip>
8 #include <iostream>
9 #include <fstream>
10 #include <yaml-cpp/yaml.h>
11 
12 #include <H5Cpp.h>
13 
14 using namespace std;
15 
16 void operator >> (const YAML::Node& node, Vector3& v)
17 {
18  double x;
19  double y;
20  double z;
21  node[0] >> x;
22  node[1] >> y;
23  node[2] >> z;
24  v = Vector3(x,y,z);
25 }
26 
27 class Method {
28 public:
29  enum MethodName {
32  Unrestricted
33  };
34 };
35 
36 
37 class Output {
38 public:
39  enum OutputName {
43  ElectrostaticPotential
44  };
45 };
46 
47 int main(int argc, char* argv[])
48 {
49  if(argc < 2) {
50  cerr << "Too few arguments." << endl;
51  cerr << "Usage: hartree-fock <config.yaml>" << endl;
52  return 1;
53  }
54  string outputPath = "";
55  if(argc >= 3) {
56  outputPath = argv[2];
57  outputPath += "/";
58  cout << "Output will be written to " << outputPath << endl;
59  }
60  ifstream fin(argv[1]);
61  if(fin.fail()) {
62  cerr << "Could not open the configuration file " << argv[1] << endl;
63  return 1;
64  }
65  YAML::Parser parser(fin);
66 
67  YAML::Node rootNode;
68  parser.GetNextDocument(rootNode);
69  unsigned int nAtoms = rootNode["atoms"].size();
70  string defaultBasis = "3-21G";
71  try {
72  rootNode["basis"] >> defaultBasis;
73  cout << "Using basis " << defaultBasis << endl;
74  } catch( YAML::TypedKeyNotFound<std::string> ) {
75  cout << "Default basis not found, expecting atom to have basis name or assuming " << defaultBasis << endl;
76  }
77 
78  struct AtomData {
79  double x;
80  double y;
81  double z;
82  double partialCharge;
83  };
84 
85  H5::CompType atomCompound( sizeof(AtomData) );
86  atomCompound.insertMember("x", HOFFSET(AtomData, x), H5::PredType::NATIVE_DOUBLE);
87  atomCompound.insertMember("y", HOFFSET(AtomData, y), H5::PredType::NATIVE_DOUBLE);
88  atomCompound.insertMember("z", HOFFSET(AtomData, z), H5::PredType::NATIVE_DOUBLE);
89 
90  struct AtomMetaData {
91  int type;
92  char basisName[64];
93  };
94 
95  H5::CompType atomMetaCompound( sizeof(AtomMetaData) );
96  atomMetaCompound.insertMember("type", HOFFSET(AtomMetaData, type), H5::PredType::NATIVE_INT);
97  atomMetaCompound.insertMember("basisName", HOFFSET(AtomMetaData, basisName), H5::StrType(H5::PredType::C_S1, 64));
98 
99  H5::H5File outFile(outputPath + "results.h5", H5F_ACC_TRUNC);
100  hsize_t dim[] = {nAtoms};
101  H5::DataSet stateDataSet = outFile.createDataSet("state", atomCompound, H5::DataSpace(1, dim));
102  H5::DataSet atomMetaDataSet(outFile.createDataSet("atomMeta", atomMetaCompound, H5::DataSpace(1, dim)));
103 
104  AtomData atoms[nAtoms];
105  AtomMetaData atomsMeta[nAtoms];
106 
107  GaussianSystem system;
109  vector<Output::OutputName> outputs;
110  for(YAML::Iterator it=rootNode.begin();it!=rootNode.end();++it) {
111  string rootKey;
112  it.first() >> rootKey;
113  if(rootKey == "atoms") {
114  int atomCounter = 0;
115  const YAML::Node &atomsNode = it.second();
116  for(YAML::Iterator it2=atomsNode.begin();it2!=atomsNode.end();++it2) {
117  const YAML::Node &atomNode = *it2;
118  string typeAbbreviation;
119  atomNode["type"] >> typeAbbreviation;
120  Vector3 position;
121  atomNode["position"] >> position;
122  string basis;
123  try {
124  atomNode["basis"] >> basis;
125  } catch( YAML::TypedKeyNotFound<std::string> ) {
126  basis = defaultBasis;
127  }
128 
129  basis = HF::escapeBasis(basis);
130 
131  strncpy(atomsMeta[atomCounter].basisName, basis.c_str(), 63);
132  atomsMeta[atomCounter].type = HF::abbreviationToAtomType(typeAbbreviation);
133  system.addCore(GaussianCore(position, typeAbbreviation, basis));
134  atoms[atomCounter].x = position.x();
135  atoms[atomCounter].y = position.y();
136  atoms[atomCounter].z = position.z();
137  atomCounter++;
138  }
139  } else if(rootKey == "method") {
140  string methodName;
141  it.second() >> methodName;
142  if(methodName == "unrestricted") {
143  method = Method::Unrestricted;
144  } else if(methodName == "restricted") {
145  method = Method::Restricted;
146  } else {
147  cerr << "Error: Unknown method name " << methodName << endl;
148  return 1;
149  }
150  } else if(rootKey == "electronsDown" || rootKey == "electronsUp") {
151  int electronsDown;
152  it.second() >> electronsDown;
153  system.setNParticlesDown(electronsDown);
154  } else if(rootKey == "output") {
155  const YAML::Node &outputNode = it.second();
156  for(YAML::Iterator it2=outputNode.begin();it2!=outputNode.end();++it2) {
157  string outputName;
158  *it2 >> outputName;
159  if(outputName == "energy") {
160  outputs.push_back(Output::Energy);
161  } else if(outputName == "density") {
162  outputs.push_back(Output::Density);
163  } else if(outputName == "electrostatic_potential") {
164  outputs.push_back(Output::ElectrostaticPotential);
165  }
166  }
167  }
168  }
169  stateDataSet.write(atoms, atomCompound);
170  atomMetaDataSet.write(atomsMeta, atomMetaCompound);
171 
172  double energy = 0.0;
173  mat coefficientsUp;
174  mat coefficientsDown;
175  if(method == Method::Unrestricted) {
176  cout << "Setting up the unrestricted Hartree-Fock solver..." << endl;
177  UnrestrictedHartreeFockSolver solver(&system);
178  solver.setConvergenceTreshold(1e-10);
179  solver.setDensityMixFactor(0.95);
180  solver.setNIterationsMax(1e4);
181  cout << "Solving..." << endl;
182  solver.solve();
183  energy = solver.energy();
184  cout << "Energy: " << setprecision(16) << solver.energy() << endl;
185 
186  coefficientsUp = solver.coeffcientMatrixUp();
187  coefficientsDown = solver.coeffcientMatrixDown();
188 
189  } else {
190  cout << "Setting up the restricted Hartree-Fock solver..." << endl;
191  RestrictedHartreeFockSolver solver(&system);
192  solver.setConvergenceTreshold(1e-12);
193  solver.setDensityMixFactor(0.95);
194  solver.setNIterationsMax(1e4);
195  cout << "Solving..." << endl;
196  solver.solve();
197  energy = solver.energy();
198  cout << "Energy: " << setprecision(16) << solver.energy() << endl;
199 
200  coefficientsUp = solver.coefficientMatrix();
201  }
202  cout << "Writing requested output to file:" << endl;
203  for(Output::OutputName output : outputs) {
204  if(output == Output::Energy) {
205  cout << "Writing energy..." << endl;
206  H5::Attribute energyAttribute(stateDataSet.createAttribute("energy", H5::PredType::NATIVE_DOUBLE, H5S_SCALAR));
207  energyAttribute.write(H5::PredType::NATIVE_DOUBLE, &energy);
208  } else if(output == Output::Density) {
209  cout << "Calculating density..." << endl;
210 
211  mat coefficientsAll;
212  if(method == Method::Unrestricted) {
213  coefficientsAll = join_rows(coefficientsUp, coefficientsDown);
214  } else if(method == Method::Restricted) {
215  coefficientsAll = coefficientsUp;
216  }
217  vec x = linspace(-3, 3, 100);
218  vec y = linspace(-3, 3, 100);
219  vec z = linspace(-3, 3, 100);
220  cube totalDensity = zeros(x.n_elem, y.n_elem, z.n_elem);
221  field<cube> orbitalDensities;
222  orbitalDensities.set_size(system.nParticles());
223  for(cube& orbitalDensity : orbitalDensities) {
224  orbitalDensity = zeros(x.n_elem, y.n_elem, z.n_elem);
225  }
226  for(uint i = 0; i < x.n_elem; i++) {
227  for(uint j = 0; j < y.n_elem; j++) {
228  for(uint k = 0; k < z.n_elem; k++) {
229  Vector3 position(x(i), y(j), z(k));
230  rowvec density = system.orbitalDensities(coefficientsAll, position);
231  for(uint orbital = 0; orbital < orbitalDensities.size(); orbital++) {
232  cube &orbitalDensity = orbitalDensities(orbital);
233  orbitalDensity(k,j,i) = density(orbital);
234  }
235  totalDensity(k,j,i) = sum(density);
236  }
237  }
238  }
239  for(uint orbital = 0; orbital < orbitalDensities.size(); orbital++) {
240  cube &orbitalDensity = orbitalDensities(orbital);
241  orbitalDensity.save(outputPath + "orbital_density_" + to_string(orbital) + ".h5", hdf5_binary);
242  }
243  totalDensity.save(outputPath + "density.h5", hdf5_binary);
244  } else if(output == Output::ElectrostaticPotential) {
245  cout << "Calculating electrostatic potential..." << endl;
246  if(method == Method::Unrestricted) {
247 
248  vec x = linspace(-5, 5, 50);
249  vec y = linspace(-5, 5, 50);
250  vec z = linspace(-5, 5, 50);
251  cube electrostaticPotential = zeros(x.n_elem, y.n_elem, z.n_elem);
252  mat coefficientsAll = join_rows(coefficientsUp, coefficientsDown);
253  for(uint i = 0; i < x.n_elem; i++) {
254  for(uint j = 0; j < y.n_elem; j++) {
255  for(uint k = 0; k < z.n_elem; k++) {
256  Vector3 position(x(i), y(j), z(k));
257  electrostaticPotential(k,j,i) = system.electrostaticPotential(coefficientsAll, position);
258  }
259  }
260  }
261  electrostaticPotential.save(outputPath + "electrostatic_potential.h5", hdf5_binary);
262  }
263  }
264  }
265  outFile.close();
266  cout << "Done." << endl;
267  return 0;
268 }
269