1 /*
2  * Copyright 2009-2021 The VOTCA Development Team (http://www.votca.org)
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17 
18 #ifndef VOTCA_CSG_CSGAPPLICATION_H
19 #define VOTCA_CSG_CSGAPPLICATION_H
20 
21 // VOTCA includes
22 #include <memory>
23 #include <votca/tools/application.h>
24 #include <votca/tools/mutex.h>
25 #include <votca/tools/thread.h>
26 
27 // Local VOTCA includes
28 #include "cgobserver.h"
29 #include "topology.h"
30 #include "topologymap.h"
31 #include "trajectoryreader.h"
32 
33 namespace votca {
34 namespace csg {
35 
36 class CsgApplication : public tools::Application {
37  public:
38   CsgApplication() = default;
39   ~CsgApplication() override = default;
40 
41   void Initialize() override;
42   bool EvaluateOptions() override;
43 
44   void Run(void) override;
45 
46   void ShowHelpText(std::ostream &out) override;
47 
48   /// \brief overload and return true to enable mapping command line options
49 
DoMapping(void)50   virtual bool DoMapping(void) { return false; }
51   /// \brief if DoMapping is true, will by default require mapping or not
52 
DoMappingDefault(void)53   virtual bool DoMappingDefault(void) { return true; }
54   /// \brief overload and return true to enable trajectory command line options
55 
DoTrajectory(void)56   virtual bool DoTrajectory(void) { return false; }
57 
58   /* \brief overload and return true to enable threaded calculations */
DoThreaded(void)59   virtual bool DoThreaded(void) { return false; }
60 
61   /* \brief overload and return false to disable synchronized (while threaded)
62    * calculations */
SynchronizeThreads(void)63   virtual bool SynchronizeThreads(void) {
64     if (DoThreaded()) {
65       return true;
66     } else {
67       return false;
68     }
69   }
70 
71   /// \brief if topology is always needed
NeedsTopology(void)72   virtual bool NeedsTopology(void) { return true; }
73 
74   /// \brief called after topology was loaded
75 
76   virtual bool EvaluateTopology(Topology *, Topology * = nullptr) {
77     return true;
78   }
79 
80   void AddObserver(CGObserver *observer);
81 
82   /// \brief called before the first frame
83   virtual void BeginEvaluate(Topology *top, Topology *top_ref = nullptr);
84   /// \brief called after the last frame
85   virtual void EndEvaluate();
86   // \brief called for each frame which is mapped
87   virtual void EvalConfiguration(Topology *top, Topology *top_ref = nullptr);
88 
89   // thread related stuff follows
90 
91   /**
92    \brief Worker, derived from Thread, does the work.
93    *
94    * Worker holds the information about the current frame, either in its
95    * own copy (e.g. Topology), or, by reference, from the parent CsgApplication.
96    * The computation is shifted from Run() into EvalConfiguration. The
97    * user is required to overload ForkWorker and Mergeworker and thereby
98    * define the initialization and merging of workers. By default, workers
99    * will be executed in correct order according to the frames. Also,
100    * output will follow the same order.
101    * Mutexes handle the locking of input/output and are also used to impose
102    * the correct order of frames for in/output.
103    *
104    */
105   class Worker : public tools::Thread {
106    public:
107     Worker() = default;
108 
109     /// \brief overload with the actual computation
110     virtual void EvalConfiguration(Topology *top,
111                                    Topology *top_ref = nullptr) = 0;
112 
113     /// \brief returns worker id
getId()114     Index getId() { return id_; }
115 
116    protected:
117     CsgApplication *app_ = nullptr;
118     Topology top_, top_cg_;
119     std::unique_ptr<TopologyMap> map_;
120     Index id_ = -1;
121 
122     void Run(void) override;
123 
setApplication(CsgApplication * app)124     void setApplication(CsgApplication *app) { app_ = app; }
125 
setId(Index id)126     void setId(Index id) { id_ = id; }
127 
128     friend class CsgApplication;
129   };
130 
131   /**
132    * \brief Gets frames from TrajectoryReader in an ordered way and, if
133    * successful, calls Worker::EvalConfiguration for that frame.
134    *
135    * @param worker
136    * @return True if frames left for calculation, else False
137    */
138   bool ProcessData(Worker *worker);
139 
140   /**
141    *
142    * User is required to overload ForkWorker and initialize workers.
143    * @return worker
144    */
145   virtual std::unique_ptr<Worker> ForkWorker(void);
146 
147   /**
148    * User is required to overload MergeWorker and merge data from each worker.
149    * @param worker
150    */
151   virtual void MergeWorker(Worker *worker);
152 
153  protected:
154   std::list<CGObserver *> observers_;
155   bool do_mapping_;
156   std::vector<std::unique_ptr<Worker>> myWorkers_;
157   Index nframes_;
158   bool is_first_frame_;
159   Index nthreads_;
160   tools::Mutex nframesMutex_;
161   tools::Mutex traj_readerMutex_;
162 
163   /// \brief stores Mutexes used to impose order for input
164   std::vector<std::unique_ptr<tools::Mutex>> threadsMutexesIn_;
165   /// \brief stores Mutexes used to impose order for output
166   std::vector<std::unique_ptr<tools::Mutex>> threadsMutexesOut_;
167   std::unique_ptr<TrajectoryReader> traj_reader_;
168 };
169 
AddObserver(CGObserver * observer)170 inline void CsgApplication::AddObserver(CGObserver *observer) {
171   observers_.push_back(observer);
172 }
173 
174 }  // namespace csg
175 }  // namespace votca
176 
177 #endif  // VOTCA_CSG_CSGAPPLICATION_H
178