Skip to content

Commit b5464f5

Browse files
authored
Merge pull request #13 from DCM-UPB/mpi_wrapper
Mpi wrapper
2 parents 6a5cbd4 + 9426115 commit b5464f5

File tree

14 files changed

+637
-61
lines changed

14 files changed

+637
-61
lines changed

config_template.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ LIBNAME="mci"
66
# C++ compiler
77
CC="g++"
88

9+
# MPI compiler wrapper
10+
MPICC="mpic++"
11+
912
# C++ flags (std=c++11 is necessary)
1013
FLAGS="-std=c++11 -Wall -Werror"
1114

debug/unittests/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,7 @@
99
## Unit Test 2
1010

1111
`ut2/`: Like ut1, but with one one-dimensional and one three-dimensional observable.
12+
13+
## Unit Test 3
14+
15+
`ut3/`: Like ut1, but checking with fixed number of findMRT2step/decorrelation steps and fixed blocking technique

debug/unittests/ut3/main.cpp

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
#include "MCIntegrator.hpp"
2+
#include "MCISamplingFunctionInterface.hpp"
3+
4+
#include <iostream>
5+
#include <math.h>
6+
#include <assert.h>
7+
8+
using namespace std;
9+
10+
11+
12+
class ThreeDimGaussianPDF: public MCISamplingFunctionInterface{
13+
public:
14+
ThreeDimGaussianPDF(): MCISamplingFunctionInterface(3, 1){}
15+
~ThreeDimGaussianPDF(){}
16+
17+
void samplingFunction(const double *in, double * protovalues){
18+
protovalues[0] = (in[0]*in[0]) + (in[1]*in[1]) + (in[2]*in[2]);
19+
}
20+
21+
22+
double getAcceptance(const double * protoold, const double * protonew){
23+
return exp(-protonew[0]+protoold[0]);
24+
}
25+
26+
};
27+
28+
29+
class XSquared: public MCIObservableFunctionInterface{
30+
public:
31+
XSquared(): MCIObservableFunctionInterface(3, 1){}
32+
~XSquared(){}
33+
34+
void observableFunction(const double * in, double * out){
35+
out[0] = in[0] * in[0];
36+
}
37+
};
38+
39+
40+
41+
int main(){
42+
const long NMC = 10000;
43+
const double CORRECT_RESULT = 0.5;
44+
45+
ThreeDimGaussianPDF * pdf = new ThreeDimGaussianPDF();
46+
XSquared * obs = new XSquared();
47+
48+
MCI * mci = new MCI(3);
49+
mci->setSeed(5649871);
50+
mci->addSamplingFunction(pdf);
51+
mci->addObservable(obs);
52+
// the integral should provide 0.5 as answer!
53+
54+
double * x = new double[3];
55+
x[0] = 5.; x[1] = -5.; x[2] = 10.;
56+
57+
double * average = new double;
58+
double * error = new double;
59+
60+
// this integral will give a wrong answer! This is because the starting point is very bad and initialDecorrelation is skipped (as well as the MRT2step automatic setting)
61+
mci->setX(x);
62+
mci->integrate(NMC, average, error, 0, 0);
63+
assert( abs(average[0]-CORRECT_RESULT) > 2.*error[0] );
64+
65+
// this integral, instead, will provide the right answer
66+
mci->setX(x);
67+
mci->integrate(NMC, average, error, 10, 1000);
68+
assert( abs(average[0]-CORRECT_RESULT) < 2.*error[0] );
69+
70+
// now, doing an integral without finding again the MRT2step and doing the initialDecorrelation will also result in a correct result
71+
mci->integrate(NMC, average, error, 0, 0);
72+
assert( abs(average[0]-CORRECT_RESULT) < 2.*error[0] );
73+
74+
// and using fixed blocking also gives the same result
75+
mci->integrate(NMC, average, error, 0, 0, 15);
76+
assert( abs(average[0]-CORRECT_RESULT) < 2.*error[0] );
77+
78+
79+
delete pdf;
80+
delete obs;
81+
delete mci;
82+
delete [] x;
83+
delete average;
84+
delete error;
85+
86+
return 0;
87+
}

doc/user_manual.pdf

3.07 KB
Binary file not shown.

doc/user_manual.tex

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,34 @@ \subsection{Multidimensional estimations} % (fold)
568568
Data (\verb+x+) are supposed to be organised as a $\verb+n+ \times \verb+ndim+$ matrix.
569569
% subsection multidimensional_estimations (end)
570570

