• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

adc-connect / adcc / 5362537629

pending completion
5362537629

push

github

mfherbst
Bump version: 0.15.16 → 0.15.17

1487 of 2318 branches covered (64.15%)

Branch coverage included in aggregate %.

1 of 1 new or added line in 1 file covered. (100.0%)

7130 of 9470 relevant lines covered (75.29%)

191956.13 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

77.4
/libadcc/ReferenceState.cc
1
//
2
// Copyright (C) 2019 by the adcc authors
3
//
4
// This file is part of adcc.
5
//
6
// adcc is free software: you can redistribute it and/or modify
7
// it under the terms of the GNU General Public License as published
8
// by the Free Software Foundation, either version 3 of the License, or
9
// (at your option) any later version.
10
//
11
// adcc 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 General Public License for more details.
15
//
16
// You should have received a copy of the GNU General Public License
17
// along with adcc. If not, see <http://www.gnu.org/licenses/>.
18
//
19

20
#include "ReferenceState.hh"
21
#include "MoIndexTranslation.hh"
22
#include "TensorImpl.hh"
23
#include "exceptions.hh"
24
#include "import_eri.hh"
25
#include "make_symmetry.hh"
26

27
namespace libadcc {
28
ReferenceState::ReferenceState(std::shared_ptr<const HartreeFockSolution_i> hfsoln_ptr,
632✔
29
                               std::shared_ptr<const MoSpaces> mo_ptr,
30
                               bool symmetry_check_on_import)
632✔
31
      : m_n_alpha{0},
632✔
32
        m_n_beta{0},
632✔
33
        m_orben{},
632✔
34
        m_orbcoeff{},
632✔
35
        m_orbcoeff_alpha{},
632✔
36
        m_orbcoeff_beta{},
632✔
37
        m_fock{},
632✔
38
        m_eri{},
632✔
39
        m_hfsoln_ptr{hfsoln_ptr},
632✔
40
        m_mo_ptr{mo_ptr},
632✔
41
        m_symmetry_check_on_import{symmetry_check_on_import},
632✔
42
        m_timer{} {
632✔
43
  for (auto& ss : mo_ptr->subspaces_occupied) {
1,610✔
44
    m_n_alpha += mo_ptr->n_orbs_alpha(ss);
978✔
45
    m_n_beta += mo_ptr->n_orbs_beta(ss);
978✔
46
  }
47

48
  // Import orbital energies and coefficients
49
  import_orbital_energies(*hfsoln_ptr, mo_ptr, symmetry_check_on_import);
632✔
50
  import_orbital_coefficients(*hfsoln_ptr, mo_ptr, symmetry_check_on_import);
632✔
51
}
632✔
52

53
//
54
// Importers
55
//
56
void ReferenceState::import_orbital_energies(
632✔
57
      const HartreeFockSolution_i& hf, const std::shared_ptr<const MoSpaces>& mo_ptr,
58
      bool symmetry_check_on_import) {
59
  m_orben.clear();
632✔
60
  RecordTime rec(m_timer, "import/orbital_energies");
1,264✔
61

62
  std::vector<scalar_type> tmp_orben(hf.n_orbs());
632✔
63
  hf.orben_f(tmp_orben.data(), tmp_orben.size());
632✔
64
  for (auto& ss : mo_ptr->subspaces) {
2,374✔
65
    std::shared_ptr<Symmetry> sym_ptr = make_symmetry_orbital_energies(mo_ptr, ss);
1,742✔
66
    std::shared_ptr<Tensor> orben     = make_tensor_zero(sym_ptr);
1,742✔
67
    MoIndexTranslation idxtrans(mo_ptr, ss);
1,742✔
68

69
    auto orben_generator = [&tmp_orben, &idxtrans](
2,278✔
70
                                 const std::vector<std::pair<size_t, size_t>>& block,
71
                                 scalar_type* buffer) {
6,842✔
72
      const std::pair<size_t, size_t>& block_ss = block[0];
2,278✔
73
      const size_t length_ss_full               = block_ss.second - block_ss.first;
2,278✔
74

75
      std::vector<RangeMapping> mappings = idxtrans.map_range_to_hf_provider(block);
4,556✔
76
      for (const RangeMapping& map : mappings) {
4,560✔
77
        // orben is 1D -> idim == 0 always
78
        const size_t idim = 0;
2,282✔
79

80
        // Starting index of the mapping in the adcc index convention
81
        const size_t start = map.from().axis(idim).start() - block_ss.first;
2,282✔
82

83
        // Start and end in the HfProvider indexing convention
84
        const size_t start_hf = map.to().axis(idim).start();
2,282✔
85
        const size_t end_hf   = map.to().axis(idim).end();
2,282✔
86

87
        if (start + (end_hf - start_hf) > length_ss_full) {
2,282✔
88
          throw runtime_error("Internal error: Out-of-bounds write in orben_generator");
×
89
        }
90
        // Do the "import" by copying the appropriate part of the buf_orben object
91
        std::copy(tmp_orben.begin() + static_cast<ptrdiff_t>(start_hf),
2,282✔
92
                  tmp_orben.begin() + static_cast<ptrdiff_t>(end_hf), buffer + start);
4,564✔
93
      }
94
    };
2,278✔
95
    orben->import_from(orben_generator, hf.conv_tol(), symmetry_check_on_import);
1,742✔
96
    orben->set_immutable();
1,742✔
97
    m_orben[ss] = orben;
1,742✔
98
  }
1,742✔
99
}
632✔
100

101
void ReferenceState::import_orbital_coefficients(
632✔
102
      const HartreeFockSolution_i& hf, const std::shared_ptr<const MoSpaces>& mo_ptr,
103
      bool symmetry_check_on_import) {
104
  RecordTime rec(m_timer, "import/orbital_coefficients");
1,264✔
105
  m_orbcoeff.clear();
632✔
106
  m_orbcoeff_alpha.clear();
632✔
107
  m_orbcoeff_beta.clear();
632✔
108

109
  std::vector<scalar_type> tmp_orbcoeff(hf.n_orbs() * hf.n_bas());
632✔
110
  tmp_orbcoeff.resize(hf.n_orbs() * hf.n_bas());
632✔
111
  hf.orbcoeff_fb(tmp_orbcoeff.data(), tmp_orbcoeff.size());
632✔
112
  for (auto& ss : mo_ptr->subspaces) {
2,374✔
113
    // The index translation for the first subspace (which is not "b")
114
    MoIndexTranslation idxtrans(mo_ptr, ss);
1,742✔
115

116
    auto orbcoeff_generator_ab = [&tmp_orbcoeff, &idxtrans, &hf](
5,604✔
117
                                       const std::vector<std::pair<size_t, size_t>>&
118
                                             block,
119
                                       scalar_type* buffer, bool alpha, bool beta) {
50,500✔
120
      const std::pair<size_t, size_t>& block_ss = block[0];
5,604✔
121
      const std::pair<size_t, size_t>& block_b  = block[1];
5,604✔
122

123
      // Length of the axis:
124
      const size_t length_b       = block_b.second - block_b.first;
5,604✔
125
      const size_t length_ss_full = block_ss.second - block_ss.first;
5,604✔
126

127
      std::vector<RangeMapping> mappings_ss =
128
            idxtrans.map_range_to_hf_provider({{block_ss}});
11,208✔
129
      for (const RangeMapping& map_ss : mappings_ss) {
11,216✔
130
        // Get start and end of index ranges in adcc and HfProvider convention
131
        const size_t idim      = 0;  // The ss subspace of orbcoeff is 1D => idim == 0
5,612✔
132
        const size_t start_ss  = map_ss.from().axis(idim).start();
5,612✔
133
        const size_t end_ss    = map_ss.from().axis(idim).end();
5,612✔
134
        const size_t length_ss = end_ss - start_ss;
5,612✔
135

136
        const size_t start_hf = map_ss.to().axis(idim).start();
5,612✔
137
        const size_t end_hf   = map_ss.to().axis(idim).end();
5,612✔
138

139
        // Since the orbecoeff are 2D-arrays and moreover the tmp_orbcoeff vector is a 2D
140
        // array in row-major C-like index ordering, the first element of this buffer to
141
        // copy is
142
        auto ittmp = tmp_orbcoeff.begin() +
11,224✔
143
                     static_cast<ptrdiff_t>(start_hf * hf.n_bas() + block_b.first);
5,612✔
144

145
        // The first element into which data will be copied, on the other hand,
146
        // is shifted, like the following, since in the output buffer there will
147
        // length_b columns and the first (start_ss - block_ss.first) rows are skipped
148
        // in this mapping loop.
149
        scalar_type* ptrbuf =
5,612✔
150
              buffer + static_cast<ptrdiff_t>((start_ss - block_ss.first) * length_b);
5,612✔
151

152
        if (alpha && beta) {
5,612✔
153
          throw runtime_error("Internal error: Requested both alpha and beta block.");
×
154
        }
155

156
        // Fill with zeros if we are in the alpha or beta block and this
157
        // should be skipped
158
        bool fill_zeros = false;
5,612✔
159
        if (idxtrans.spin_of({start_ss}) == "b") {
5,612✔
160
          if (idxtrans.spin_of({end_ss - 1}) != "b") {
2,810✔
161
            throw runtime_error(
×
162
                  "Internal error: Assertion about blocks being split whenever spin "
163
                  "changes is violated.");
×
164
          }
165
          if (!beta) {
2,810✔
166
            // beta block should be zero
167
            fill_zeros = true;
590✔
168
          }
169
        }
170
        if (idxtrans.spin_of({end_ss - 1}) == "a") {
5,612✔
171
          if (idxtrans.spin_of({start_ss}) != "a") {
2,802✔
172
            throw runtime_error(
×
173
                  "Internal error: Assertion about blocks being split whenever spin "
174
                  "changes is violated.");
×
175
          }
176
          if (!alpha) {
2,802✔
177
            // beta block should be zero
178
            fill_zeros = true;
586✔
179
          }
180
        }
181

182
        const ptrdiff_t slength_b = static_cast<ptrdiff_t>(length_b);
5,612✔
183
        const ptrdiff_t sn_bas    = static_cast<ptrdiff_t>(hf.n_bas());
5,612✔
184

185
        // Copy length_b elements at a time (one row) and then advance the pointer into
186
        // the buffer (ptrbuf) and the iterator into the tmp_orbcoeff vector.
187
        // For the ittmp iterator, n_bas() elements need to be skipped, for ptrbuf only
188
        // length_b, because it only is a matrix block with length_b columns.
189
        for (size_t irow = 0; irow < length_ss;
33,436✔
190
             ++irow, ptrbuf += length_b, ittmp += sn_bas) {
27,824✔
191
          if (ptrbuf + slength_b > buffer + length_ss_full * length_b) {
27,824✔
192
            throw runtime_error(
×
193
                  "Internal error: Out-of-bounds write in orbcoeff_generator");
×
194
          }
195
          if (fill_zeros) {
27,824✔
196
            std::fill(ptrbuf, ptrbuf + length_b, 0);
5,972✔
197
          } else {
198
            std::copy(ittmp, ittmp + slength_b, ptrbuf);
21,852✔
199
          }
200
        }
201

202
        if (ittmp != tmp_orbcoeff.begin() +
5,612✔
203
                           static_cast<ptrdiff_t>(end_hf * hf.n_bas() + block_b.first)) {
5,612✔
204
          throw runtime_error("Internal error: ittmp index issue in orbcoeff_generator");
×
205
        }
206
        if (ptrbuf != buffer + (end_ss - block_ss.first) * length_b) {
5,612✔
207
          throw runtime_error("Internal error: ptrbuf index issue in orbcoeff_generator");
×
208
        }
209
      }
210
    };
5,604✔
211

212
    //
213
    // Import alpha coefficients, i.e. the vector (a)
214
    //                                            (0)
215
    //
216
    std::shared_ptr<Symmetry> sym_a_ptr =
217
          make_symmetry_orbital_coefficients(mo_ptr, ss + "b", hf.n_bas(), "a");
3,484✔
218
    std::shared_ptr<Tensor> orbcoeff_a = make_tensor_zero(sym_a_ptr);
1,742✔
219
    orbcoeff_a->import_from(
3,484✔
220
          [&orbcoeff_generator_ab](const std::vector<std::pair<size_t, size_t>>& block,
2,802✔
221
                                   scalar_type* buffer) {
2,802✔
222
            orbcoeff_generator_ab(block, buffer, /*alpha*/ true, /*beta*/ false);
2,802✔
223
          },
2,802✔
224
          hf.conv_tol(), symmetry_check_on_import);
1,742✔
225
    orbcoeff_a->set_immutable();
1,742✔
226
    m_orbcoeff_alpha[ss + "b"] = orbcoeff_a;
1,742✔
227

228
    //
229
    // Import beta coefficients, i.e. the vector (0)
230
    //                                           (b)
231
    //
232
    std::shared_ptr<Symmetry> sym_b_ptr =
233
          make_symmetry_orbital_coefficients(mo_ptr, ss + "b", hf.n_bas(), "b");
3,484✔
234
    std::shared_ptr<Tensor> orbcoeff_b = make_tensor_zero(sym_b_ptr);
1,742✔
235
    orbcoeff_b->import_from(
3,484✔
236
          [&orbcoeff_generator_ab](const std::vector<std::pair<size_t, size_t>>& block,
2,802✔
237
                                   scalar_type* buffer) {
2,802✔
238
            orbcoeff_generator_ab(block, buffer, /*alpha*/ false, /*beta*/ true);
2,802✔
239
          },
2,802✔
240
          hf.conv_tol(), symmetry_check_on_import);
1,742✔
241
    orbcoeff_b->set_immutable();
1,742✔
242
    m_orbcoeff_beta[ss + "b"] = orbcoeff_b;
1,742✔
243

244
    //
245
    // Build full coefficients (a 0)
246
    //                         (0 b)
247
    //
248
    // Export orbcoeff_a and orbcoeff_b for the full coefficient import
249
    // (The rationale is that these already have the right MO ordering along the MO axis,
250
    //  which makes the code for the full coefficient import a lot more readable)
251
    std::vector<scalar_type> exp_orbcoeff_a;
1,742✔
252
    orbcoeff_a->export_to(exp_orbcoeff_a);
1,742✔
253
    std::vector<scalar_type> exp_orbcoeff_b;
1,742✔
254
    orbcoeff_b->export_to(exp_orbcoeff_b);
1,742✔
255
    if (exp_orbcoeff_a.size() != exp_orbcoeff_b.size()) {
1,742✔
256
      throw runtime_error(
×
257
            "Internal error: exp_orbcoeff_a.size() and exp_orbcoeff_b.size() do not "
258
            "agree.");
×
259
    }
260

261
    auto orbcoeff_generator = [&exp_orbcoeff_a, &exp_orbcoeff_b, &hf](
3,974✔
262
                                    const std::vector<std::pair<size_t, size_t>>& block,
263
                                    scalar_type* buffer) {
71,560✔
264
      const std::pair<size_t, size_t>& block_ss = block[0];
3,974✔
265
      const std::pair<size_t, size_t>& block_b  = block[1];
3,974✔
266

267
      // Length of the axis:
268
      const size_t length_b       = block_b.second - block_b.first;
3,974✔
269
      const size_t length_ss_full = block_ss.second - block_ss.first;
3,974✔
270

271
      // Spin data for axis b
272
      const std::vector<std::pair<size_t, size_t>> b_spin_ranges{
273
            {0, hf.n_bas()}, {hf.n_bas(), 2 * hf.n_bas()}};
3,974✔
274
      const std::vector<scalar_type*> b_spin_data{exp_orbcoeff_a.data(),
3,974✔
275
                                                  exp_orbcoeff_b.data()};
3,974✔
276

277
      // Loop over spins (alpha == 0 and beta == 1)
278
      for (size_t ispin = 0; ispin < 2; ++ispin) {
11,922✔
279
        size_t from_b_first  = block_b.first;
7,948✔
280
        size_t from_b_length = length_b;
7,948✔
281

282
        if (block_b.first >= b_spin_ranges[ispin].second) {
7,948✔
283
          // Beyond the range covered by this spin
284
          continue;
1,172✔
285
        }
286
        if (block_b.second - 1 < b_spin_ranges[ispin].first) {
6,776✔
287
          // Before the range covered by this spin
288
          continue;
2,802✔
289
        }
290

291
        // Get the first index in the b axis to be used and the length
292
        // for the spin chunk covered in this loop iteration
293
        from_b_first  = std::max(block_b.first, b_spin_ranges[ispin].first);
3,974✔
294
        from_b_length = std::min(hf.n_bas(), block_b.second - from_b_first);
3,974✔
295

296
        // from_b_first has still spin information (i.e. indexed in the range
297
        // [0,2*n_bas], but exp_orbcoeff_a and exp_orbcoeff_b containeres
298
        // only covers the spatial range [0, n_bas], so we reduce it to
299
        // the spatial index only
300
        const size_t from_b_first_spatial = from_b_first % hf.n_bas();
3,974✔
301

302
        // Prepare input and output pointers and copy the data.
303
        scalar_type* from   = b_spin_data[ispin];
3,974✔
304
        scalar_type* ptrbuf = buffer + (from_b_first - block_b.first) * length_ss_full;
3,974✔
305
        size_t offset       = hf.n_bas() * block_ss.first + from_b_first_spatial;
3,974✔
306
        for (size_t iss = 0; iss < length_ss_full;
23,858✔
307
             ++iss, ptrbuf += length_b, offset += hf.n_bas()) {
19,884✔
308
          if (offset + from_b_length > exp_orbcoeff_a.size()) {
19,884✔
309
            throw runtime_error("Read buffer overflow.");
×
310
          }
311
          if (ptrbuf + from_b_length > buffer + length_b * length_ss_full) {
19,884✔
312
            throw runtime_error("Write buffer overflow.");
×
313
          }
314
          if (ptrbuf < buffer) {
19,884✔
315
            throw runtime_error("Write buffer underflow.");
×
316
          }
317
          std::copy(from + offset, from + offset + from_b_length, ptrbuf);
19,884✔
318
        }
319
      }
320
    };
3,974✔
321
    std::shared_ptr<Symmetry> sym_ab_ptr =
322
          make_symmetry_orbital_coefficients(mo_ptr, ss + "b", hf.n_bas(), "ab");
3,484✔
323
    std::shared_ptr<Tensor> orbcoeff_ab = make_tensor_zero(sym_ab_ptr);
1,742✔
324
    orbcoeff_ab->import_from(orbcoeff_generator, hf.conv_tol(), symmetry_check_on_import);
1,742✔
325
    orbcoeff_ab->set_immutable();
1,742✔
326
    m_orbcoeff[ss + "b"] = orbcoeff_ab;
1,742✔
327
  }
1,742✔
328
}
632✔
329

330
//
331
// Info about the reference state
332
//
333
size_t ReferenceState::spin_multiplicity() const {
98✔
334
  if (!restricted()) {
98✔
335
    return 0;
48✔
336
  } else {
337
    return m_hfsoln_ptr->spin_multiplicity();
50✔
338
  }
339
}
340

341
std::string ReferenceState::irreducible_representation() const {
98✔
342
  if (m_mo_ptr->point_group == "C1") return "A";
98✔
343

344
  // Notice: This is not true, since the occupation might be uneven
345
  // between spatial parts
346
  // if (n_alpha() == n_beta()) return m_mo_ptr->irrep_totsym();
347

348
  // For non-closed-shell we would need to see whatever orbitals are occupied
349
  // and determine from this the resulting overall irrep
350
  throw not_implemented_error("Only C1 is implemented.");
×
351
}
352

353
std::vector<scalar_type> ReferenceState::nuclear_multipole(size_t order) const {
466✔
354
  std::vector<scalar_type> ret((order + 2) * (order + 1) / 2);
466✔
355
  m_hfsoln_ptr->nuclear_multipole(order, ret.data(), ret.size());
466✔
356
  return ret;
466✔
357
}
×
358

359
//
360
// Tensor data
361
//
362
std::shared_ptr<Tensor> ReferenceState::orbital_energies(const std::string& space) const {
326✔
363
  const auto itfound = m_orben.find(space);
326✔
364
  if (itfound == m_orben.end()) {
326✔
365
    throw invalid_argument(
×
366
          "Invalid space string " + space + ": An object orbital_energies(" + space +
×
367
          ") is not known. Check that the string has exactly 2 characters "
368
          "and describes a valid orbital subspace.");
×
369
  }
370
  return itfound->second;
652✔
371
}
372

373
std::shared_ptr<Tensor> ReferenceState::orbital_coefficients(
66,634✔
374
      const std::string& space) const {
375
  const auto itfound = m_orbcoeff.find(space);
66,634✔
376
  if (itfound == m_orbcoeff.end()) {
66,634✔
377
    throw invalid_argument(
×
378
          "Invalid space string " + space + ": An object orbital_coefficients(" + space +
×
379
          ") is not known. Check that the string has exactly 3 characters "
380
          "and describes two valid orbital subspace.");
×
381
  }
382
  return itfound->second;
133,268✔
383
}
384

385
std::shared_ptr<Tensor> ReferenceState::orbital_coefficients_alpha(
1,864✔
386
      const std::string& space) const {
387
  const auto itfound = m_orbcoeff_alpha.find(space);
1,864✔
388
  if (itfound == m_orbcoeff_alpha.end()) {
1,864✔
389
    throw invalid_argument(
×
390
          "Invalid space string " + space + ": An object orbital_coefficients_alpha(" +
×
391
          space +
×
392
          ") is not known. Check that the string has exactly 3 characters "
393
          "and describes two valid orbital subspace.");
×
394
  }
395
  return itfound->second;
3,728✔
396
}
397

398
std::shared_ptr<Tensor> ReferenceState::orbital_coefficients_beta(
1,864✔
399
      const std::string& space) const {
400
  const auto itfound = m_orbcoeff_beta.find(space);
1,864✔
401
  if (itfound == m_orbcoeff_beta.end()) {
1,864✔
402
    throw invalid_argument(
×
403
          "Invalid space string " + space + ": An object orbital_coefficients_beta(" +
×
404
          space +
×
405
          ") is not known. Check that the string has exactly 3 characters "
406
          "and describes two valid orbital subspace.");
×
407
  }
408
  return itfound->second;
3,728✔
409
}
410

411
std::shared_ptr<Tensor> ReferenceState::fock(const std::string& space) const {
51,440✔
412
  const auto itfound = m_fock.find(space);
51,440✔
413
  if (itfound != m_fock.end()) return itfound->second;
51,440✔
414

415
  std::unique_ptr<MoIndexTranslation> trans_ptr;
2,010✔
416
  try {
417
    trans_ptr.reset(new MoIndexTranslation(m_mo_ptr, space));
2,010✔
418
  } catch (const invalid_argument& inv) {
×
419
    throw invalid_argument("Invalid fock space string: " + std::string(inv.what()));
×
420
  }
×
421
  MoIndexTranslation& idxtrans = *trans_ptr;
2,010✔
422
  if (idxtrans.ndim() != 2) {
2,010✔
423
    throw invalid_argument("Invalid fock space string" + space +
×
424
                           ": Needs to consist of exactly 2 spaces.");
×
425
  }
426

427
  {
428
    RecordTime rec(m_timer, "import/fock/" + space);
2,010✔
429
    // Fock operator is symmetric wrt. index permutation and transforms
430
    // as the totally symmetric irrep
431
    const bool symmetric = true;
2,010✔
432
    std::shared_ptr<Symmetry> sym_ptr =
433
          make_symmetry_operator(m_mo_ptr, space, symmetric, "1");
4,020✔
434
    std::shared_ptr<Tensor> fock    = make_tensor_zero(sym_ptr);
2,010✔
435
    const HartreeFockSolution_i& hf = *m_hfsoln_ptr;
2,010✔
436

437
    auto fock_generator = [&idxtrans, &hf](
3,888✔
438
                                const std::vector<std::pair<size_t, size_t>>& block,
439
                                scalar_type* buffer) {
7,792✔
440
      // Strides, which should be used to write data to buffer
441
      // and size of the buffer.
442
      const std::vector<size_t> blength{block[0].second - block[0].first,
3,888✔
443
                                        block[1].second - block[1].first};
3,888✔
444
      const std::vector<size_t> strides{blength[1], 1};
3,888✔
445
      const size_t buffer_size = strides[0] * blength[0];
3,888✔
446

447
      std::vector<RangeMapping> mappings = idxtrans.map_range_to_hf_provider(block);
7,776✔
448
      for (RangeMapping& map : mappings) {
7,792✔
449
        const SimpleRange& bidx  = map.from();  // Indices of the MO subspace block
3,904✔
450
        const SimpleRange& hfidx = map.to();    // Indices translated to HF provider
3,904✔
451

452
        // Compute offset and remaining buffer size
453
        size_t offset = 0;
3,904✔
454
        for (size_t i = 0; i < 2; ++i) {
11,712✔
455
          offset += (bidx.axis(i).start() - block[i].first) * strides[i];
7,808✔
456
        }
457
        const size_t size = buffer_size - offset;
3,904✔
458
        hf.fock_ff(hfidx.axis(0).start(), hfidx.axis(0).end(),  //
3,904✔
459
                   hfidx.axis(1).start(), hfidx.axis(1).end(),  //
7,808✔
460
                   strides[0], strides[1], buffer + offset, size);
3,904✔
461
      }
462
    };
3,888✔
463
    fock->import_from(fock_generator, hf.conv_tol(), m_symmetry_check_on_import);
2,010✔
464
    fock->set_immutable();
2,010✔
465

466
    m_fock[space] = fock;
2,010✔
467
    return fock;
2,010✔
468
  }
2,010✔
469
}
2,010✔
470

471
std::shared_ptr<Tensor> ReferenceState::eri(const std::string& space) const {
135,785✔
472
  const auto itfound = m_eri.find(space);
135,785✔
473
  if (itfound != m_eri.end()) return itfound->second;
135,785✔
474

475
  std::unique_ptr<MoIndexTranslation> trans_ptr;
3,728✔
476
  try {
477
    trans_ptr.reset(new MoIndexTranslation(m_mo_ptr, space));
3,728✔
478
  } catch (const invalid_argument& inv) {
×
479
    throw invalid_argument("Invalid ERI space string: " + std::string(inv.what()));
×
480
  }
×
481
  if (trans_ptr->ndim() != 4) {
3,728✔
482
    throw invalid_argument("Invalid ERI space string" + space +
×
483
                           ": Needs to consist of exactly 4 spaces.");
×
484
  }
485

486
  // Branch off to three different ways to import the tensor, depending on the
487
  // capabilities of the HartreFockSolution_i and the block to be imported.
488
  RecordTime rec(m_timer, "import/eri/" + space);
3,728✔
489
  const std::vector<std::string>& ss = trans_ptr->subspaces();
3,728✔
490
  if (m_hfsoln_ptr->has_eri_phys_asym_ffff()) {
3,728✔
491
    m_eri[space] =
×
492
          import_eri_asym_direct(*m_hfsoln_ptr, *trans_ptr, m_symmetry_check_on_import);
×
493
  } else if (ss[2] == ss[3] || ss[0] == ss[1]) {
3,728✔
494
    m_eri[space] = import_eri_chem_then_asym_fast(*m_hfsoln_ptr, *trans_ptr,
5,204✔
495
                                                  m_symmetry_check_on_import);
5,204✔
496
  } else {
497
    m_eri[space] = import_eri_chem_then_asym(*m_hfsoln_ptr, *trans_ptr,
2,252✔
498
                                             m_symmetry_check_on_import);
2,252✔
499
  }
500
  m_eri[space]->set_immutable();
3,728✔
501
  return m_eri[space];
3,728✔
502
}
3,728✔
503

504
void ReferenceState::import_all() const {
22✔
505
  auto& ss = m_mo_ptr->subspaces;
22✔
506
  std::vector<std::string> ss_pairs;
22✔
507
  for (auto it1 = ss.begin(); it1 != ss.end(); ++it1) {
76✔
508
    for (auto it2 = it1; it2 != ss.end(); ++it2) {
150✔
509
      ss_pairs.push_back(*it1 + *it2);
96✔
510
      fock(*it1 + *it2);
96✔
511
    }
512
  }
513

514
  for (auto it1 = ss_pairs.begin(); it1 != ss_pairs.end(); ++it1) {
118✔
515
    for (auto it2 = it1; it2 != ss_pairs.end(); ++it2) {
378✔
516
      eri(*it1 + *it2);
282✔
517
    }
518
  }
519

520
  flush_hf_cache();
22✔
521
}
22✔
522

523
std::vector<std::string> ReferenceState::cached_fock_blocks() const {
×
524
  std::vector<std::string> ret;
×
525
  for (auto& kv : m_fock) ret.push_back(kv.first);
×
526
  return ret;
×
527
}
×
528

529
std::vector<std::string> ReferenceState::cached_eri_blocks() const {
×
530
  std::vector<std::string> ret;
×
531
  for (auto& kv : m_eri) ret.push_back(kv.first);
×
532
  return ret;
×
533
}
×
534

535
void ReferenceState::set_cached_fock_blocks(std::vector<std::string> newlist) {
×
536
  for (auto& item : newlist) fock(item);
×
537
  flush_hf_cache();
×
538

539
  std::sort(newlist.begin(), newlist.end());
×
540
  auto it = m_fock.begin();
×
541
  while (it != m_fock.end()) {
×
542
    if (std::binary_search(newlist.begin(), newlist.end(), it->first)) {
×
543
      ++it;
×
544
    } else {
545
      it = m_fock.erase(it);
×
546
    }
547
  }
548
}
×
549

550
void ReferenceState::set_cached_eri_blocks(std::vector<std::string> newlist) {
×
551
  for (auto& item : newlist) eri(item);
×
552
  flush_hf_cache();
×
553

554
  std::sort(newlist.begin(), newlist.end());
×
555
  auto it = m_eri.begin();
×
556
  while (it != m_eri.end()) {
×
557
    if (std::binary_search(newlist.begin(), newlist.end(), it->first)) {
×
558
      ++it;
×
559
    } else {
560
      it = m_eri.erase(it);
×
561
    }
562
  }
563
}
×
564

565
}  // namespace libadcc
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc