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

adc-connect / adcc / 13945654759

19 Mar 2025 11:40AM UTC coverage: 73.602% (-0.3%) from 73.946%
13945654759

Pull #169

github

web-flow
Merge 905afe0b9 into f5662a8a2
Pull Request #169: Additional operator integrals and selection of gauge origin

1167 of 1876 branches covered (62.21%)

Branch coverage included in aggregate %.

185 of 288 new or added lines in 12 files covered. (64.24%)

2 existing lines in 2 files now uncovered.

7267 of 9583 relevant lines covered (75.83%)

282621.94 hits per line

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

79.17
/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,
567✔
29
                               std::shared_ptr<const MoSpaces> mo_ptr,
30
                               bool symmetry_check_on_import)
567✔
31
      : m_n_alpha{0},
567✔
32
        m_n_beta{0},
567✔
33
        m_orben{},
567✔
34
        m_orbcoeff{},
567✔
35
        m_orbcoeff_alpha{},
567✔
36
        m_orbcoeff_beta{},
567✔
37
        m_fock{},
567✔
38
        m_eri{},
567✔
39
        m_hfsoln_ptr{hfsoln_ptr},
567✔
40
        m_mo_ptr{mo_ptr},
567✔
41
        m_symmetry_check_on_import{symmetry_check_on_import},
567✔
42
        m_timer{} {
567✔
43
  for (auto& ss : mo_ptr->subspaces_occupied) {
1,422✔
44
    m_n_alpha += mo_ptr->n_orbs_alpha(ss);
855✔
45
    m_n_beta += mo_ptr->n_orbs_beta(ss);
855✔
46
  }
47

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

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

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

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

75
      std::vector<RangeMapping> mappings = idxtrans.map_range_to_hf_provider(block);
2,262✔
76
      for (const RangeMapping& map : mappings) {
4,530✔
77
        // orben is 1D -> idim == 0 always
78
        const size_t idim = 0;
2,268✔
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,268✔
82

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

87
        if (start + (end_hf - start_hf) > length_ss_full) {
2,268✔
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,268✔
92
                  tmp_orben.begin() + static_cast<ptrdiff_t>(end_hf), buffer + start);
4,536✔
93
      }
94
    };
2,262✔
95
    orben->import_from(orben_generator, hf.conv_tol(), symmetry_check_on_import);
1,554✔
96
    orben->set_immutable();
1,554✔
97
    m_orben[ss] = orben;
1,554✔
98
  }
1,554✔
99
}
567✔
100

101
void ReferenceState::import_orbital_coefficients(
567✔
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");
567✔
105
  m_orbcoeff.clear();
567✔
106
  m_orbcoeff_alpha.clear();
567✔
107
  m_orbcoeff_beta.clear();
567✔
108

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

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

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

127
      std::vector<RangeMapping> mappings_ss =
128
            idxtrans.map_range_to_hf_provider({{block_ss}});
12,132✔
129
      for (const RangeMapping& map_ss : mappings_ss) {
12,144✔
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
6,078✔
132
        const size_t start_ss  = map_ss.from().axis(idim).start();
6,078✔
133
        const size_t end_ss    = map_ss.from().axis(idim).end();
6,078✔
134
        const size_t length_ss = end_ss - start_ss;
6,078✔
135

136
        const size_t start_hf = map_ss.to().axis(idim).start();
6,078✔
137
        const size_t end_hf   = map_ss.to().axis(idim).end();
6,078✔
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() +
12,156✔
143
                     static_cast<ptrdiff_t>(start_hf * hf.n_bas() + block_b.first);
6,078✔
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 =
6,078✔
150
              buffer + static_cast<ptrdiff_t>((start_ss - block_ss.first) * length_b);
6,078✔
151

152
        if (alpha && beta) {
6,078✔
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;
6,078✔
159
        if (idxtrans.spin_of({start_ss}) == "b") {
18,234✔
160
          if (idxtrans.spin_of({end_ss - 1}) != "b") {
9,135✔
161
            throw runtime_error(
162
                  "Internal error: Assertion about blocks being split whenever spin "
163
                  "changes is violated.");
×
164
          }
165
          if (!beta) {
3,045✔
166
            // beta block should be zero
167
            fill_zeros = true;
789✔
168
          }
169
        }
170
        if (idxtrans.spin_of({end_ss - 1}) == "a") {
18,234✔
171
          if (idxtrans.spin_of({start_ss}) != "a") {
9,099✔
172
            throw runtime_error(
173
                  "Internal error: Assertion about blocks being split whenever spin "
174
                  "changes is violated.");
×
175
          }
176
          if (!alpha) {
3,033✔
177
            // beta block should be zero
178
            fill_zeros = true;
783✔
179
          }
180
        }
181

182
        const ptrdiff_t slength_b = static_cast<ptrdiff_t>(length_b);
6,078✔
183
        const ptrdiff_t sn_bas    = static_cast<ptrdiff_t>(hf.n_bas());
6,078✔
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;
40,332✔
190
             ++irow, ptrbuf += length_b, ittmp += sn_bas) {
34,254✔
191
          if (ptrbuf + slength_b > buffer + length_ss_full * length_b) {
34,254✔
192
            throw runtime_error(
193
                  "Internal error: Out-of-bounds write in orbcoeff_generator");
×
194
          }
195
          if (fill_zeros) {
34,254✔
196
            std::fill(ptrbuf, ptrbuf + length_b, 0);
8,028✔
197
          } else {
198
            std::copy(ittmp, ittmp + slength_b, ptrbuf);
26,226✔
199
          }
200
        }
201

202
        if (ittmp != tmp_orbcoeff.begin() +
6,078✔
203
                           static_cast<ptrdiff_t>(end_hf * hf.n_bas() + block_b.first)) {
6,078✔
204
          throw runtime_error("Internal error: ittmp index issue in orbcoeff_generator");
×
205
        }
206
        if (ptrbuf != buffer + (end_ss - block_ss.first) * length_b) {
6,078✔
207
          throw runtime_error("Internal error: ptrbuf index issue in orbcoeff_generator");
×
208
        }
209
      }
210
    };
7,620✔
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");
1,554✔
218
    std::shared_ptr<Tensor> orbcoeff_a = make_tensor_zero(sym_a_ptr);
1,554✔
219
    orbcoeff_a->import_from(
3,108✔
220
          [&orbcoeff_generator_ab](const std::vector<std::pair<size_t, size_t>>& block,
1,554✔
221
                                   scalar_type* buffer) {
222
            orbcoeff_generator_ab(block, buffer, /*alpha*/ true, /*beta*/ false);
3,033✔
223
          },
3,033✔
224
          hf.conv_tol(), symmetry_check_on_import);
1,554✔
225
    orbcoeff_a->set_immutable();
1,554✔
226
    m_orbcoeff_alpha[ss + "b"] = orbcoeff_a;
1,554✔
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");
1,554✔
234
    std::shared_ptr<Tensor> orbcoeff_b = make_tensor_zero(sym_b_ptr);
1,554✔
235
    orbcoeff_b->import_from(
3,108✔
236
          [&orbcoeff_generator_ab](const std::vector<std::pair<size_t, size_t>>& block,
1,554✔
237
                                   scalar_type* buffer) {
238
            orbcoeff_generator_ab(block, buffer, /*alpha*/ false, /*beta*/ true);
3,033✔
239
          },
3,033✔
240
          hf.conv_tol(), symmetry_check_on_import);
1,554✔
241
    orbcoeff_b->set_immutable();
1,554✔
242
    m_orbcoeff_beta[ss + "b"] = orbcoeff_b;
1,554✔
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,554✔
252
    orbcoeff_a->export_to(exp_orbcoeff_a);
1,554✔
253
    std::vector<scalar_type> exp_orbcoeff_b;
1,554✔
254
    orbcoeff_b->export_to(exp_orbcoeff_b);
