29 #ifndef _chemistry_qc_scf_assignments_h
30 #define _chemistry_qc_scf_assignments_h
36 #include <boost/shared_ptr.hpp>
37 #include <boost/make_shared.hpp>
38 #include <boost/enable_shared_from_this.hpp>
42 #include <boost/heap/fibonacci_heap.hpp>
44 #include <util/misc/formio.h>
49 namespace sc {
namespace cadf {
52 template<
typename T,
template<
typename...>
class compare=std::less>
55 template<
typename T,
template <
typename...>
class compare>
58 bool operator()(T*
const& a, T*
const& b)
const {
59 return compare<T>()(*a, *b);
65 template<
typename T,
template <
typename...>
class compare>
68 bool operator()(boost::shared_ptr<T>
const& a, boost::shared_ptr<T>
const& b)
const {
69 return compare<T>()(*a, *b);
78 bool operator()(
const T& a,
const T& b)
const {
79 return a.coef_workload > b.coef_workload;
85 bool operator()(
const T& a,
const T& b)
const {
86 return a.index < b.index;
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>,
101 template<
typename...>
class container,
103 template<
typename...>
class compare=std::less
104 >
using ordered_ptr_container =
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;
138 assert(iblk.nbf == iblk.atom_nbf);
139 nshell = iblk.nshell;
141 dfnshell = iblk.atom_dfnsh;
142 dfnbf = iblk.atom_dfnbf;
143 coefs_size = iblk.nbf * iblk.basis->nbasis() * iblk.atom_dfnbf;
163 coefs_size = ish.nbf * ish.basis->
nbasis() * ish.atom_dfnbf;
178 const boost::shared_ptr<Node> node;
183 const boost::shared_ptr<Node> node
184 ) : ish(ish), Xatom(Xblk.center), node(node)
187 cost_estimate_ = ish.nbf * Xblk.nbf;
190 uli cost_estimate()
const {
191 return cost_estimate_;
197 namespace assignments {
struct AtomCluster; };
199 class Node :
public boost::enable_shared_from_this<Node> {
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;
221 obs_shells_to_do.insert(ish);
222 dfbs_atoms_to_do.insert(Xblk.center);
225 pairs.emplace_back(pair);
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;
235 bool should_do_obs_shell(uli shell_index)
const {
236 return obs_shells_to_do.find(shell_index) != obs_shells_to_do.end();
239 bool should_do_dfbs_atom(uli atom_index)
const {
240 return dfbs_atoms_to_do.find(atom_index) != dfbs_atoms_to_do.end();
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);
250 const std::set<uint>& assigned_dfbs_shells()
const;
253 assigned_dfbs_atoms()
const;
257 bool operator <(
const Node&
other)
const {
258 return estimated_workload >
other.estimated_workload;
261 const std::unordered_map<uint, uli>&
262 dfbs_coef_offsets()
const;
269 class AssignmentBin :
public boost::enable_shared_from_this<AssignmentBin> {
273 ptr_priority_queue<boost::shared_ptr<Node>> nodes;
274 std::vector<boost::shared_ptr<Node>> nodes_list;
276 std::set<uint> assigned_dfbs_shells;
278 std::array<std::vector<boost::shared_ptr<AssignableItem>>, 2> compute_coef_items;
279 uli estimated_workload = 0;
280 uli coef_workload = 0;
290 std::unordered_map<uint, uli> obs_coef_offsets;
292 std::unordered_map<uint, uli> dfbs_coef_offsets;
300 boost::shared_ptr<cadf::Node> add_node(
int index);
304 inline void assign_dfbs_atom(
const boost::shared_ptr<AssignableItem>& dfbs_atom);
306 inline void assign_obs_shell(
const boost::shared_ptr<AssignableItem>& obs_shell);
308 inline void make_assignments();
310 void compute_coef_for_item(
const boost::shared_ptr<AssignableItem>& item,
bool is_df);
312 size_t n_node()
const {
return nodes.size(); }
314 uint dfnsh()
const {
return assigned_dfbs_shells.size(); }
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;
322 static constexpr
bool debug_ =
false;
328 uli estimated_workload = 0;
329 std::vector<boost::shared_ptr<AssignableItem>> assigned_items;
334 : id(
id), is_df_row(is_df)
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);
342 void add_bin(boost::shared_ptr<AssignmentBin>
const& bin) {
343 auto handle = bins.push(bin);
344 (*handle)->row_handles[is_df_row] = handle;
347 void make_assignments();
351 return estimated_workload >
other.estimated_workload;
354 typename priority_queue<AssignmentBinRow>::handle_type pq_handle;
363 std::vector<boost::shared_ptr<AssignableAtom>> atoms_;
364 std::vector<boost::shared_ptr<AssignableShell>> obs_shells_;
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_;
376 bool bins_have_multiple_nodes =
false;
386 return *(nodes_[me]->bin);
389 const Node& my_assignments(
int me)
const {
390 return *(nodes_[me]);
393 const boost::shared_ptr<Node> my_assignments_ptr(
int me)
const {
405 void print_detail(std::ostream& o=
ExEnv::out0(),
bool full_memory=
false)
const;
410 namespace assignments {
414 struct AtomCluster : boost::enable_shared_from_this<AtomCluster> {
416 std::vector<boost::shared_ptr<Node>> nodes;
421 std::set<uint> assigned_dfbs_shells;
422 std::unordered_map<uint, uint> dfbs_shell_map;
423 std::unordered_map<uint, uli> coef_offsets;
425 void assign_atom(
const boost::shared_ptr<AssignableAtom>& atom);
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();
432 node.cluster = shared_from_this();
436 uli workload_per_node() {
return nodes.size() > 0 ? coefs_size / nodes.size() : std::numeric_limits<uli>::max(); }
438 void make_assignments();
440 bool has_local_coefs_for_atom(uint atom_index) {
441 return coef_offsets.find(atom_index) != coef_offsets.end();
448 std::vector<boost::shared_ptr<AtomCluster>> clusters;
449 std::vector<boost::shared_ptr<Node>> nodes;
457 int min_atoms_per_cluster,
461 void print_detail(std::ostream& o)
const;