votca 2024.2-dev
Loading...
Searching...
No Matches
template_threaded.cc
Go to the documentation of this file.
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#include <cstdlib>
19#include <memory>
20
21#include <votca/csg/beadlist.h>
23#include <votca/csg/nblist.h>
26
27using namespace std;
28using namespace votca::csg;
29
30// comments were mainly added to explain the "overhead" needed for threaded
31// calculations/analyzations
32
33// to sum it up: instead of having one "thread" doing all your work (the whole
34// tracetory), you may split it into single frames and distribute it among many
35// "workers". a solid choice is: number of cores = number of workers. you, as
36// the user, are required to define how to initialize and merge your workers.
37// the main part of the program, EvalConfiguration, is shifted to the Worker
38// class but other than that stays untouched compared to a non-threaded version
39
41
42 string ProgramName() override { return "template_threaded_rdf"; }
43
44 void HelpText(ostream &out) override {
45 out << "template for threaded rdf calculations";
46 }
47
48 void Initialize() override;
49
50 bool DoTrajectory() override { return true; }
51
52 // explicitly turn on threaded mode by overriding DoThreaded() and returning
53 // true note that threads will be started and merged in an ordered way by
54 // default this has the disadvantage of slowing everything down a bit (you
55 // will likely not notice a decrease of performance), but the advantage of
56 // processing frames in their original order in most cases, you want that in
57 // some cases, where reading and writing/merging does not have to occur in
58 // order, you may consider switching SynchronizeThreads() off in this example,
59 // where an rdf-like value is calculated, ordered reading/writing is not
60 // neccessary. however, leave it untouched to prevent future mistakes
61
62 bool DoThreaded() override { return true; }
63 // are you sure? really?
64 // bool SynchronizeThreads() {
65 // return false;
66 // }
67
68 void BeginEvaluate(Topology *top, Topology *top_ref) override;
69 void EndEvaluate() override;
70
71 // ForkWorker is the function you need to override and initialize your workers
72 std::unique_ptr<CsgApplication::Worker> ForkWorker(void) override;
73
74 // MergeWorker needs you to define how to merge different workers and their
75 // data
76 void MergeWorker(Worker *worker) override;
77
78 protected:
79 // data belonging to the main class CsgParallelTestApp
81 double cut_off_;
82};
83
84// derive from CsgApplication::Worker and define your worker
86 public:
87 ~RDFWorker() override = default;
88 // override EvalConfiguration with your analysis routine
89 void EvalConfiguration(Topology *, Topology *) override;
90 // data belonging to this particular worker
92 double cut_off_;
93};
94
95int main(int argc, char **argv) {
97
98 return app.Exec(argc, argv);
99}
100
103 AddProgramOptions("RDF options")(
104 "c", boost::program_options::value<double>()->default_value(1.0),
105 "the cutoff");
106}
107
109 cut_off_ = OptionsMap()["c"].as<double>();
110 rdf_.Initialize(0, cut_off_, 50);
111}
112
113// create and initialize single workers
114// ForkWorker() will be called as often as the parameter '--nt NTHREADS'
115// it creates a new worker and the user is required to initialize variables etc.
116// (if needed)
117std::unique_ptr<CsgApplication::Worker> CsgParallelTestApp::ForkWorker() {
118 auto worker = std::make_unique<RDFWorker>();
119 // initialize
120 worker->cut_off_ = OptionsMap()["c"].as<double>();
121 worker->rdf_.Initialize(0, worker->cut_off_, 50);
122 return worker;
123}
124
125// EvalConfiguration does the actual calculation
126// you won't see any explicit threaded stuff here
128 BeadList b;
129 b.Generate(*top, "*");
130 NBListGrid nb;
132 nb.Generate(b);
133 for (auto &pair : nb) {
134 rdf_.Process(pair->dist());
135 }
136}
137
138// the user is required to define how to merge the single data
139// belonging to each thread into the main data belonging to CsgParallelTestApp
141 RDFWorker *myRDFWorker;
142 // cast generel Worker into your derived worker class(here RDFWorker)
143 myRDFWorker = dynamic_cast<RDFWorker *>(worker);
144
145 // the next comment block explains how mutexes are used internally for this
146 // function: mutexes are used to exclusively work on data e.g., if you read or
147 // write global data, make sure that nobody else (i.e. no other worker) works
148 // on that very same piece of data at the same time; otherwise, you will end
149 // up with wrong results that you struggle to understand the parent class
150 // handles a "merging mutex" for you internally; this is what happens: first,
151 // a mutex is created, e.g.
152 // Mutex rdfMutex;
153 // then, for each worker, the mutex is first locked
154 // rdfMutex.Lock())
155 // and MergeWorker(worker) is called (i.e. the code you define here is
156 // executed) after MergeWorker exits, the mutex is unlocked
157 // rdfMutex.Unlock();
158 // and allows other threads to get a lock and start merging
159
160 // now follows your code
161
162 // merging of data in this simple example is easy and does not have to follow
163 // the original order of frames (since plain summing is commutative)
164 rdf_.data().y() = rdf_.data().y() + myRDFWorker->rdf_.data().y();
165}
166
168 rdf_.data().y() = rdf_.data().y().cwiseQuotient(rdf_.data().x().cwiseAbs2());
169 rdf_.data().Save("rdf.dat");
170}
bool DoThreaded() override
string ProgramName() override
program name
void MergeWorker(Worker *worker) override
void BeginEvaluate(Topology *top, Topology *top_ref) override
called before the first frame
std::unique_ptr< CsgApplication::Worker > ForkWorker(void) override
void HelpText(ostream &out) override
help text of application without version information
votca::tools::HistogramNew rdf_
bool DoTrajectory() override
overload and return true to enable trajectory command line options
void Initialize() override
Initialize application data.
void EndEvaluate() override
called after the last frame
votca::tools::HistogramNew rdf_
void EvalConfiguration(Topology *, Topology *) override
overload with the actual computation
~RDFWorker() override=default
Index Generate(Topology &top, const std::string &select)
Select all beads of type "select".
Definition beadlist.cc:30
Worker, derived from Thread, does the work.
void Initialize() override
Initialize application data.
void Generate(BeadList &list1, BeadList &list2, bool do_exclusions=true) override
Generate the neighbour list based on two bead lists (e.g. bead types)
Definition nblistgrid.cc:28
void setCutoff(double cutoff)
set the cutoff for the neighbour search
Definition nblist.h:53
topology of the whole system
Definition topology.h:81
int Exec(int argc, char **argv)
executes the program
boost::program_options::variables_map & OptionsMap()
get available program options & descriptions
boost::program_options::options_description_easy_init AddProgramOptions(const std::string &group="")
add option for command line
class to generate histograms
Table & data()
get access to content of histogram
void Initialize(double min, double max, Index nbins)
Initialize the HistogramNew.
void Process(const double &v, double scale=1.0)
process a data point
double & x(Index i)
Definition table.h:44
double & y(Index i)
Definition table.h:45
void Save(std::string filename) const
Definition table.cc:59
STL namespace.
int main(int argc, char **argv)