LIBINT 2.7.2
atom.h
1/*
2 * Copyright (C) 2004-2021 Edward F. Valeev
3 *
4 * This file is part of Libint.
5 *
6 * Libint is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Libint is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with Libint. If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#ifndef _libint2_src_lib_libint_atom_h_
22#define _libint2_src_lib_libint_atom_h_
23
24#include <libint2/util/cxxstd.h>
25#if LIBINT2_CPLUSPLUS_STD < 2011
26# error "libint2/atom.h requires C++11 support"
27#endif
28
29#include <array>
30#include <iostream>
31#include <sstream>
32#include <tuple>
33#include <utility>
34#include <vector>
35
36#include <libint2/chemistry/elements.h>
37
38namespace libint2 {
39
40 struct Atom {
41 int atomic_number;
42 double x, y, z;
43 };
44 inline bool operator==(const Atom& atom1, const Atom& atom2) {
45 return atom1.atomic_number == atom2.atomic_number && atom1.x == atom2.x &&
46 atom1.y == atom2.y && atom1.z == atom2.z;
47 }
48
49 namespace constants {
51 struct codata_2018 {
52 static constexpr double bohr_to_angstrom = 0.529177210903;
53 static constexpr double angstrom_to_bohr = 1 / bohr_to_angstrom;
54 };
56 struct codata_2014 {
57 static constexpr double bohr_to_angstrom = 0.52917721067;
58 static constexpr double angstrom_to_bohr = 1 / bohr_to_angstrom;
59 };
61 struct codata_2010 {
62 static constexpr double bohr_to_angstrom = 0.52917721092;
63 static constexpr double angstrom_to_bohr = 1 / bohr_to_angstrom;
64 };
65 } // namespace constants
66
67} // namespace libint2
68
69namespace {
70
71bool strcaseequal(const std::string &a, const std::string &b) {
72 return a.size() == b.size() &&
73 std::equal(a.begin(), a.end(), b.begin(), [](char a, char b) {
74 return ::tolower(a) == ::tolower(b);
75 });
76}
77
81inline std::tuple<std::vector<libint2::Atom>,
83__libint2_read_dotxyz(std::istream &is, const double bohr_to_angstrom,
84 const bool pbc = false) {
85 using libint2::Atom;
86 const std::string caller = std::string("libint2::read_dotxyz") + (pbc ? "_pbc" : "");
87
88 // first line = # of atoms
89 size_t natom;
90 is >> natom;
91
92 // read off the rest of first line and discard
93 std::string rest_of_line;
94 std::getline(is, rest_of_line);
95
96 // second line = comment
97 std::string comment;
98 std::getline(is, comment);
99
100 // rest of lines are atoms (and unit cell parameters, if pbc = true)
101 const auto nlines_expected = natom + (pbc ? 3 : 0);
102 std::vector<Atom> atoms(natom, Atom{0, 0.0, 0.0, 0.0});
103 std::array<std::array<double, 3>, 3> unit_cell({{{0.0, 0.0, 0.0}}});
104 bool found_abc[3] = {false, false, false};
105 for (size_t line = 0, atom_index = 0; line < nlines_expected; ++line) {
106 if (is.eof())
107 throw std::logic_error(caller + ": expected " +
108 std::to_string(nlines_expected) +
109 " sets of coordinates but only " +
110 std::to_string(line) + " received");
111
112 // read line
113 std::string linestr;
114 std::getline(is, linestr);
115 std::istringstream iss(linestr);
116 // then parse ... this handles "extended" XYZ formats
117 std::string element_symbol;
118 double x, y, z;
119 iss >> element_symbol >> x >> y >> z;
120
121 // .xyz files report Cartesian coordinates in angstroms; convert to bohr
122 const auto angstrom_to_bohr = 1 / bohr_to_angstrom;
123
124 auto assign_atom = [angstrom_to_bohr](Atom &atom, int Z, double x, double y,
125 double z) {
126 atom.atomic_number = Z;
127 atom.x = x * angstrom_to_bohr;
128 atom.y = y * angstrom_to_bohr;
129 atom.z = z * angstrom_to_bohr;
130 };
131 auto assign_xyz = [angstrom_to_bohr](std::array<double, 3> &xyz, double x,
132 double y, double z) {
133 xyz[0] = x * angstrom_to_bohr;
134 xyz[1] = y * angstrom_to_bohr;
135 xyz[2] = z * angstrom_to_bohr;
136 };
137
138 auto axis = -1;
139 // if pbc = true, look for unit cell params
140 if (pbc) {
141 if (strcaseequal("AA", element_symbol))
142 axis = 0;
143 if (strcaseequal("BB", element_symbol))
144 axis = 1;
145 if (strcaseequal("CC", element_symbol))
146 axis = 2;
147 if (axis != -1) {
148 if (found_abc[axis])
149 throw std::logic_error(
150 caller + ": unit cell parameter along Cartesian axis " +
151 std::to_string(axis) + " appears more than once");
152 assign_xyz(unit_cell[axis], x, y, z);
153 found_abc[axis] = true;
154 }
155 }
156
157 // .xyz files report element labels, hence convert to atomic numbers
158 if (axis == -1) {
159 int Z = -1;
160 for (const auto &e : libint2::chemistry::get_element_info()) {
161 if (strcaseequal(e.symbol, element_symbol)) {
162 Z = e.Z;
163 break;
164 }
165 }
166 if (Z == -1) {
167 std::ostringstream oss;
168 oss << caller << ": element symbol \"" << element_symbol
169 << "\" is not recognized" << std::endl;
170 throw std::logic_error(oss.str().c_str());
171 }
172
173 if (pbc && atom_index == atoms.size()) { // if PBC, check for too many atoms
174 throw std::logic_error(caller + ": too many atoms");
175 }
176 assign_atom(atoms[atom_index++], Z, x, y, z);
177 }
178 }
179
180 // make sure all 3 axes were specified
181 if (pbc) {
182 for(auto xyz=0; xyz!=3; ++xyz)
183 if (!found_abc[xyz]) {
184 throw std::logic_error(caller +
185 ": unit cell parameter along Cartesian axis " +
186 std::to_string(xyz) + " not given");
187 }
188 }
189
190 return std::make_tuple(atoms, unit_cell);
191}
192
193} // anonymous namespace
194
195namespace libint2 {
196
197// clang-format off
209// clang-format off
210inline std::vector<Atom> read_dotxyz(
211 std::istream &is,
212 const double bohr_to_angstrom = constants::codata_2018::bohr_to_angstrom) {
213 std::vector<Atom> atoms;
214 std::tie(atoms, std::ignore) =
215 __libint2_read_dotxyz(is, bohr_to_angstrom, false);
216 return atoms;
217}
218
234inline auto read_dotxyz_pbc(
235 std::istream &is,
236 const double bohr_to_angstrom = constants::codata_2018::bohr_to_angstrom)
237 -> decltype(__libint2_read_dotxyz(is, bohr_to_angstrom, true)) {
238 return __libint2_read_dotxyz(is, bohr_to_angstrom, true);
239}
240
242std::vector<std::pair<double, std::array<double, 3>>> inline make_point_charges(
243 const std::vector<libint2::Atom> &atoms) {
244 std::vector<std::pair<double, std::array<double, 3>>> q;
245 q.reserve(atoms.size());
246 for (const auto &atom : atoms) {
247 q.emplace_back(static_cast<double>(atom.atomic_number),
248 std::array<double, 3>{{atom.x, atom.y, atom.z}});
249 }
250 return q;
251}
252
253} // namespace libint2
254
255#endif /* _libint2_src_lib_libint_atom_h_ */
Array idential to C++0X arrays.
Definition: stdarray_bits.h:14
Defaults definitions for various parameters assumed by Libint.
Definition: algebra.cc:24
auto read_dotxyz_pbc(std::istream &is, const double bohr_to_angstrom=constants::codata_2018::bohr_to_angstrom) -> decltype(__libint2_read_dotxyz(is, bohr_to_angstrom, true))
reads the list of atoms from a file in the PBC-extended XYZ format
Definition: atom.h:234
std::vector< std::pair< double, std::array< double, 3 > > > make_point_charges(const std::vector< libint2::Atom > &atoms)
converts a vector of Atoms to a vector of point charges
Definition: atom.h:242
std::vector< Atom > read_dotxyz(std::istream &is, const double bohr_to_angstrom=constants::codata_2018::bohr_to_angstrom)
reads the list of atoms from a file in the standard XYZ format supported by most chemistry software (...
Definition: atom.h:210
Definition: atom.h:40
the 2010 CODATA reference set, available at DOI 10.1103/RevModPhys.84.1527
Definition: atom.h:61
the 2014 CODATA reference set, available at DOI 10.1103/RevModPhys.88.035009
Definition: atom.h:56
the 2018 CODATA reference set, available at https://physics.nist.gov/cuu/pdf/wall_2018....
Definition: atom.h:51