571+
\section{MPI-MCI} % (fold)
572+
\label{sec:mpimci}
573+
574+
It is possible to use Message Passing Interface (MPI) for evaluating the MC integrals
575+
in parallel. The library provides a namespace \verb+MPIMCI+ that contains a few
576+
simple methods to use for creating a parallel MC program. Although the MCI library can be
577+
compiled without any MPI implementation present, to use the MPIMCI methods in
578+
executable code you need OpenMPI or an alternative implementation.
579+
\\\\Then just use MPIMCI in your code as follows and compile\&run the executable with your system's MPI wrappers (e.g mpic++ and mpirun).
580+
581+
\begin{verbatim}
582+
#include "MPIMCI.hpp"
583+
// start of main
584+
const int myrank = MPIMCI::init();
585+
// ...
586+
MPIMCI::integrate(mci, Nmc, average, error);
587+
// ...
588+
if (myrank==0) { /* printout etc. */ }
589+
// ...
590+
MPIMCI::finalize();
591+
// end of main
592+
\end{verbatim}
593+
Remember not to encapsulate any code within \verb+if (myrank==0){}+ clauses,
594+
that is actually relevant to all threads. Typically this means only file and
595+
console output belongs there.
596+
\\\\For further information on options and use, check out \verb+ex2+ and the \verb+MPIMCI.hpp+ header file.
597+
598+
% section mpivmc (end)
571599

572600

573601
\printindex

examples/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,8 @@
55
## Example 1
66

77
`ex1/`: integration of a 1-dimensional quadratic function, without and with a sampling function.
8+
9+
10+
## Example 2
11+
12+
`ex2/`: like ex2, but using the MPI wrapper for parallel integration. Pass the wanted number of threads to run.sh.

examples/ex2/main.cpp

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
#include "mpi.h"
2+
#include <iostream>
3+
#include <cmath>
4+
#include <math.h>
5+
#include <fstream>
6+
7+
#include "MCIntegrator.hpp"
8+
#include "MPIMCI.hpp"
9+
10+
11+
// Observable functions
12+
class Parabola: public MCIObservableFunctionInterface{
13+
public:
14+
Parabola(const int &ndim): MCIObservableFunctionInterface(ndim, 1) {}
15+
16+
void observableFunction(const double * in, double * out){
17+
out[0] = 4.*in[0] - in[0]*in[0];
18+
}
19+
};
20+
21+
class NormalizedParabola: public MCIObservableFunctionInterface{
22+
public:
23+
NormalizedParabola(const int &ndim): MCIObservableFunctionInterface(ndim, 1) {}
24+
25+
void observableFunction(const double * in, double * out){
26+
out[0] = (4. - in[0]) * 5.;
27+
if (std::signbit(in[0])) out[0] = -out[0];
28+
}
29+
};
30+
31+
32+
33+
// Sampling function
34+
// the 48 is for normalization (even if not strictly necessary)
35+
class NormalizedLine: public MCISamplingFunctionInterface{
36+
public:
37+
NormalizedLine(const int &ndim): MCISamplingFunctionInterface(ndim, 1) {}
38+
39+
void samplingFunction(const double * in, double * protovalue){
40+
protovalue[0] = 0.2 * abs(in[0]);
41+
}
42+
43+
double getAcceptance(const double * protoold, const double * protonew){
44+
return protonew[0] / protoold[0];
45+
}
46+
};
47+
48+
49+
50+
int main() {
51+
using namespace std;
52+
53+
int myrank = MPIMCI::init(); // first run custom MPI init
54+
55+
if (myrank == 0) {
56+
// intro
57+
cout << "We want to compute the integral" << endl;
58+
cout << " Integral[-1:3] dx (4x - x^2)" << endl << endl;
59+
cout << "Notice that we can re-write the integral as" << endl;
60+
cout << " Integral[-1:3] dx (5*sign(x)*(4-x) * |x|/5)" << endl;
61+
cout << "where g(x)=|x|/5 is a candidate sampling function since it's positive on the domain [-1:3] and its integral on the domain is equal to 1." << endl << endl;
62+
63+
cout << "We start by initializing MPI and setting the MCI:" << endl;
64+
}
65+
66+
const int ndim = 1;
67+
MCI * mci = new MCI(ndim);
68+
69+
// seed the different MPI threads from a file
70+
MPIMCI::setSeed(mci, "rseed.txt", 0); // offset x -> start from the x-th seed in file
71+
72+
if (myrank == 0) cout << "ndim = " << mci->getNDim() << endl;
73+
74+
// set the integration range to [-1:3]
75+
double ** irange = new double*[ndim];
76+
irange[0] = new double[2];
77+
irange[0][0] = -1.;
78+
irange[0][1] = 3.;
79+
mci->setIRange(irange);
80+
81+
if (myrank == 0) cout << "irange = [ " << mci->getIRange(0, 0) << " ; " << mci->getIRange(0, 1) << " ]" << endl;
82+
83+
// initial walker position
84+
double * initpos = new double[ndim];
85+
initpos[0] = -0.5;
86+
mci->setX(initpos);
87+
88+
if (myrank == 0) cout << "initial walker position = " << mci->getX(0) << endl;
89+
90+
// initial MRT2 step
91+
double * step = new double[ndim];
92+
step[0] = 0.5;
93+
mci->setMRT2Step(step);
94+
95+
if (myrank == 0) cout << "MRT2 step = " << mci->getMRT2Step(0) << endl;
96+
97+
// target acceptance rate
98+
double * targetacceptrate = new double[1];
99+
targetacceptrate[0] = 0.7;
100+
mci->setTargetAcceptanceRate(targetacceptrate);
101+
102+
if (myrank == 0) {
103+
cout << "Acceptance rate = " << mci->getTargetAcceptanceRate() << endl;
104+
cout << endl << endl;
105+
106+
// first way of integrating
107+
cout << "We first compute the integral without setting a sampling function." << endl;
108+
cout << " f(x) = (4x - x^2) " << endl;
109+
cout << " g(x) = - " << endl << endl;
110+
}
111+
112+
// observable
113+
MCIObservableFunctionInterface * obs = new Parabola(ndim);
114+
mci->addObservable(obs);
115+
116+
if (myrank == 0) {
117+
cout << "Number of observables set = " << mci->getNObs() << endl;
118+
// sampling function
119+
cout << "Number of sampling function set = " << mci->getNSampF() << endl;
120+
}
121+
122+
// integrate
123+
const long Nmc = 1000000;
124+
double * average = new double[mci->getNObsDim()];
125+
double * error = new double[mci->getNObsDim()];
126+
127+
MPIMCI::integrate(mci, Nmc, average, error);
128+
129+
if (myrank == 0) {
130+
cout << "The integral gives as result = " << average[0] << " +- " << error[0] << endl;
131+
cout << "--------------------------------------------------------" << endl << endl;
132+
133+
// second way of integrating
134+
cout << "Now we compute the integral using a sampling function." << endl;
135+
cout << " f(x) = 5*sign(x)*(4-x) " << endl;
136+
cout << " g(x) = |x|/5 " << endl << endl;
137+
}
138+
139+
// observable
140+
delete obs;
141+
obs = new NormalizedParabola(ndim);
142+
mci->clearObservables(); // we first remove the old observable
143+
mci->addObservable(obs);
144+
145+
if (myrank == 0) cout << "Number of observables set = " << mci->getNObs() << endl;
146+
147+
148+
// sampling function
149+
MCISamplingFunctionInterface * sf = new NormalizedLine(ndim);
150+
mci->addSamplingFunction(sf);
151+
152+
if (myrank == 0) cout << "Number of sampling function set = " << mci->getNSampF() << endl;
153+
154+
155+
// integrate
156+
MPIMCI::integrate(mci, Nmc, average, error);
157+
158+
if (myrank == 0) {
159+
cout << "The integral gives as result = " << average[0] << " +- " << error[0] << endl;
160+
cout << "--------------------------------------------------------" << endl << endl;
161+
162+
163+
// final comments
164+
cout << "Using a sampling function in this case gives worse performance. In fact, the error bar is larger." << endl;
165+
cout << "This implies that the variance of the re-factored f(x) written for introducing a sampling function, is larger than the original f(x)." << endl;
166+
}
167+
168+
// deallocate per-thread allocations
169+
delete sf;
170+
171+
delete obs;
172+
173+
delete[] targetacceptrate;
174+
175+
delete[] step;
176+
177+
delete[] initpos;
178+
179+
delete[] irange[0];
180+
delete[] irange;
181+
182+
delete[] average;
183+
delete[] error;
184+
185+
delete mci;
186+
187+
// finalize MPI
188+
MPIMCI::finalize();
189+
190+
// end
191+
return 0;
192+
}

