CoDiPack  3.1.2
A Code Differentiation Package
SciComp TU Kaiserslautern
Loading...
Searching...
No Matches
codiReverseMeDiPackTool.hpp
1/*
2 * CoDiPack, a Code Differentiation Package
3 *
4 * Copyright (C) 2015-2026 Chair for Scientific Computing (SciComp), RPTU University Kaiserslautern-Landau
5 * Homepage: http://scicomp.rptu.de
6 * Contact: Prof. Nicolas R. Gauger (codi@scicomp.uni-kl.de)
7 *
8 * Lead developers: Max Sagebaum, Johannes Blühdorn (SciComp, RPTU University Kaiserslautern-Landau)
9 *
10 * This file is part of CoDiPack (http://scicomp.rptu.de/software/codi).
11 *
12 * CoDiPack is free software: you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, either version 3 of the
15 * License, or (at your option) any later version.
16 *
17 * CoDiPack is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty
19 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20 *
21 * See the GNU General Public License for more details.
22 * You should have received a copy of the GNU
23 * General Public License along with CoDiPack.
24 * If not, see <http://www.gnu.org/licenses/>.
25 *
26 * For other licensing options please contact us.
27 *
28 * Authors:
29 * - SciComp, RPTU University Kaiserslautern-Landau:
30 * - Max Sagebaum
31 * - Johannes Blühdorn
32 * - Former members:
33 * - Tim Albring
34 */
35#pragma once
36
37#include <medi/adToolInterface.h>
38#include <medi/ampi/ampiMisc.h>
39
40#include <medi/adToolImplCommon.hpp>
41#include <medi/adjointInterface.hpp>
42#include <medi/ampi/op.hpp>
43#include <medi/ampi/typeDefault.hpp>
44#include <medi/ampi/types/indexTypeHelper.hpp>
45
46#include "../../config.h"
47#include "../../expressions/lhsExpressionInterface.hpp"
48#include "../../misc/macros.hpp"
49#include "../../tapes/interfaces/fullTapeInterface.hpp"
50#include "../../tapes/misc/adjointVectorAccess.hpp"
51
53namespace codi {
54
55#ifndef DOXYGEN_DISABLE
56
57 #define MEDI_1_4_OR_GREATER MEDI_MAJOR_VERSION > 1 || (MEDI_MAJOR_VERSION == 1 && MEDI_MINOR_VERSION >= 4)
58
59 template<typename T_Type>
60 struct CoDiMeDiAdjointInterfaceWrapper : public medi::AdjointInterface {
61 public:
62
63 using Type = CODI_DD(T_Type, CODI_DEFAULT_LHS_EXPRESSION);
64
65 using Real = typename Type::Real;
66 using Identifier = typename Type::Identifier;
67
68 VectorAccessInterface<Real, Identifier>* codiInterface;
69
70 int vecSize;
71
72 CoDiMeDiAdjointInterfaceWrapper(VectorAccessInterface<Real, Identifier>* interface)
73 : codiInterface(interface), vecSize((int)interface->getVectorSize()) {}
74
75 CODI_INLINE_NO_FA int computeElements(int elements) const {
76 return elements * vecSize;
77 }
78
79 CODI_INLINE_NO_FA int getVectorSize() const {
80 return vecSize;
81 }
82
83 CODI_INLINE_NO_FA void getAdjoints(void const* i, void* a, int elements) const {
84 Real* adjoints = (Real*)a;
85 Identifier* indices = (Identifier*)i;
86
87 for (int pos = 0; pos < elements; ++pos) {
88 codiInterface->getAdjointVec(indices[pos], &adjoints[pos * vecSize]);
89 codiInterface->resetAdjointVec(indices[pos]);
90 }
91 }
92
93 CODI_INLINE_NO_FA void updateAdjoints(void const* i, void const* a, int elements) const {
94 Real* adjoints = (Real*)a;
95 Identifier* indices = (Identifier*)i;
96
97 for (int pos = 0; pos < elements; ++pos) {
98 codiInterface->updateAdjointVec(indices[pos], &adjoints[pos * vecSize]);
99 }
100 }
101
102 CODI_INLINE_NO_FA void getPrimals(void const* i, void const* p, int elements) const {
103 Real* primals = (Real*)p;
104 Identifier* indices = (Identifier*)i;
105
106 for (int pos = 0; pos < elements; ++pos) {
107 primals[pos] = codiInterface->getPrimal(indices[pos]);
108 }
109 }
110
111 CODI_INLINE_NO_FA void setPrimals(void const* i, void const* p, int elements) const {
112 Real* primals = (Real*)p;
113 Identifier* indices = (Identifier*)i;
114
115 for (int pos = 0; pos < elements; ++pos) {
116 codiInterface->setPrimal(indices[pos], primals[pos]);
117 }
118 }
119
120 CODI_INLINE_NO_FA void combineAdjoints(void* b, int const elements, int const ranks) const {
121 Real* buf = (Real*)b;
122
123 for (int curRank = 1; curRank < ranks; ++curRank) {
124 for (int curPos = 0; curPos < elements; ++curPos) {
125 for (int dim = 0; dim < vecSize; ++dim) {
126 buf[curPos * vecSize + dim] += buf[(elements * curRank + curPos) * vecSize + dim];
127 }
128 }
129 }
130 }
131
132 CODI_INLINE_NO_FA void createPrimalTypeBuffer(void*& buf, size_t size) const {
133 buf = (void*)(new Real[size * vecSize]);
134 }
135
136 CODI_INLINE_NO_FA void deletePrimalTypeBuffer(void*& b) const {
137 if (nullptr != b) {
138 Real* buf = (Real*)b;
139 delete[] buf;
140 b = nullptr;
141 }
142 }
143
144 CODI_INLINE_NO_FA void createAdjointTypeBuffer(void*& buf, size_t size) const {
145 buf = (void*)(new Real[size * vecSize]);
146 }
147
148 CODI_INLINE_NO_FA void deleteAdjointTypeBuffer(void*& b) const {
149 if (nullptr != b) {
150 Real* buf = (Real*)b;
151 delete[] buf;
152 b = nullptr;
153 }
154 }
155 };
156
157 template<typename T_Type>
158 struct CoDiPackReverseTool
159 : public medi::ADToolImplCommon<CoDiPackReverseTool<T_Type>, T_Type::Tape::RequiresPrimalRestore, false, T_Type,
160 typename T_Type::Gradient, typename T_Type::Real, typename T_Type::Identifier> {
161 public:
162
163 // All type definitions for the interface.
164 using Type = CODI_DD(T_Type, CODI_DEFAULT_LHS_EXPRESSION);
165 using PrimalType = typename Type::Real;
166 using AdjointType = void;
167 using ModifiedType = Type;
168 using IndexType = typename Type::Identifier;
169
170 // Helper definition for CoDiPack.
171 using Tape = CODI_DD(typename Type::Tape, CODI_DEFAULT_TAPE);
172 using IterCallback = typename ExternalFunction<Tape>::IterCallback;
173
174 using OpHelper =
175 medi::OperatorHelper<medi::FunctionHelper<Type, Type, typename Type::PassiveReal, typename Type::Gradient,
176 typename Type::Identifier, CoDiPackReverseTool> >;
177
178 using Base = medi::ADToolImplCommon<CoDiPackReverseTool, Tape::RequiresPrimalRestore, false, Type,
179 typename Type::Gradient, PrimalType, IndexType>;
180
181 private:
182 // Private structures for the implementation.
183
184 OpHelper opHelper;
185
186 public:
187 CoDiPackReverseTool(MPI_Datatype primalMpiType, MPI_Datatype adjointMpiType)
188 : Base(primalMpiType, adjointMpiType), opHelper() {
189 opHelper.init();
190 }
191
192 ~CoDiPackReverseTool() {
193 opHelper.finalize();
194 }
195
196 // Implementation of the interface.
197
198 CODI_INLINE_NO_FA bool isHandleRequired() const {
199 // Handle creation is based on the CoDiPack tape activity. Only if the tape is recording the adjoint
200 // communication needs to be evaluated.
201 return getTape().isActive();
202 }
203
204 CODI_INLINE_NO_FA void startAssembly(medi::HandleBase* h) const {
205 CODI_UNUSED(h);
206
207 // No preparation required for CoDiPack.
208 }
209
210 CODI_INLINE_NO_FA void addToolAction(medi::HandleBase* h) const {
211 if (nullptr != h) {
212 getTape().pushExternalFunction(
213 ExternalFunction<Tape>::create(callHandleReverse, h, deleteHandle, callHandleForward, callHandlePrimal,
214 callHandleIterateInputs, callHandleIterateOutputs));
215 }
216 }
217
218 medi::AMPI_Op convertOperator(medi::AMPI_Op op) const {
219 return opHelper.convertOperator(op);
220 }
221
222 CODI_INLINE_NO_FA void stopAssembly(medi::HandleBase* h) const {
223 CODI_UNUSED(h);
224
225 // No preparation required for CoDiPack.
226 }
227
228 static CODI_INLINE_NO_FA IndexType getIndex(Type const& value) {
229 return value.getIdentifier();
230 }
231
232 static CODI_INLINE_NO_FA void registerValue(Type& value, PrimalType& oldPrimal, IndexType& index) {
233 bool wasActive = getTape().isIdentifierActive(value.getIdentifier());
234 value.getIdentifier() = IndexType();
235
236 // Make the value active again if it has been active before on the other processor.
237 if (wasActive) {
238 if (Tape::LinearIndexHandling) {
239 // Value has been registered in createIndices.
240 value.getIdentifier() = index;
241
242 // In createIndices the primal value has been set to zero. So set now the correct value.
243 if (Tape::HasPrimalValues) {
244 getTape().setPrimal(index, value.getValue());
245 }
246 if (Tape::RequiresPrimalRestore) {
247 oldPrimal = PrimalType(0.0);
248 }
249 } else {
250 PrimalType primal = getTape().registerExternalFunctionOutput(value);
251 if (Tape::RequiresPrimalRestore) {
252 oldPrimal = primal;
253 }
254 index = value.getIdentifier();
255 }
256 } else {
257 if (Tape::RequiresPrimalRestore) {
258 oldPrimal = PrimalType(0.0);
259 }
260 if (!Tape::LinearIndexHandling) {
261 index = getTape().getPassiveIndex();
262 }
263 }
264 }
265
266 static CODI_INLINE_NO_FA void clearIndex(Type& value) {
267 IndexType oldIndex = value.getIdentifier();
268 value.~Type();
269 value.getIdentifier() = oldIndex; // Restore the index here so that the other side can decide of the
270 // communication was active or not.
271 }
272
273 static CODI_INLINE_NO_FA void createIndex(Type& value, IndexType& index) {
274 if (Tape::LinearIndexHandling) {
275 IndexType oldIndex = value.getIdentifier();
276 getTape().registerInput(value);
277 index = value.getIdentifier();
278 value.getIdentifier() = oldIndex; // Restore the index here so that the other side can decide of the
279 // communication was active or not.
280 }
281 }
282
283 static CODI_INLINE_NO_FA PrimalType getValue(Type const& value) {
284 return value.getValue();
285 }
286
287 static CODI_INLINE_NO_FA void setIntoModifyBuffer(ModifiedType& modValue, Type const& value) {
288 CODI_UNUSED(modValue, value);
289
290 // CoDiPack values are send in place. No modified buffer is crated.
291 }
292
293 static CODI_INLINE_NO_FA void getFromModifyBuffer(ModifiedType const& modValue, Type& value) {
294 CODI_UNUSED(modValue, value);
295
296 // CoDiPack values are send in place. No modified buffer is crated.
297 }
298
299 static PrimalType getPrimalFromMod(ModifiedType const& modValue) {
300 return modValue.value();
301 }
302
303 static void setPrimalToMod(ModifiedType& modValue, PrimalType const& value) {
304 modValue.value() = value;
305 }
306
307 static void modifyDependency(ModifiedType& inval, ModifiedType& inoutval) {
308 bool active = getTape().isIdentifierActive(inoutval.getIdentifier()) ||
309 getTape().isIdentifierActive(inval.getIdentifier());
310 if (active) {
311 inoutval.getIdentifier() = getTape().getInvalidIndex();
312 } else {
313 inoutval.getIdentifier() = getTape().getPassiveIndex();
314 }
315 }
316
317 private:
318
319 static void callHandleReverse(Tape* tape, void* h, VectorAccessInterface<PrimalType, IndexType>* ah) {
320 CODI_UNUSED(tape);
321
322 medi::HandleBase* handle = static_cast<medi::HandleBase*>(h);
323 CoDiMeDiAdjointInterfaceWrapper<Type> ahWrapper(ah);
324 handle->funcReverse(handle, &ahWrapper);
325 }
326
327 static void callHandleForward(Tape* tape, void* h, VectorAccessInterface<PrimalType, IndexType>* ah) {
328 CODI_UNUSED(tape);
329
330 medi::HandleBase* handle = static_cast<medi::HandleBase*>(h);
331 CoDiMeDiAdjointInterfaceWrapper<Type> ahWrapper(ah);
332 handle->funcForward(handle, &ahWrapper);
333 }
334
335 static void callHandlePrimal(Tape* tape, void* h, VectorAccessInterface<PrimalType, IndexType>* ah) {
336 CODI_UNUSED(tape);
337
338 medi::HandleBase* handle = static_cast<medi::HandleBase*>(h);
339 CoDiMeDiAdjointInterfaceWrapper<Type> ahWrapper(ah);
340 handle->funcPrimal(handle, &ahWrapper);
341 }
342
343 static void deleteHandle(Tape* tape, void* h) {
344 CODI_UNUSED(tape);
345
346 medi::HandleBase* handle = static_cast<medi::HandleBase*>(h);
347 delete handle;
348 }
349
350 static void callHandleIterateInputs(Tape* tape, void* h, IterCallback func, void* userData) {
351 CODI_UNUSED(tape);
352 #if MEDI_1_4_OR_GREATER
353 medi::HandleBase* handle = static_cast<medi::HandleBase*>(h);
354 handle->funcIterateInputIds(handle, (::medi::CallbackFunc)func, userData);
355 #else
356 CODI_UNUSED(h, func, userData);
357 CODI_EXCEPTION("Identifier iteration requires at leas MeDiPack 1.4.0.");
358 #endif
359 }
360
361 static void callHandleIterateOutputs(Tape* tape, void* h, IterCallback func, void* userData) {
362 CODI_UNUSED(tape);
363
364 #if MEDI_1_4_OR_GREATER
365 medi::HandleBase* handle = static_cast<medi::HandleBase*>(h);
366 handle->funcIterateOutputIds(handle, (::medi::CallbackFunc)func, userData);
367 #else
368 CODI_UNUSED(h, func, userData);
369 CODI_EXCEPTION("Identifier iteration requires at leas MeDiPack 1.4.0.");
370 #endif
371 }
372
373 static Tape& getTape() {
374 return Type::getTape();
375 }
376 };
377#endif
378}
#define CODI_INLINE_NO_FA
See codi::Config::ForcedInlines.
Definition config.h:471
#define CODI_DD(Type, Default)
Abbreviation for CODI_DECLARE_DEFAULT.
Definition macros.hpp:97
typename TraitsImplementation< Gradient >::Real Real
The base value used in the gradient entries.
Definition gradientTraits.hpp:92
inlinesize_t constexpr dim()
Number of dimensions this gradient value has.
Definition gradientTraits.hpp:96
inlinetypename DataExtraction< Type >::Real getValue(Type const &v)
Extract an aggregate of primal values from an aggregate of active types.
Definition realTraits.hpp:381
CoDiPack - Code Differentiation Package.
Definition codi.hpp:102
inlinevoid CODI_UNUSED(Args const &...)
Disable unused warnings for an arbitrary number of arguments.
Definition macros.hpp:55