1,554✔
255
    if (exp_orbcoeff_a.size() != exp_orbcoeff_b.size()) {
1,554✔
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](
4,599✔
262
                                    const std::vector<std::pair<size_t, size_t>>& block,
263
                                    scalar_type* buffer) {
264
      const std::pair<size_t, size_t>& block_ss = block[0];
4,599✔
265
      const std::pair<size_t, size_t>& block_b  = block[1];
4,599✔
266

267
      // Length of the axis:
268
      const size_t length_b       = block_b.second - block_b.first;
4,599✔
269
      const size_t length_ss_full = block_ss.second - block_ss.first;
4,599✔
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()}};
9,198✔
274
      const std::vector<scalar_type*> b_spin_data{exp_orbcoeff_a.data(),
4,599✔
275
                                                  exp_orbcoeff_b.data()};
9,198✔
276

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

282
        if (block_b.first >= b_spin_ranges[ispin].second) {
9,198✔
283
          // Beyond the range covered by this spin
284
          continue;
1,566✔
285
        }
286
        if (block_b.second - 1 < b_spin_ranges[ispin].first) {
7,632✔
287
          // Before the range covered by this spin
288
          continue;
3,033✔
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);
4,599✔
294
        from_b_length = std::min(hf.n_bas(), block_b.second - from_b_first);
4,599✔
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();
4,599✔
301

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

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

