Goal: Learn how to differentiate OpenMP parallel codes with CoDiPack and OpDiLib.
Prerequisite: Tutorial 2 - Reverse mode AD
Full code:
#include <codi.hpp>
#include <opdi.hpp>
#include <iostream>
#include <opdi/backend/macro/macroBackend.hpp>
#include <opdi.hpp>
int main(int nargs, char** args) {
opdi::backend = new opdi::MacroBackend();
opdi::backend->init();
opdi::logic = new opdi::OmpLogic;
opdi::logic->init();
opdi::tool = new CoDiOpDiLibTool<Real>;
tape.setActive();
tape.registerInput(x);
OPDI_PARALLEL()
{
OPDI_FOR()
for (int i = 0; i < 1000; ++i)
{
a[i] = sin(x * i);
}
OPDI_END_FOR
}
OPDI_END_PARALLEL
for (int i = 0; i < 1000; ++i) {
y += a[i];
}
tape.registerOutput(y);
tape.setPassive();
opdi::logic->prepareEvaluate();
tape.evaluate();
std::cout << "f(" << x << ") = " << y << std::endl;
std::cout <<
"df/dx(" << x <<
") = " << x.
getGradient() << std::endl;
opdi::backend->finalize();
delete opdi::backend;
delete opdi::logic;
delete opdi::tool;
return 0;
}
#include <opdi.cpp>
RealReverseIndexOpenMPGen< double > RealReverseIndexOpenMP
Definition: codiOpenMP.hpp:72
Represents a concrete lvalue in the CoDiPack expression tree.
Definition: activeType.hpp:52
static Tape & getTape()
Get a reference to the tape which manages this expression.
Definition: activeType.hpp:99
T_Tape Tape
See ActiveType.
Definition: activeType.hpp:55
void setGradient(Gradient const &g)
Set the gradient of this lvalue in the tape.
Definition: lhsExpressionInterface.hpp:120
Gradient getGradient() const
Get the gradient of this lvalue from the tape.
Definition: lhsExpressionInterface.hpp:115
OpenMP parallel codes are differentiated with the help of the OpDiLib AD tool add-on (https://www.scicomp.uni-kl.de/software/opdi). Please refer to the OpDiLib documentation for further examples and modes of operation.
The usual AD workflow is the same as for a serial code, except for the initialization and finalization of OpDiLib. In the example at hand, OpDiLib's macro backend is used, where pragmas such as #pragma omp parallel
are replaced by macros such as OPDI_PARALLEL()
together with end macros such as OPDI_END_PARALLEL
. If you have a compiler with OMPT support, you can use OpDiLib's OMPT backend that supports the usage of unmodified OpenMP pragmas (see https://github.com/SciCompKL/OpDiLib for examples).
OpDiLib can only be used with CoDiPack types that are thread-safe for applications in OpenMP parallel codes. Right now, the dedicated type that supports this is codi::RealReverseIndexOpenMP.