votca 2025.1-dev
Loading...
Searching...
No Matches
template_threaded.cc
Go to the documentation of this file.
1/*
2 * Copyright 2009-2025 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
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::Histogram rdf_
void EvalConfiguration(Topology *, Topology *) override
overload with the actual computation
~RDFWorker() override=default
votca::tools::Histogram rdf_
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
Definition histogram.h:77
Table & data()
get access to content of histogram
Definition histogram.h:157
double & y(Index i)
Definition table.h:45
STL namespace.
int main(int argc, char **argv)