MPQC  3.0.0-alpha
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 
49 namespace sc { namespace cadf {
50 
51 namespace detail {
52  template<typename T, template<typename...> class compare=std::less>
53  struct deref_compare;
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 
92 template<typename T, typename... Args> using priority_queue =
93  boost::heap::fibonacci_heap<T, boost::heap::stable<true>, Args...>;
94 template<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  >;
100 template<
101  template<typename...> class container,
102  typename T,
103  template<typename...> class compare=std::less
104 > using ordered_ptr_container =
105  container<
107  >;
108 template<typename T, template<typename...> class compare=std::less> using ptr_set =
109  ordered_ptr_container<std::set, T, compare>;
110 typedef uint64_t uli;
111 typedef unsigned int uint;
112 
113 class 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 
135  AssignableAtom(const ShellBlockData<>& iblk)
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 
196 class AssignmentBin;
197 namespace assignments { struct AtomCluster; };
198 
199 class 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 
266 class AssignmentGrid;
267 class AssignmentBinRow;
268 
269 class 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 
410 namespace assignments {
411 
412 struct Assignments;
413 
414 struct 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 
447 struct Assignments {
448  std::vector<boost::shared_ptr<AtomCluster>> clusters;
449  std::vector<boost::shared_ptr<Node>> nodes;
450 
451  GaussianBasisSet* basis;
452  GaussianBasisSet* dfbasis;
453 
454  Assignments(
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 */
sc::cadf::AssignableItem::cost_estimate
virtual uli cost_estimate(bool df) const =0
Cost estimate for atom's portion of the coefficient tensor.
sc::cadf::AssignableShellPair
Definition: assignments.h:171
sc::cadf::AssignableAtom::cost_estimate
uli cost_estimate(bool df) const
Cost estimate for atom's portion of the coefficient tensor.
Definition: assignments.h:146
sc::cadf::AssignmentBinRow
Definition: assignments.h:325
sc::cadf::detail::index_less
Definition: assignments.h:84
sc::ShellData
Definition: iters.h:135
sc::cadf::detail::deref_compare
Definition: assignments.h:53
sc::cadf::detail::more_work
Definition: assignments.h:77
sc::ShellBlockData
Definition: iters.h:638
sc::cadf::AssignmentGrid
Definition: assignments.h:357
sc::GaussianBasisSet::nbasis
unsigned int nbasis() const
Return the number of basis functions.
Definition: gaussbas.h:514
sc::cadf::Node
Definition: assignments.h:199
sc::cadf::AssignableAtom
Definition: assignments.h:125
sc::cadf::AssignableShell::cost_estimate
uli cost_estimate(bool df) const
Cost estimate for atom's portion of the coefficient tensor.
Definition: assignments.h:166
sc::cadf::AssignableItem
Definition: assignments.h:115
sc::cadf::AssignmentBin
Definition: assignments.h:269
sc::other
SpinCase1 other(SpinCase1 S)
given 1-spin return the other 1-spin
sc::cadf::AssignableShell
Definition: assignments.h:151
sc::GaussianBasisSet
The GaussianBasisSet class is used describe a basis set composed of atomic gaussian orbitals.
Definition: gaussbas.h:141
sc::ExEnv::out0
static std::ostream & out0()
Return an ostream that writes from node 0.
sc::cadf::assignments::AtomCluster
Definition: assignments.h:414
sc
Contains all MPQC code up to version 3.
Definition: mpqcin.h:14
sc::cadf::assignments::Assignments
Definition: assignments.h:447

Generated at Sun Jan 26 2020 23:23:59 for MPQC 3.0.0-alpha using the documentation package Doxygen 1.8.16.