MPQC 3.0.0-alpha
Loading...
Searching...
No Matches
assignments.h
1//
2// assignments.h
3//
4// Copyright (C) 2014 David Hollman
5//
6// Author: David Hollman
7// Maintainer: DSH
8// Created: Apr 15, 2014
9//
10// This file is part of the SC Toolkit.
11//
12// The SC Toolkit is free software; you can redistribute it and/or modify
13// it under the terms of the GNU Library General Public License as published by
14// the Free Software Foundation; either version 2, or (at your option)
15// any later version.
16//
17// The SC Toolkit is distributed in the hope that it will be useful,
18// but WITHOUT ANY WARRANTY; without even the implied warranty of
19// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20// GNU Library General Public License for more details.
21//
22// You should have received a copy of the GNU Library General Public License
23// along with the SC Toolkit; see the file COPYING.LIB. If not, write to
24// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
25//
26// The U.S. Government is granted a limited license as per AL 91-7.
27//
28
29#ifndef _chemistry_qc_scf_assignments_h
30#define _chemistry_qc_scf_assignments_h
31
32#include <array>
33#include <set>
34#include <utility>
35
36#include <boost/shared_ptr.hpp>
37#include <boost/make_shared.hpp>
38#include <boost/enable_shared_from_this.hpp>
39//#include <boost/container/set.hpp>
40
41
42#include <boost/heap/fibonacci_heap.hpp>
43
44#include <util/misc/formio.h>
45
46#include "iters.h"
47
48
49namespace sc { namespace cadf {
50
51namespace detail {
52 template<typename T, template<typename...> class compare=std::less>
54
55 template<typename T, template <typename...> class compare>
56 struct deref_compare<T*, compare>
57 {
58 bool operator()(T* const& a, T* const& b) const {
59 return compare<T>()(*a, *b);
60 }
61 private:
62 //compare<T> cmp_;
63 };
64
65 template<typename T, template <typename...> class compare>
66 struct deref_compare<boost::shared_ptr<T>, compare>
67 {
68 bool operator()(boost::shared_ptr<T> const& a, boost::shared_ptr<T> const& b) const {
69 return compare<T>()(*a, *b);
70 }
71 private:
72 //compare<T> cmp_;
73 };
74
75
76 template<typename T>
77 struct more_work {
78 bool operator()(const T& a, const T& b) const {
79 return a.coef_workload > b.coef_workload;
80 }
81 };
82
83 template<typename T>
84 struct index_less {
85 bool operator()(const T& a, const T& b) const {
86 return a.index < b.index;
87 }
88 };
89
90}
91
92template<typename T, typename... Args> using priority_queue =
93 boost::heap::fibonacci_heap<T, boost::heap::stable<true>, Args...>;
94template<typename T, template<typename...> class compare=std::less> using ptr_priority_queue =
95 boost::heap::fibonacci_heap<T, boost::heap::stable<true>,
96 boost::heap::compare<
98 >
99 >;
100template<
101 template<typename...> class container,
102 typename T,
103 template<typename...> class compare=std::less
104> using ordered_ptr_container =
105 container<
107 >;
108template<typename T, template<typename...> class compare=std::less> using ptr_set =
109 ordered_ptr_container<std::set, T, compare>;
110typedef uint64_t uli;
111typedef unsigned int uint;
112
113class Node;
114
116 public:
117 int index;
118 uli coefs_size;
119 AssignableItem(int index) : index(index), coefs_size(0) { }
120 virtual ~AssignableItem() { }
122 virtual uli cost_estimate(bool df) const = 0;
123};
124
126 public:
127 int nshell;
128 int nbf;
129 int dfnshell;
130 int dfnbf;
131
132 // Note: coefs_size is the size of coefs
133 // C_{\nu_c \sigma}^{X_c} for atom c (in number of doubles)
134
136 : AssignableItem(iblk.center)
137 {
138 assert(iblk.nbf == iblk.atom_nbf);
139 nshell = iblk.nshell;
140 nbf = iblk.nbf;
141 dfnshell = iblk.atom_dfnsh;
142 dfnbf = iblk.atom_dfnbf;
143 coefs_size = iblk.nbf * iblk.basis->nbasis() * iblk.atom_dfnbf;
144 }
145
146 uli cost_estimate(bool df) const {
147 return coefs_size;
148 }
149};
150
152 public:
153
154 int nbf;
155
156 // Note: coefs_size is the size of coefs
157 // C_{\mu_a \sigma}^{X_a} for shell \mu_a (in number of doubles)
158
159 AssignableShell(const ShellData& ish)
160 : AssignableItem(ish.index)
161 {
162 nbf = ish.nbf;
163 coefs_size = ish.nbf * ish.basis->nbasis() * ish.atom_dfnbf;
164 }
165
166 uli cost_estimate(bool df) const {
167 return coefs_size;
168 }
169};
170
172
173 uli cost_estimate_;
174
175 public:
176 int ish;
177 int Xatom;
178 const boost::shared_ptr<Node> node;
179
181 const ShellData& ish,
182 const ShellBlockData<>& Xblk,
183 const boost::shared_ptr<Node> node
184 ) : ish(ish), Xatom(Xblk.center), node(node)
185 {
186 // TODO more efficient cost estimation options
187 cost_estimate_ = ish.nbf * Xblk.nbf;
188 }
189
190 uli cost_estimate() const {
191 return cost_estimate_;
192 }
193};
194
195
196class AssignmentBin;
197namespace assignments { struct AtomCluster; };
198
199class Node : public boost::enable_shared_from_this<Node> {
200 public:
201
202 union { int node_index; int id; };
203 std::vector<AssignableShellPair> pairs;
204 std::set<uli> obs_shells_to_do;
205 std::set<uli> dfbs_atoms_to_do;
206 std::array<std::vector<boost::shared_ptr<AssignableItem>>, 2> compute_coef_items;
207 boost::shared_ptr<AssignmentBin> bin;
208 boost::shared_ptr<assignments::AtomCluster> cluster;
209 typename ptr_priority_queue<boost::shared_ptr<Node>>::handle_type pq_handle;
210 uli estimated_workload = 0;
211 uli shell_pair_count = 0;
212 uli basis_pair_count = 0;
213
214 bool is_me = false;
215
216 uli assign_pair(
217 const ShellData& ish,
218 const ShellBlockData<>& Xblk
219 )
220 {
221 obs_shells_to_do.insert(ish);
222 dfbs_atoms_to_do.insert(Xblk.center);
223 AssignableShellPair pair(ish, Xblk, shared_from_this());
224 if(is_me) {
225 pairs.emplace_back(pair);
226 }
227 // compute the cost
228 const uli cost = pair.cost_estimate();
229 estimated_workload += cost;
230 shell_pair_count += Xblk.nshell;
231 basis_pair_count += Xblk.nbf * ish.nbf;
232 return cost;
233 }
234
235 bool should_do_obs_shell(uli shell_index) const {
236 return obs_shells_to_do.find(shell_index) != obs_shells_to_do.end();
237 }
238
239 bool should_do_dfbs_atom(uli atom_index) const {
240 return dfbs_atoms_to_do.find(atom_index) != dfbs_atoms_to_do.end();
241 }
242
243 void assign_coef_item(boost::shared_ptr<AssignableItem> const& item, bool is_df) {
244 compute_coef_items[is_df].push_back(item);
245 estimated_workload += item->cost_estimate(is_df);
246 }
247
248 uli dfnsh() const;
249
250 const std::set<uint>& assigned_dfbs_shells() const;
251
252 const ptr_set<boost::shared_ptr<AssignableAtom>, detail::index_less>&
253 assigned_dfbs_atoms() const;
254
255
256
257 bool operator <(const Node& other) const {
258 return estimated_workload > other.estimated_workload;
259 }
260
261 const std::unordered_map<uint, uli>&
262 dfbs_coef_offsets() const;
263
264};
265
266class AssignmentGrid;
267class AssignmentBinRow;
268
269class AssignmentBin : public boost::enable_shared_from_this<AssignmentBin> {
270
271
272 public:
273 ptr_priority_queue<boost::shared_ptr<Node>> nodes;
274 std::vector<boost::shared_ptr<Node>> nodes_list;
275 ptr_set<boost::shared_ptr<AssignableAtom>, detail::index_less> assigned_dfbs_atoms;
276 std::set<uint> assigned_dfbs_shells;
277 ptr_set<boost::shared_ptr<AssignableItem>, detail::index_less> assigned_obs_shells;
278 std::array<std::vector<boost::shared_ptr<AssignableItem>>, 2> compute_coef_items;
279 uli estimated_workload = 0;
280 uli coef_workload = 0;
281 uint id;
282 uint obs_row_id;
283 uint dfbs_row_id;
284
285 // Size of coefs C_{\mu_a \rho}^{X_a} for a in assigned obs_atoms
286 uli obs_ncoefs = 0;
287 // Size of coefs C_{\nu_c \sigma}^{X_c} for c in assigned dfbs_atoms
288 uli dfbs_ncoefs = 0;
289 // offsets of the start of C_{\mu_a \rho}^{X_a} in the obs coefficient memory (in number of doubles) for given a
290 std::unordered_map<uint, uli> obs_coef_offsets;
291 // offsets of the start of C_{\nu_c \rho}^{X_c} in the dfbs coefficient memory (in number of doubles) for given c
292 std::unordered_map<uint, uli> dfbs_coef_offsets;
293
294 AssignmentGrid* grid;
295
297 uint id, AssignmentGrid* grid
298 );
299
300 boost::shared_ptr<cadf::Node> add_node(int index);
301
302 inline void register_in_row(const AssignmentBinRow& row, bool is_df);
303
304 inline void assign_dfbs_atom(const boost::shared_ptr<AssignableItem>& dfbs_atom);
305
306 inline void assign_obs_shell(const boost::shared_ptr<AssignableItem>& obs_shell);
307
308 inline void make_assignments();
309
310 void compute_coef_for_item(const boost::shared_ptr<AssignableItem>& item, bool is_df);
311
312 size_t n_node() const { return nodes.size(); }
313
314 uint dfnsh() const { return assigned_dfbs_shells.size(); }
315
316 bool operator<(const AssignmentBin& other) const;
317
318 typename ptr_priority_queue<boost::shared_ptr<AssignmentBin>>::handle_type pq_handle;
319 std::array<typename ptr_priority_queue<boost::shared_ptr<AssignmentBin>, detail::more_work>::handle_type, 2> row_handles;
320
321 private:
322 static constexpr bool debug_ = false;
323};
324
326 public:
327 bool is_df_row;
328 uli estimated_workload = 0;
329 std::vector<boost::shared_ptr<AssignableItem>> assigned_items;
330 ptr_priority_queue<boost::shared_ptr<AssignmentBin>, detail::more_work> bins;
331 uint id;
332
333 AssignmentBinRow(uint id, bool is_df)
334 : id(id), is_df_row(is_df)
335 { }
336
337 void assign_item(const boost::shared_ptr<AssignableItem>& item) {
338 assigned_items.push_back(item);
339 estimated_workload += item->cost_estimate(is_df_row);
340 }
341
342 void add_bin(boost::shared_ptr<AssignmentBin> const& bin) {
343 auto handle = bins.push(bin);
344 (*handle)->row_handles[is_df_row] = handle;
345 }
346
347 void make_assignments();
348
349 bool operator <(const AssignmentBinRow& other) const {
350 // We want to assign work to the row with the lowest estimated workload
351 return estimated_workload > other.estimated_workload;
352 }
353
354 typename priority_queue<AssignmentBinRow>::handle_type pq_handle;
355};
356
358
359 GaussianBasisSet* basis_;
360 GaussianBasisSet* dfbasis_;
361
362 // TODO Fix this. We can't store pointers to these things in other places, since they may be moved
363 std::vector<boost::shared_ptr<AssignableAtom>> atoms_;
364 std::vector<boost::shared_ptr<AssignableShell>> obs_shells_;
365
366 ptr_priority_queue<boost::shared_ptr<AssignmentBin>> bins_;
367 priority_queue<AssignmentBinRow> obs_rows_;
368 priority_queue<AssignmentBinRow> dfbs_rows_;
369 std::vector<boost::shared_ptr<Node>> nodes_;
370
371 public:
372
373 int nrows_dfbs;
374 int nrows_obs;
375 int nbin;
376 bool bins_have_multiple_nodes = false;
377
378
380 GaussianBasisSet* basis,
381 GaussianBasisSet* dfbasis,
382 int n_node, int me
383 );
384
385 const AssignmentBin& my_bin(int me) const {
386 return *(nodes_[me]->bin);
387 }
388
389 const Node& my_assignments(int me) const {
390 return *(nodes_[me]);
391 }
392
393 const boost::shared_ptr<Node> my_assignments_ptr(int me) const {
394 return nodes_[me];
395 }
396
397 GaussianBasisSet* basis() {
398 return basis_;
399 }
400
401 GaussianBasisSet* dfbasis() {
402 return dfbasis_;
403 }
404
405 void print_detail(std::ostream& o=ExEnv::out0(), bool full_memory=false) const;
406
407};
408
409
410namespace assignments {
411
412struct Assignments;
413
414struct AtomCluster : boost::enable_shared_from_this<AtomCluster> {
415 ptr_set<boost::shared_ptr<AssignableAtom>, detail::index_less> atoms;
416 std::vector<boost::shared_ptr<Node>> nodes;
417 Assignments* parent;
418 uli coefs_size = 0;
419 int index;
420 uli dfnsh = 0;
421 std::set<uint> assigned_dfbs_shells;
422 std::unordered_map<uint, uint> dfbs_shell_map;
423 std::unordered_map<uint, uli> coef_offsets;
424
425 void assign_atom(const boost::shared_ptr<AssignableAtom>& atom);
426
427 boost::shared_ptr<Node> use_node(int inode, bool is_me) {
428 nodes.emplace_back(boost::make_shared<Node>());
429 auto& node = *nodes.back();
430 node.id = inode;
431 node.is_me = is_me;
432 node.cluster = shared_from_this();
433 return nodes.back();
434 }
435
436 uli workload_per_node() { return nodes.size() > 0 ? coefs_size / nodes.size() : std::numeric_limits<uli>::max(); }
437
438 void make_assignments();
439
440 bool has_local_coefs_for_atom(uint atom_index) {
441 return coef_offsets.find(atom_index) != coef_offsets.end();
442 }
443
444};
445
446
448 std::vector<boost::shared_ptr<AtomCluster>> clusters;
449 std::vector<boost::shared_ptr<Node>> nodes;
450
451 GaussianBasisSet* basis;
452 GaussianBasisSet* dfbasis;
453
455 GaussianBasisSet* basis,
456 GaussianBasisSet* dfbasis,
457 int min_atoms_per_cluster,
458 int n_node, int me
459 );
460
461 void print_detail(std::ostream& o) const;
462
463
464};
465
466}
467
468}} // end namespaces cadf and sc
469
470
471
472#endif /* _chemistry_qc_scf_assignments_h */
static std::ostream & out0()
Return an ostream that writes from node 0.
The GaussianBasisSet class is used describe a basis set composed of atomic gaussian orbitals.
Definition gaussbas.h:145
unsigned int nbasis() const
Return the number of basis functions.
Definition gaussbas.h:514
Definition iters.h:638
Definition assignments.h:125
uli cost_estimate(bool df) const
Cost estimate for atom's portion of the coefficient tensor.
Definition assignments.h:146
Definition assignments.h:115
virtual uli cost_estimate(bool df) const =0
Cost estimate for atom's portion of the coefficient tensor.
Definition assignments.h:171
Definition assignments.h:151
uli cost_estimate(bool df) const
Cost estimate for atom's portion of the coefficient tensor.
Definition assignments.h:166
Definition assignments.h:325
Definition assignments.h:269
Definition assignments.h:357
Definition assignments.h:199
SpinCase1 other(SpinCase1 S)
given 1-spin return the other 1-spin
Contains all MPQC code up to version 3.
Definition mpqcin.h:14
Definition iters.h:135
Definition assignments.h:447
Definition assignments.h:414
Definition assignments.h:53
Definition assignments.h:84
Definition assignments.h:77

Generated at Wed Sep 25 2024 02:45:30 for MPQC 3.0.0-alpha using the documentation package Doxygen 1.12.0.