examples/ex2/rseed.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../res/rseed.txt

examples/ex2/run.sh

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#!/bin/bash
2+
source ../../config.sh
3+
OS_NAME=$(uname)
4+
5+
# Delete old compiled files
6+
\rm -f exe
7+
\rm -f *.o
8+
9+
#runtime dynamic library path
10+
RPATH="$(pwd)/../.."
11+
12+
FLAGS_TO_USE=$OPTFLAGS
13+
14+
# Build the main executable
15+
echo "$MPICC $FLAGS $FLAGS_TO_USE -I$(pwd)/../../src/ -c *.cpp"
16+
$MPICC $FLAGS $FLAGS_TO_USE -Wall -I$(pwd)/../../src/ -c *.cpp
17+
18+
case ${OS_NAME} in
19+
"Darwin")
20+
echo "$MPICC $FLAGS $FLAGS_TO_USE -L$(pwd)/../.. -o exe *.o -l${LIBNAME}"
21+
$MPICC $FLAGS $FLAGS_TO_USE -L$(pwd)/../.. -o exe *.o -l${LIBNAME}
22+
;;
23+
"Linux")
24+
echo "$MPICC $FLAGS $FLAGS_TO_USE -L$(pwd)/../.. -Wl,-rpath=${RPATH} -o exe *.o -l${LIBNAME}"
25+
$MPICC $FLAGS $FLAGS_TO_USE -L$(pwd)/../.. -Wl,-rpath=${RPATH} -o exe *.o -l${LIBNAME}
26+
;;
27+
esac
28+
29+
echo "Rebuilt the executable file"
30+
echo ""
31+
echo ""
32+
33+
# Run the debugging executable
34+
echo "Ready to run!"
35+
echo ""
36+
echo "--------------------------------------------------------------------------"
37+
echo ""
38+
echo ""
39+
echo ""
40+
mpirun -np $1 exe

res/rseed.txt

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)