341
std::string ReferenceState::irreducible_representation() const {
195✔
342
  if (m_mo_ptr->point_group == "C1") return "A";
585✔
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(
708✔
354
      size_t order, std::array<scalar_type, 3> gauge_origin) const {
355
  std::vector<scalar_type> ret((order + 2) * (order + 1) / 2);
708✔
356
  m_hfsoln_ptr->nuclear_multipole(order, gauge_origin, ret.data(), ret.size());
708✔
357
  return ret;
708✔
NEW
358
}
×
359

360
const std::array<scalar_type, 3> ReferenceState::gauge_origin_to_xyz(
162✔
361
      std::string gauge_origin) const {
362
  const std::array<scalar_type, 3> ret = m_hfsoln_ptr->gauge_origin_to_xyz(gauge_origin);
162✔
363
  return ret;
162✔
364
}
365

366
//
367
// Tensor data
368
//
369
std::shared_ptr<Tensor> ReferenceState::orbital_energies(const std::string& space) const {
681✔
370
  const auto itfound = m_orben.find(space);
681✔
371
  if (itfound == m_orben.end()) {
681✔
372
    throw invalid_argument(
373
          "Invalid space string " + space + ": An object orbital_energies(" + space +
×
374
          ") is not known. Check that the string has exactly 2 characters "
375
          "and describes a valid orbital subspace.");
×
376
  }
377
  return itfound->second;
1,362✔
378
}
379

380
std::shared_ptr<Tensor> ReferenceState::orbital_coefficients(
190,815✔
381
      const std::string& space) const {
382
  const auto itfound = m_orbcoeff.find(space);
190,815✔
383
  if (itfound == m_orbcoeff.end()) {
190,815✔
384
    throw invalid_argument(
385
          "Invalid space string " + space + ": An object orbital_coefficients(" + space +
×
386
          ") is not known. Check that the string has exactly 3 characters "
387
          "and describes two valid orbital subspace.");
×
388
  }
389
  return itfound->second;
381,630✔
390
}
391

392
std::shared_ptr<Tensor> ReferenceState::orbital_coefficients_alpha(
3,138✔
393
      const std::string& space) const {
394
  const auto itfound = m_orbcoeff_alpha.find(space);
3,138✔
395
  if (itfound == m_orbcoeff_alpha.end()) {
3,138✔
396
    throw invalid_argument(
397
          "Invalid space string " + space + ": An object orbital_coefficients_alpha(" +
×
398
          space +
×
399
          ") is not known. Check that the string has exactly 3 characters "
400
          "and describes two valid orbital subspace.");
×
401
  }
402
  return itfound->second;
6,276✔
403
}
404

405
std::shared_ptr<Tensor> ReferenceState::orbital_coefficients_beta(
3,138✔
406
      const std::string& space) const {
407
  const auto itfound = m_orbcoeff_beta.find(space);
3,138✔
408
  if (itfound == m_orbcoeff_beta.end()) {
3,138✔
409
    throw invalid_argument(
410
          "Invalid space string " + space + ": An object orbital_coefficients_beta(" +
×
411
          space +
×
412
          ") is not known. Check that the string has exactly 3 characters "
413
          "and describes two valid orbital subspace.");
×
414
  }
415
  return itfound->second;
6,276✔
416
}
417

418
std::shared_ptr<Tensor> ReferenceState::fock(const std::string& space) const {
101,561✔
419
  const auto itfound = m_fock.find(space);
101,561✔
420
  if (itfound != m_fock.end()) return itfound->second;
101,561✔
421

422
  std::unique_ptr<MoIndexTranslation> trans_ptr;
2,736✔
423
  try {
424
    trans_ptr.reset(new MoIndexTranslation(m_mo_ptr, space));
2,736✔
425
  } catch (const invalid_argument& inv) {
×
426
    throw invalid_argument("Invalid fock space string: " + std::string(inv.what()));
×
427
  }
×
428
  MoIndexTranslation& idxtrans = *trans_ptr;
2,736✔
429
  if (idxtrans.ndim() != 2) {
2,736✔
430
    throw invalid_argument("Invalid fock space string" + space +
×
431
                           ": Needs to consist of exactly 2 spaces.");
×
432
  }
433

434
  {
435
    RecordTime rec(m_timer, "import/fock/" + space);
2,736✔
436
    // Fock operator is symmetric wrt. index permutation and transforms
437
    // as the totally symmetric irrep
438
    const bool symmetric = true;
2,736✔
439
    std::shared_ptr<Symmetry> sym_ptr =
440
          make_symmetry_operator(m_mo_ptr, space, symmetric, "1");
2,736✔
441
    std::shared_ptr<Tensor> fock    = make_tensor_zero(sym_ptr);
2,736✔
442
    const HartreeFockSolution_i& hf = *m_hfsoln_ptr;
2,736✔
443

444
    auto fock_generator = [&idxtrans, &hf](
6,153✔
445
                                const std::vector<std::pair<size_t, size_t>>& block,
446
                                scalar_type* buffer) {
447
      // Strides, which should be used to write data to buffer
448
      // and size of the buffer.
449
      const std::vector<size_t> blength{block[0].second - block[0].first,
6,153✔
450
                                        block[1].second - block[1].first};
12,306✔
451
      const std::vector<size_t> strides{blength[1], 1};
12,306✔
452
      const size_t buffer_size = strides[0] * blength[0];
6,153✔
453

454
      std::vector<RangeMapping> mappings = idxtrans.map_range_to_hf_provider(block);
6,153✔
455
      for (RangeMapping& map : mappings) {
12,330✔
456
        const SimpleRange& bidx  = map.from();  // Indices of the MO subspace block
6,177✔
457
        const SimpleRange& hfidx = map.to();    // Indices translated to HF provider
6,177✔
458

459
        // Compute offset and remaining buffer size
460
        size_t offset = 0;
6,177✔
461
        for (size_t i = 0; i < 2; ++i) {
18,531✔
462
          offset += (bidx.axis(i).start() - block[i].first) * strides[i];
12,354✔
463
        }
464
        const size_t size = buffer_size - offset;
6,177✔
465
        hf.fock_ff(hfidx.axis(0).start(), hfidx.axis(0).end(),  //
6,177✔
466
                   hfidx.axis(1).start(), hfidx.axis(1).end(),  //
12,354✔
467
                   strides[0], strides[1], buffer + offset, size);
6,177✔
468
      }
469
    };
6,153✔
470
    fock->import_from(fock_generator, hf.conv_tol(), m_symmetry_check_on_import);
2,736✔
471
    fock->set_immutable();
2,736✔
472

473
    m_fock[space] = fock;
2,736✔
474
    return fock;
2,736✔
475
  }
2,736✔
476
}
2,736✔
477

478
std::shared_ptr<Tensor> ReferenceState::eri(const std::string& space) const {
250,952✔
479
  const auto itfound = m_eri.find(space);
250,952✔
480
  if (itfound != m_eri.end()) return itfound->second;
250,952✔
481

482
  std::unique_ptr<MoIndexTranslation> trans_ptr;
7,416✔
483
  try {
484
    trans_ptr.reset(new MoIndexTranslation(m_mo_ptr, space));
7,416✔
485
  } catch (const invalid_argument& inv) {
×
486
    throw invalid_argument("Invalid ERI space string: " + std::string(inv.what()));
×
487
  }
×
488
  if (trans_ptr->ndim() != 4) {
7,416✔
489
    throw invalid_argument("Invalid ERI space string" + space +
×
490
                           ": Needs to consist of exactly 4 spaces.");
×
491
  }
492

493
  // Branch off to three different ways to import the tensor, depending on the
494
  // capabilities of the HartreFockSolution_i and the block to be imported.
495
  RecordTime rec(m_timer, "import/eri/" + space);
7,416✔
496
  const std::vector<std::string>& ss = trans_ptr->subspaces();
7,416✔
497
  if (m_hfsoln_ptr->has_eri_phys_asym_ffff()) {
7,416✔
498
    m_eri[space] =
×
499
          import_eri_asym_direct(*m_hfsoln_ptr, *trans_ptr, m_symmetry_check_on_import);
×
500
  } else if (ss[2] == ss[3] || ss[0] == ss[1]) {
7,416✔
501
    m_eri[space] = import_eri_chem_then_asym_fast(*m_hfsoln_ptr, *trans_ptr,
9,258✔
502
                                                  m_symmetry_check_on_import);
9,258✔
503
  } else {
504
    m_eri[space] = import_eri_chem_then_asym(*m_hfsoln_ptr, *trans_ptr,
5,574✔
505
                                             m_symmetry_check_on_import);
5,574✔
506
  }
507
  m_eri[space]->set_immutable();
7,416✔
508
  return m_eri[space];
7,416✔
509
}
7,416✔
510

511
void ReferenceState::import_all() const {
84✔
512
  auto& ss = m_mo_ptr->subspaces;
84✔
513
  std::vector<std::string> ss_pairs;
84✔
514
  for (auto it1 = ss.begin(); it1 != ss.end(); ++it1) {
372✔
515
    for (auto it2 = it1; it2 != ss.end(); ++it2) {
957✔
516
      ss_pairs.push_back(*it1 + *it2);
669✔
517
      fock(*it1 + *it2);
669✔
518
    }
519
  }
520

521
  for (auto it1 = ss_pairs.begin(); it1 != ss_pairs.end(); ++it1) {
753✔
522
    for (auto it2 = it1; it2 != ss_pairs.end(); ++it2) {
4,164✔
523
      eri(*it1 + *it2);
3,495✔
524
    }
525
  }
526

527
  flush_hf_cache();
84✔
528
}
84✔
529

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

536
std::vector<std::string> ReferenceState::cached_eri_blocks() const {
×
537
  std::vector<std::string> ret;
×
538
  for (auto& kv : m_eri) ret.push_back(kv.first);
×
539
  return ret;
×
540
}
×
541

542
void ReferenceState::set_cached_fock_blocks(std::vector<std::string> newlist) {
×
543
  for (auto& item : newlist) fock(item);
×
544
  flush_hf_cache();
×
545

546
  std::sort(newlist.begin(), newlist.end());
×
547
  auto it = m_fock.begin();
×
548
  while (it != m_fock.end()) {
×
549
    if (std::binary_search(newlist.begin(), newlist.end(), it->first)) {
×
550
      ++it;
×
551
    } else {
552
      it = m_fock.erase(it);
×
553
    }
554
  }
555
}
×
556

557
void ReferenceState::set_cached_eri_blocks(std::vector<std::string> newlist) {
×
558
  for (auto& item : newlist) eri(item);
×
559
  flush_hf_cache();
×
560

561
  std::sort(newlist.begin(), newlist.end());
×
562
  auto it = m_eri.begin();
×
563
  while (it != m_eri.end()) {
×
564
    if (std::binary_search(newlist.begin(), newlist.end(), it->first)) {
×
565
      ++it;
×
566
    } else {
567
      it = m_eri.erase(it);
×
568
    }
569
  }
570
}
×
571

572
}  // 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

© 2025 Coveralls, Inc