1 // An interscale operator class for sharing definitions of atomic quantities, e.g., temperature
2 // between different parts of the code
3 
4 #ifndef INTERSCALE_MANAGER_H
5 #define INTERSCALE_MANAGER_H
6 
7 #include "MatrixLibrary.h"
8 #include "ATC_TypeDefs.h"
9 #include "ATC_Error.h"
10 #include "LammpsInterface.h"
11 #include "PerAtomQuantity.h"
12 #include "PerPairQuantity.h"
13 #include "FundamentalAtomicQuantity.h"
14 #include <vector>
15 #include <map>
16 #include <set>
17 #include <string>
18 #include <utility>
19 
20 namespace ATC {
21 
22   // forward declarations
23   class ATC_Method;
24   class SmallMoleculeSet;
25 
26   /**
27    *  @class  InterscaleManager
28    *  @brief  Handles definitions for atomistic quantities
29    */
30 
31   //--------------------------------------------------------
32   //--------------------------------------------------------
33   //  Class InterscaleManager
34   //--------------------------------------------------------
35   //--------------------------------------------------------
36 
37   class InterscaleManager {
38 
39   public:
40 
41     // constructor
42     InterscaleManager(ATC_Method * atc);
43 
44     // destructor
45     ~InterscaleManager();
46 
47     /** delete all allocated data */
48     void clear();
49 
50     /** delete non-persistent data */
51     void clear_temporary_data();
52 
53     /** set lammps data prefix */
54     void set_lammps_data_prefix();
55 
56     /** parser/modifier */
57     bool modify(int narg, char **arg);
58 
59     /** pre time integration */
60     void initialize();
61 
62     // access to per atom quantity objects
63     /** access to fundamental atomic quantities */
64     FundamentalAtomQuantity * fundamental_atom_quantity(LammpsInterface::FundamentalAtomQuantity id,
65                                                         AtomType atomType = INTERNAL);
66     /** access to double per atom quantities */
67     PerAtomQuantity<double> * per_atom_quantity(const std::string & tag);
68     /** access to integer per atom quantities */
69     PerAtomQuantity<int> * per_atom_int_quantity(const std::string & tag);
70     /** access to double per atom diagonal matrices */
71     PerAtomDiagonalMatrix<double> * per_atom_diagonal_matrix(const std::string & tag);
72     /** access to double per atom sparse matrices */
73     PerAtomSparseMatrix<double> * per_atom_sparse_matrix(const std::string & tag);
74     /** access to pair maps */
75     PairMap * pair_map(const std::string & tag);
76 
77     // addition of new atom quantities, note provider must allocate but the manager will clean-up
78     /** addition of a double atomic quantity */
79     void add_per_atom_quantity(PerAtomQuantity<double> * atomQuantity,
80                                const std::string & tag);
81     /** addition of an integer atomic quantity */
82     void add_per_atom_int_quantity(PerAtomQuantity<int> * atomQuantity,
83                                    const std::string & tag);
84     /** addition of a double atomic diagonal matrix */
85     void add_per_atom_diagonal_matrix(PerAtomDiagonalMatrix<double> * atomQuantity,
86                                       const std::string & tag);
87     /** addition of a double atomic sparse matrix */
88     void add_per_atom_sparse_matrix(PerAtomSparseMatrix<double> * atomQuantity,
89                                     const std::string & tag);
90     /** addition of an pair map */
91     void add_pair_map(PairMap * pairMap, const std::string & tag);
92 
93     /** access to dense matrices */
94     DENS_MAN * dense_matrix(const std::string & tag);
95 
96     /** addition of dense matrices */
97     void add_dense_matrix(DENS_MAN * denseMatrix,
98                           const std::string & tag);
99 
100     /** access integer dense matrices */
101     MatrixDependencyManager<DenseMatrix, int> * dense_matrix_int(const std::string & tag);
102 
103     /** addition of integer dense matrices */
104     void add_dense_matrix_int(MatrixDependencyManager<DenseMatrix, int> * denseMatrix,
105                                const std::string & tag);
106 
107     /** access boolean dense matrices */
108     MatrixDependencyManager<DenseMatrix, bool> * dense_matrix_bool(const std::string & tag);
109 
110     /** addition of boolean dense matrices */
111     void add_dense_matrix_bool(MatrixDependencyManager<DenseMatrix, bool> * denseMatrix,
112                                const std::string & tag);
113 
114     /** access to sparse matrices */
115     SPAR_MAN * sparse_matrix(const std::string & tag);
116 
117     /** addition of a sparse matrix */
118     void add_sparse_matrix(SPAR_MAN * sparseMatrix,
119                            const std::string & tag);
120 
121     /** access to diagonal matrices */
122     DIAG_MAN * diagonal_matrix(const std::string & tag);
123 
124     /** addition of a diagonal matrix */
125     void add_diagonal_matrix(DIAG_MAN * diagonalMatrix,
126                              const std::string & tag);
127 
128     /** access to vectors of sparse matrices */
129     VectorDependencyManager<SPAR_MAT * > * vector_sparse_matrix(const std::string & tag);
130 
131     /** addition of a vector of sparse matrices */
132     void add_vector_sparse_matrix(VectorDependencyManager<SPAR_MAT * > * sparseMatrix,
133                                   const std::string & tag);
134 
135     /** access to sets of ints */
136     SetDependencyManager<int> * set_int(const std::string & tag);
137 
138     /** addition of a set of ints */
139     void add_set_int(SetDependencyManager<int> * sparseMatrix,
140                      const std::string & tag);
141 
142     /** access to molecule sets */
143     SmallMoleculeSet * small_molecule_set(const std::string & tag);
144 
145     /** addition of a transfer operator */
146     void add_small_molecule_set(SmallMoleculeSet * moleculeSet,
147                                 const std::string & tag);
148 
149     /** addition of exchange list object */
150     void add_to_exchange_list(const std::string & tag);
151 
152     /** searches through all lists to see if a tag is registered */
153     DependencyManager * find(const std::string & tag);
154 
155     /** schedules a quantity for deletion, if it exists */
156     void remove(const std::string & tag);
157 
158     /** size communicated quantities initially */
159     void size_comm_quantities();
160 
161     /** resets nlocal count of managed atomic quantities which do not perform parallel exchange */
162     void reset_nlocal();
163 
164     /** resets specific lammps fundamental quantities data, as needed, to account for times when lammps can change quantities */
165     void fundamental_force_reset(unsigned quantity);
166 
167     /** resets all lammps data, as needed, to account for times when lammps can change quantities */
168     void lammps_force_reset();
169 
170     /** syncs lammps data to managed objects for parallel communication */
171     void prepare_exchange();
172 
173     /** syncs managed objects to lammps data after parallel communication */
174     void post_exchange();
175 
176     /** returns how much lammps memory is used in this function */
177     int memory_usage() const;
178 
179     /** packs up data for parallel transfer, called from pack_exchange */
180     int pack_exchange(int i, double *buffer);
181 
182     /** unpacks data after parallel transfer, called from unpack_exchange */
183     int unpack_exchange(int i, double *buffer);
184 
185     /** packs up data for parallel transfer to ghost atoms on other processors */
186     int pack_comm(int index, double *buf,
187                   int pbc_flag, int *pbc);
188 
189     /** unpacks data after parallel transfer to ghost atoms on other processors */
190     int unpack_comm(int index, double *buf);
191 
192     /** changes size of temperary lammps storage data if transfer is being used */
193     void grow_arrays(int nmax);
194 
195     /** rearrange memory of temporary lammps storage data, called from copy_array */
196     void copy_arrays(int i, int j);
197 
198   protected:
199 
200     /** pointer to access ATC methods */
201     ATC_Method * atc_;
202 
203     /** flag for if first initialization has happened */
204     bool initialized_;
205 
206     /** containers for fundamental atom quantities, set on request */
207     std::vector<std::vector<FundamentalAtomQuantity* > > fundamentalAtomQuantities_;
208 
209     /** container for per-atom quantities using dense matrices of doubles */
210     std::map<std::string, PerAtomQuantity<double> * > perAtomQuantities_;
211 
212     /** container for integer atom quantities, set by AtC classes */
213     std::map<std::string, PerAtomQuantity<int> * > perAtomIntQuantities_;
214 
215     /** container for per-atom quantities using diagonal matrices of doubles */
216     std::map<std::string, PerAtomDiagonalMatrix<double> * > perAtomDiagonalMatrices_;
217 
218     /** container for per-atom quantities using sparse matrices of doubles */
219     std::map<std::string, PerAtomSparseMatrix<double> * > perAtomSparseMatrices_;
220 
221     /** container for pair maps */
222     std::map<std::string, PairMap * > pairMaps_;
223 
224     /** container for dense matrices */
225     std::map<std::string, DENS_MAN * > denseMatrices_;
226 
227     /** container for dense matrices for integer quantities */
228     std::map<std::string, MatrixDependencyManager<DenseMatrix, int> * > denseMatricesInt_;
229 
230     /** container for dense matrces for boolean quantities */
231     std::map<std::string, MatrixDependencyManager<DenseMatrix, bool> * > denseMatricesBool_;
232 
233     /** container for sparse matrices */
234     std::map<std::string, SPAR_MAN * > sparseMatrices_;
235 
236     /** container for diagonal matrices */
237     std::map<std::string, DIAG_MAN * > diagonalMatrices_;
238 
239     /** container for vectors of vectors of sparse matrices */
240     std::map<std::string, VectorDependencyManager<SPAR_MAT * > * > vectorSparMat_;
241 
242     /** container for sets of integer quantities */
243     std::map<std::string, SetDependencyManager<int> * > setInt_;
244 
245     /** container for molecule sets */
246     std::map<std::string, SmallMoleculeSet * > smallMoleculeSets_;
247 
248     /** container for atomic quantities which must be transfered when atoms cross processors */
249     std::set<PerAtomQuantity<double> *> exchangeList_;
250 
251     /** container for atomic quantities which must be transfered to ghost atoms on other processors */
252     std::vector<PerAtomQuantity<double> *> commList_;
253 
254     /** container for integer atomic quantities which must be transfered to ghost atoms on other processors */
255     std::vector<PerAtomQuantity<int> *> commIntList_;
256 
257     /** container for atomic diagonal matrices which must be transfered to ghost atoms on other processors */
258     std::vector<PerAtomDiagonalMatrix<double> *> commDmList_;
259 
260     /** container for atomic sparse matrices which must be transfered to ghost atoms on other processors */
261     std::vector<PerAtomSparseMatrix<double> *> commSmList_;
262 
263     /** prefix for labeling associated lammps arrays */
264     std::string prefix_;
265 
266     /** order of deletion list of managed quantities */
267     std::vector<DependencyManager * > deletionList_;
268 
269     /** creates a reverse sorted depth-first search list for deleting managed quantities */
270     void create_deletion_list();
271 
272     /** executes a depth-first search visit on a managed quantity */
273     int dfs_visit(DependencyManager * quantity, const int index);
274 
275     /** helper function to access a data entry in a list */
276     template <typename data>
return_quantity(std::map<std::string,data * > & list,const std::string & tag)277     data * return_quantity(std::map<std::string,data * > & list, const std::string & tag)
278     {
279       typename std::map<std::string,data * >::iterator it = list.find(tag);
280       if (it==list.end()) return NULL;
281       return it->second;
282     };
283 
284     /** helper function to add a data entry to a list */
285     template <typename data>
add_quantity(std::map<std::string,data * > & list,data * quantity,const std::string & tag)286     void add_quantity(std::map<std::string,data * > & list, data * quantity, const std::string & tag)
287     {
288       typename std::map<std::string,data * >::iterator it = list.find(tag);
289       if (it!=list.end())
290         throw ATC_Error("Tried to add another Quantity with tag "+tag+" in InterscaleManager::add_quantity");
291       typename std::template pair<std::string,data * > myPair(tag,quantity);
292       list.insert(myPair);
293     };
294 
295     /** helper function to add a data entry to a list when it requires neighbor communication*/
296     template <typename data>
add_comm_quantity(std::map<std::string,data * > & list,std::vector<data * > & commList,data * quantity,const std::string & tag)297     void add_comm_quantity(std::map<std::string,data * > & list, std::vector<data * > & commList, data * quantity, const std::string & tag)
298     {
299       add_quantity(list,quantity,tag);
300       // allocate data for parallel communication
301       quantity->grow_lammps_array(LammpsInterface::instance()->nmax(),prefix_+tag);
302       if (quantity->atom_type() == PROC_GHOST) {
303         commList.push_back(quantity);
304       }
305     };
306 
307      /** helper function to fina a data entry in a list */
308     template <typename data>
find_in_list(std::map<std::string,data * > & list,const std::string & tag)309     data * find_in_list(std::map<std::string,data * > & list, const std::string & tag)
310     {
311       typename std::map<std::string,data * >::iterator it = list.find(tag);
312       if (it!=list.end()) return it->second;
313       return NULL;
314     };
315 
316     /** helper function to force the reset of all data in a list */
317     template <typename data>
force_reset_loop(std::map<std::string,data * > & list)318     void force_reset_loop(std::map<std::string,data * > & list)
319     {
320       for (typename std::map<std::string,data* >::iterator it = list.begin(); it != list.end(); ++it)
321         (it->second)->force_reset();
322     };
323 
324     /** helper function to set the memory type to temporary of a list */
325     template <typename data>
set_memory_temporary(std::map<std::string,data * > & list)326     void set_memory_temporary(std::map<std::string,data * > & list)
327     {
328       for (typename std::map<std::string,data* >::iterator it = list.begin(); it != list.end(); ++it)
329         (it->second)->set_memory_type(TEMPORARY);
330     };
331 
332     /** helper function to perform intialization for dfs of a list */
333     template <typename data>
dfs_prepare_loop(std::map<std::string,data * > & list)334     void dfs_prepare_loop(std::map<std::string,data * > & list)
335     {
336       for (typename std::map<std::string,data* >::iterator it = list.begin(); it != list.end(); ++it) {
337         (it->second)->dfsFound_ = false;
338       }
339     };
340 
341     /** helper function to start the dfs visit for list */
342     template <typename data>
dfs_visit_loop(std::map<std::string,data * > & list,int & index)343     void dfs_visit_loop(std::map<std::string,data * > & list,
344                         int & index)
345     {
346       typename std::map<std::string,data* >::iterator it = list.begin();
347       while (it != list.end()) {
348         if  (!((it->second)->dfsFound_)) index = dfs_visit(it->second,index);
349         if ((it->second)->memory_type()==TEMPORARY) list.erase(it++);
350         else ++it;
351       }
352     };
353 
354     // PAQ helper functions
355     /** helper function to adjust local atom count for all data in a list before exchange, only valid with quantities that do that are aware of atom counts */
356     template <typename data>
reset_nlocal_loop(std::map<std::string,data * > & list)357     void reset_nlocal_loop(std::map<std::string,data * > & list)
358     {
359       for (typename std::map<std::string,data* >::iterator it = list.begin(); it != list.end(); ++it) {
360         (it->second)->reset_nlocal();
361       }
362     };
363 
364     /** helper function to indicate lammps data is stale for all data in a list before exchange, only valid with PAQs */
365     template <typename data>
lammps_reset_loop(std::map<std::string,data * > & list)366     void lammps_reset_loop(std::map<std::string,data * > & list)
367     {
368       for (typename std::map<std::string,data* >::iterator it = list.begin(); it != list.end(); ++it)
369         (it->second)->lammps_force_reset();
370     };
371 
372     /** helper function to size all data in a list, only valid with comm lists */
373     template <typename data>
size_comm_loop(std::vector<data * > & list)374     void size_comm_loop(std::vector<data * > & list)
375     {
376       for (typename std::vector<data* >::iterator it = list.begin(); it != list.end(); ++it)
377         (*it)->quantity();
378     };
379 
380     /** helper function to pack all data in a list before exchange, only valid with quantities that do work before parallel communication */
381     template <typename data>
prepare_exchange_loop(std::map<std::string,data * > & list)382     void prepare_exchange_loop(std::map<std::string,data * > & list)
383     {
384       for (typename std::map<std::string,data* >::iterator it = list.begin(); it != list.end(); ++it) {
385         (it->second)->prepare_exchange();
386       }
387     };
388 
389     /** helper function to extract all data in a list after exchange, only valid with quantities that do work after parallel communication */
390     template <typename data>
post_exchange_loop(std::map<std::string,data * > & list)391     void post_exchange_loop(std::map<std::string,data * > & list)
392     {
393       for (typename std::map<std::string,data* >::iterator it = list.begin(); it != list.end(); ++it) {
394         (it->second)->post_exchange();
395       }
396     };
397 
398     /** helper function to determine memory usage of all data in a list, only valid with PAQs */
399     template <typename data>
memory_usage_loop(const std::map<std::string,data * > & list,int & usage)400     void memory_usage_loop(const std::map<std::string,data * > & list, int & usage) const
401     {
402       for (typename std::map<std::string,data* >::const_iterator it = list.begin(); it != list.end(); ++it)
403         usage += (it->second)->memory_usage();
404     };
405 
406     /** helper function to pack arrays of all data before exchange in a list, only valid with PAQs */
407     template <typename data>
pack_exchange_loop(std::map<std::string,data * > & list,int & index,int i,double * buffer)408     void pack_exchange_loop(std::map<std::string,data * > & list, int & index, int i, double *buffer)
409     {
410       for (typename std::map<std::string,data* >::iterator it = list.begin(); it != list.end(); ++it) {
411         index += (it->second)->pack_exchange(i,&buffer[index]);
412       }
413     };
414 
415     /** helper function to unpack arrays of all data after exchange in a list, only valid with PAQs */
416     template <typename data>
unpack_exchange_loop(std::map<std::string,data * > & list,int & index,int i,double * buffer)417     void unpack_exchange_loop(std::map<std::string,data * > & list, int & index, int i, double *buffer)
418     {
419       for (typename std::map<std::string,data* >::iterator it = list.begin(); it != list.end(); ++it)
420         index += (it->second)->unpack_exchange(i,&buffer[index]);
421     };
422 
423     /** helper function to pack arrays of all data in a list, only valid with comm lists */
424     template <typename data>
pack_comm_loop(std::vector<data * > & list,int & size,int index,double * buf,int pbc_flag,int * pbc)425     void pack_comm_loop(std::vector<data * > & list, int & size, int index, double *buf,
426                         int pbc_flag, int *pbc)
427     {
428       for (typename std::vector<data* >::iterator it = list.begin(); it != list.end(); ++it)
429         size += (*it)->pack_comm(index,&buf[size],pbc_flag,pbc);
430     };
431 
432     /** helper function to unpack arrays of all data in a list, only valid with comm lists */
433     template <typename data>
unpack_comm_loop(std::vector<data * > & list,int & size,int index,double * buf)434     void unpack_comm_loop(std::vector<data * > & list, int & size, int index, double *buf)
435     {
436       for (typename std::vector<data* >::iterator it = list.begin(); it != list.end(); ++it)
437         size += (*it)->unpack_comm(index,&buf[size]);
438     };
439 
440     /** helper function to grow arrays of all data in a list, only valid with PAQs */
441     template <typename data>
grow_arrays_loop(std::map<std::string,data * > & list,int nmax)442     void grow_arrays_loop(std::map<std::string,data * > & list, int nmax)
443     {
444       for (typename std::map<std::string,data* >::iterator it = list.begin(); it != list.end(); ++it)
445         (it->second)->grow_lammps_array(nmax,prefix_+it->first);
446     };
447 
448     /** helper function to copy arrays of all data in a list, only valid with PAQs */
449     template <typename data>
copy_arrays_loop(std::map<std::string,data * > & list,int i,int j)450     void copy_arrays_loop(std::map<std::string,data * > & list, int i, int j)
451     {
452       for (typename std::map<std::string,data* >::iterator it = list.begin(); it != list.end(); ++it)
453         (it->second)->copy_lammps_array(i,j);
454     };
455 
456   private:
457 
458 
459     InterscaleManager();
460 
461   };
462 
463 }
464 
465 #endif
466