deal.II version GIT relicensing-6834-g5b78e6bcdf 2026-10-01 11:20:01+00:00
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
ad_drivers.cc
Go to the documentation of this file.
1// -----------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception OR LGPL-2.1-or-later
4// Copyright (C) 2019 - 2026 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Detailed license information governing the source code and contributions
9// can be found in LICENSE.md and CONTRIBUTING.md at the top level directory.
10//
11// -----------------------------------------------------------------------------
12
13#include <deal.II/base/config.h>
14
15#if defined(DEAL_II_WITH_ADOLC) || defined(DEAL_II_TRILINOS_WITH_SACADO)
16
18# include <deal.II/base/types.h>
20
26
28# include <deal.II/lac/vector.h>
29
30# ifdef DEAL_II_WITH_ADOLC
31# include <adolc/adolc_fatalerror.h>
32# include <adolc/drivers/drivers.h>
33# include <adolc/taping.h>
34# endif // DEAL_II_WITH_ADOLC
35
36# include <vector>
37
38
39
40#endif // defined(DEAL_II_WITH_ADOLC) || defined(DEAL_II_TRILINOS_WITH_SACADO)
41
43
44#if defined(DEAL_II_WITH_ADOLC) || defined(DEAL_II_TRILINOS_WITH_SACADO)
45
46
47namespace Differentiation
48{
49 namespace AD
50 {
51 // ------------- TapedDrivers -------------
52
53
54 template <typename ADNumberType, typename ScalarType, typename T>
55 bool
61
62
63 template <typename ADNumberType, typename ScalarType, typename T>
70
71
72 template <typename ADNumberType, typename ScalarType, typename T>
73 bool
80
81
82 template <typename ADNumberType, typename ScalarType, typename T>
83 bool
89
90
91 template <typename ADNumberType, typename ScalarType, typename T>
92 void
101
102
103 template <typename ADNumberType, typename ScalarType, typename T>
104 void
111
112
113 template <typename ADNumberType, typename ScalarType, typename T>
114 void
121
122
123 template <typename ADNumberType, typename ScalarType, typename T>
124 std::vector<typename Types<ADNumberType>::tape_index>
126 const
127 {
129 return std::vector<typename Types<ADNumberType>::tape_index>();
130 }
131
132
133 template <typename ADNumberType, typename ScalarType, typename T>
134 void
140
141
142 template <typename ADNumberType, typename ScalarType, typename T>
143 bool
150
151
152 template <typename ADNumberType, typename ScalarType, typename T>
153 bool
160
161
162 template <typename ADNumberType, typename ScalarType, typename T>
163 void
170
171 template <typename ADNumberType, typename ScalarType, typename T>
172 void
177
178
179 template <typename ADNumberType, typename ScalarType, typename T>
180 void
185
186
187 template <typename ADNumberType, typename ScalarType, typename T>
188 void
195
196
197 template <typename ADNumberType, typename ScalarType, typename T>
198 ScalarType
200 const typename Types<ADNumberType>::tape_index,
201 const std::vector<ScalarType> &) const
202 {
204 return ScalarType(0.0);
205 }
206
207
208 template <typename ADNumberType, typename ScalarType, typename T>
209 void
211 const typename Types<ADNumberType>::tape_index,
212 const std::vector<ScalarType> &,
213 Vector<ScalarType> &) const
214 {
216 }
217
218
219 template <typename ADNumberType, typename ScalarType, typename T>
220 void
222 const typename Types<ADNumberType>::tape_index,
223 const std::vector<ScalarType> &,
225 {
227 }
228
229
230 template <typename ADNumberType, typename ScalarType, typename T>
231 void
233 const typename Types<ADNumberType>::tape_index,
234 const unsigned int,
235 const std::vector<ScalarType> &,
236 Vector<ScalarType> &) const
237 {
239 }
240
241
242 template <typename ADNumberType, typename ScalarType, typename T>
243 void
245 const typename Types<ADNumberType>::tape_index,
246 const unsigned int,
247 const std::vector<ScalarType> &,
249 {
251 }
252
253
254
255# ifdef DEAL_II_WITH_ADOLC
256
257# ifndef DOXYGEN
258 // Specialization for taped ADOL-C auto-differentiable numbers.
259
260 template <typename ADNumberType>
261 TapedDrivers<ADNumberType,
262 double,
263 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
264 NumberTypes::adolc_taped>>::TapedDrivers()
265 : active_tape(Numbers<ADNumberType>::invalid_tape_index)
266 , keep_values(true)
267 , is_recording_flag(false)
268 , use_stored_taped_buffer_sizes(false)
269 , obufsize(0u)
270 , lbufsize(0u)
271 , vbufsize(0u)
272 , tbufsize(0u)
273 {}
274# endif
275
276
277 template <typename ADNumberType>
278 bool
279 TapedDrivers<ADNumberType,
280 double,
281 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
282 NumberTypes::adolc_taped>>::is_recording()
283 const
284 {
285 return is_recording_flag;
286 }
287
288
289 template <typename ADNumberType>
291 TapedDrivers<
292 ADNumberType,
293 double,
294 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
295 NumberTypes::adolc_taped>>::active_tape_index() const
296 {
297 return active_tape;
298 }
299
300
301 template <typename ADNumberType>
302 bool
303 TapedDrivers<ADNumberType,
304 double,
305 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
307 keep_independent_values() const
308 {
309 return keep_values;
310 }
311
313 template <typename ADNumberType>
314 bool
315 TapedDrivers<ADNumberType,
316 double,
317 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
319 is_registered_tape(
320 const typename Types<ADNumberType>::tape_index tape_index) const
321 {
322 // Sigh... This is a mess :-/
323 // The most succinct way to get this piece of information, would be to
324 // use the getTapeInfos() function, but would come at the expense of
325 // creating an inactive tape data within ADOL-C's global store. For
326 // hints as to why this is the way it is, see the getTapeInfos()
327 // function in
328 // https://gitlab.com/adol-c/adol-c/blob/master/ADOL-C/src/tape_handling.cpp
329 // An alternative solution would be to manually access the tape data;
330 // see the removeTape() function in
331 // https://gitlab.com/adol-c/adol-c/blob/master/ADOL-C/src/tape_handling.cpp
332 // with the consideration of the #defines in
333 // https://gitlab.com/adol-c/adol-c/blob/master/ADOL-C/src/taping_p.h
334 // as to how this would be performed.
335 // Doing things "manually" (the second way) without creating the
336 // additional data object would be a lot more work...
337 //
338 // Both of the above solutions would be possible IF ADOL-C exposed
339 // this data object or a method to access it to the outside world.
340 // But they don't :-(
341 // Instead, what we'll have to do is get the statistics for this tape
342 // and make our own determination as to whether or not this tape exists.
343 // This effectively executes the first solution, with even more
344 // overhead! If the tape is in existence, we can assume that it should a
345 // non-zero number of dependent and independent variables. Those are
346 // stored in the zeroth and first entries of the statistics vector.
347 //
348 // But, oh wait... Surprise! This will trigger an error if the tape
349 // doesn't exist at all! So lets first check their tape info cache to
350 // see if the tape REALLY exists (i.e. has been touched, even if nothing
351 // has been written to it) before trying to access it. It'll only take
352 // an O(n) search, but at this point who really cares about efficiency?
353 //
354 // It has been suggested in
355 // https://gitlab.com/adol-c/adol-c/issues/11
356 // that a simply try-catch block around ::tapestats is the solution that
357 // we want here. Unfortunately this results in unwanted pollution of
358 // the terminal, of the form
359 // ADOL-C error: reading integer tape number 4!
360 // >>> File or directory not found! <<<
361 // , every time a query is made about a non-existent tape.
362 // So either way we have to guard that check with something more
363 // conservative so that we don't output useless messages for our users.
364 const std::vector<typename Types<ADNumberType>::tape_index>
365 registered_tape_indices = get_registered_tape_indices();
366 const auto it = std::find(registered_tape_indices.begin(),
367 registered_tape_indices.end(),
368 tape_index);
369 if (it == registered_tape_indices.end())
370 return false;
371
372 // See https://gitlab.com/adol-c/adol-c/issues/11#note_108341333
373 try
374 {
375 std::vector<std::size_t> counts(STAT_SIZE);
376 ::tapestats(tape_index, counts.data());
377 return true;
378 }
379 catch (const ::FatalError &exc)
380 {
381 return false;
382 }
383 }
384
386 template <typename ADNumberType>
387 void
388 TapedDrivers<ADNumberType,
389 double,
390 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
392 set_tape_buffer_sizes(
393 const typename Types<ADNumberType>::tape_buffer_sizes in_obufsize,
394 const typename Types<ADNumberType>::tape_buffer_sizes in_lbufsize,
395 const typename Types<ADNumberType>::tape_buffer_sizes in_vbufsize,
396 const typename Types<ADNumberType>::tape_buffer_sizes in_tbufsize)
397 {
398 // When valid for the chosen AD number type, these values will be used
399 // the next time start_recording_operations() is called.
400 obufsize = in_obufsize;
401 lbufsize = in_lbufsize;
402 vbufsize = in_vbufsize;
403 tbufsize = in_tbufsize;
404 use_stored_taped_buffer_sizes = true;
405 }
406
408 template <typename ADNumberType>
409 void
410 TapedDrivers<ADNumberType,
411 double,
412 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
414 start_taping(const typename Types<ADNumberType>::tape_index tape_index,
415 const bool keep_independent_values)
416 {
417 if (use_stored_taped_buffer_sizes)
418 trace_on(tape_index,
419 keep_independent_values,
420 obufsize,
421 lbufsize,
422 vbufsize,
423 tbufsize);
424 else
425 trace_on(tape_index, keep_independent_values);
426
427 // Set some other flags to their indicated / required values
428 keep_values = keep_independent_values;
429 is_recording_flag = true;
430 }
431
432
433 template <typename ADNumberType>
434 void
435 TapedDrivers<ADNumberType,
436 double,
437 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
439 stop_taping(
440 const typename Types<ADNumberType>::tape_index active_tape_index,
441 const bool write_tapes_to_file)
443 if (write_tapes_to_file)
444 trace_off(active_tape_index); // Slow
445 else
446 trace_off(); // Fast(er)
447
448 // Now that we've turned tracing off, we've definitely
449 // stopped all tape recording.
450 is_recording_flag = false;
451
452 // If the keep_values flag is set, then we expect the user to use this
453 // tape immediately after recording it. There is therefore no need to
454 // invalidate it. However, there is now also no way to double-check
455 // that the newly recorded tape is indeed the active tape.
456 if (keep_independent_values() == false)
458 }
459
460
461 template <typename ADNumberType>
462 std::vector<typename Types<ADNumberType>::tape_index>
463 TapedDrivers<ADNumberType,
464 double,
465 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
467 get_registered_tape_indices() const
468 {
469 // We've chosen to use unsigned shorts for the tape
470 // index type (a safety precaution) so we need to
471 // perform a conversion between ADOL-C's native tape
472 // index type and that chosen by us.
473 std::vector<short> registered_tape_indices_s;
474 cachedTraceTags(registered_tape_indices_s);
475
476 return std::vector<typename Types<ADNumberType>::tape_index>(
477 registered_tape_indices_s.begin(), registered_tape_indices_s.end());
478 }
479
480
481 template <typename ADNumberType>
482 void
483 TapedDrivers<ADNumberType,
484 double,
485 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
487 activate_tape(const typename Types<ADNumberType>::tape_index tape_index)
488 {
489 active_tape = tape_index;
491
492
493 template <typename ADNumberType>
494 bool
495 TapedDrivers<ADNumberType,
496 double,
497 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
499 requires_retaping(
500 const typename Types<ADNumberType>::tape_index tape_index) const
501 {
502 Assert(
503 is_registered_tape(tape_index) == true,
505 "Cannot ask for the status of a tape that has not yet been recorded and used."));
506
507 const auto it_status_tape = status.find(tape_index);
508
509 // This tape's status has not been found in the map. This could be
510 // because a non-existent tape_index has been used as an argument, or
511 // because the tape exists but has not been used (in a way that
512 // initiated a status update). For example, on can create a tape in one
513 // section of code and then query the status of all existing tapes in a
514 // completely different section of code that knows nothing about the
515 // first tape. There is no prerequisite that the first tape is ever
516 // used, and it can therefore not have a status. So, in this case
517 // there's not much we can do other than to report that the tape does
518 // not require retaping.
519 if (it_status_tape == status.end())
520 return false;
521
522 const auto status_tape = it_status_tape->second;
523
524 // See ADOL-C manual section 1.7 and comments in last paragraph of
525 // section 3.1
526 Assert(
527 status_tape < 4 && status_tape >= -2,
529 "The tape status is not within the range specified within the ADOL-C documentation."));
530 return (status_tape < 0);
531 }
532
533
534 template <typename ADNumberType>
535 bool
536 TapedDrivers<ADNumberType,
537 double,
538 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
540 last_action_requires_retaping() const
541 {
542 return requires_retaping(active_tape);
543 }
544
546 template <typename ADNumberType>
547 void
548 TapedDrivers<ADNumberType,
549 double,
550 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
552 remove_tape(const typename Types<ADNumberType>::tape_index tape_index)
553 {
554 Assert(is_registered_tape(tape_index),
556 "This tape does not exist, and therefore cannot be cleared."));
557 removeTape(tape_index, TapeRemovalType::ADOLC_REMOVE_COMPLETELY);
558 }
560
561 template <typename ADNumberType>
562 void
563 TapedDrivers<ADNumberType,
564 double,
565 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
567 reset(const bool clear_registered_tapes)
568 {
570 is_recording_flag = false;
571 status.clear();
572 if (clear_registered_tapes)
574 const std::vector<typename Types<ADNumberType>::tape_index>
575 registered_tape_indices = get_registered_tape_indices();
576 for (const auto &tape_index : registered_tape_indices)
577 remove_tape(tape_index);
578 }
579 }
580
581
582 template <typename ADNumberType>
583 void
584 TapedDrivers<ADNumberType,
585 double,
586 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
587 NumberTypes::adolc_taped>>::print(std::ostream
588 &stream)
589 const
590 {
591 const std::vector<typename Types<ADNumberType>::tape_index>
592 registered_tape_indices = get_registered_tape_indices();
593 stream << "Registered tapes and their status: ";
594 auto it_registered_tape = registered_tape_indices.begin();
595 for (unsigned int i = 0; i < registered_tape_indices.size();
596 ++i, ++it_registered_tape)
597 {
598 const auto tape_index = *it_registered_tape;
599 const auto it_status_tape = status.find(tape_index);
600 Assert(it_status_tape != status.end(),
602 "This tape's status has not been found in the map."));
603 const auto status_tape = it_status_tape->second;
604
605 stream << tape_index << "->" << status_tape
606 << (i < (registered_tape_indices.size() - 1) ? "," : "");
608 stream << '\n';
609
610 stream << "Keep values? " << keep_independent_values() << '\n';
611 stream << "Use stored tape buffer sizes? "
612 << use_stored_taped_buffer_sizes << '\n';
613 }
614
615
616 template <typename ADNumberType>
617 void
618 TapedDrivers<ADNumberType,
619 double,
620 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
622 print_tape_stats(
623 const typename Types<ADNumberType>::tape_index tape_index,
624 std::ostream &stream) const
626 // See ADOL-C manual section 2.1
627 // and adolc/taping.h
628 std::vector<std::size_t> counts(STAT_SIZE);
629 ::tapestats(tape_index, counts.data());
630 Assert(counts.size() >= 18, ExcInternalError());
631 stream
632 << "Tape index: " << tape_index << '\n'
633 << "Number of independent variables: " << counts[0] << '\n'
634 << "Number of dependent variables: " << counts[1] << '\n'
635 << "Max number of live, active variables: " << counts[2] << '\n'
636 << "Size of taylor stack (number of overwrites): " << counts[3] << '\n'
637 << "Operations buffer size: " << counts[4] << '\n'
638 << "Total number of recorded operations: " << counts[5] << '\n'
639 << "Operations file written or not: " << counts[6] << '\n'
640 << "Overall number of locations: " << counts[7] << '\n'
641 << "Locations file written or not: " << counts[8] << '\n'
642 << "Overall number of values: " << counts[9] << '\n'
643 << "Values file written or not: " << counts[10] << '\n'
644 << "Locations buffer size: " << counts[11] << '\n'
645 << "Values buffer size: " << counts[12] << '\n'
646 << "Taylor buffer size: " << counts[13] << '\n'
647 << "Number of eq_*_prod for sparsity pattern: " << counts[14] << '\n'
648 << "Use of 'min_op', deferred to 'abs_op' for piecewise calculations: "
649 << counts[15] << '\n'
650 << "Number of 'abs' calls that can switch branch: " << counts[16]
651 << '\n'
652 << "Number of parameters (doubles) interchangeable without retaping: "
653 << counts[17] << '\n'
654 << std::flush;
655 }
656
657
658 template <typename ADNumberType>
659 typename TapedDrivers<
660 ADNumberType,
661 double,
662 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
663 NumberTypes::adolc_taped>>::scalar_type
664 TapedDrivers<ADNumberType,
665 double,
666 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
668 value(const typename Types<ADNumberType>::tape_index active_tape_index,
669 const std::vector<scalar_type> &independent_variables) const
670 {
671 Assert(is_registered_tape(active_tape_index),
672 ExcMessage("This tape has not yet been recorded."));
673
674 scalar_type value = 0.0;
675
676 status[active_tape_index] =
677 ::function(active_tape_index,
678 1, // Only one dependent variable
679 independent_variables.size(),
680 const_cast<double *>(independent_variables.data()),
681 &value);
682
683 return value;
684 }
685
686
687 template <typename ADNumberType>
688 void
689 TapedDrivers<ADNumberType,
690 double,
691 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
693 gradient(const typename Types<ADNumberType>::tape_index active_tape_index,
694 const std::vector<scalar_type> &independent_variables,
695 Vector<scalar_type> &gradient) const
696 {
698 1,
701 1));
702 Assert(gradient.size() == independent_variables.size(),
703 ExcDimensionMismatch(gradient.size(),
704 independent_variables.size()));
705 Assert(is_registered_tape(active_tape_index),
706 ExcMessage("This tape has not yet been recorded."));
707
708 // Note: ADOL-C's ::gradient function expects a *double as the last
709 // parameter. Here we take advantage of the fact that the data in the
710 // Vector class is aligned (e.g. stored as an Array)
711 status[active_tape_index] =
712 ::gradient(active_tape_index,
713 independent_variables.size(),
714 const_cast<scalar_type *>(independent_variables.data()),
715 gradient.data());
716 }
717
718
719 template <typename ADNumberType>
720 void
721 TapedDrivers<ADNumberType,
722 double,
723 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
725 hessian(const typename Types<ADNumberType>::tape_index active_tape_index,
726 const std::vector<scalar_type> &independent_variables,
727 FullMatrix<scalar_type> &hessian) const
728 {
730 2,
733 2));
734 Assert(hessian.m() == independent_variables.size(),
735 ExcDimensionMismatch(hessian.m(), independent_variables.size()));
736 Assert(hessian.n() == independent_variables.size(),
737 ExcDimensionMismatch(hessian.n(), independent_variables.size()));
738 Assert(is_registered_tape(active_tape_index),
739 ExcMessage("This tape has not yet been recorded."));
740
741 const unsigned int n_independent_variables = independent_variables.size();
742 std::vector<scalar_type *> H(n_independent_variables);
743 for (unsigned int i = 0; i < n_independent_variables; ++i)
744 H[i] = &hessian[i][0];
745
746 status[active_tape_index] =
747 ::hessian(active_tape_index,
748 n_independent_variables,
749 const_cast<scalar_type *>(independent_variables.data()),
750 H.data());
751
752 // ADOL-C builds only the lower-triangular part of the
753 // symmetric Hessian, so we should copy the relevant
754 // entries into the upper triangular part.
755 for (unsigned int i = 0; i < n_independent_variables; ++i)
756 for (unsigned int j = 0; j < i; ++j)
757 hessian[j][i] = hessian[i][j]; // Symmetry
758 }
759
760
761 template <typename ADNumberType>
762 void
763 TapedDrivers<ADNumberType,
764 double,
765 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
767 values(const typename Types<ADNumberType>::tape_index active_tape_index,
768 const unsigned int n_dependent_variables,
769 const std::vector<scalar_type> &independent_variables,
770 Vector<scalar_type> &values) const
771 {
772 Assert(values.size() == n_dependent_variables,
773 ExcDimensionMismatch(values.size(), n_dependent_variables));
774 Assert(is_registered_tape(active_tape_index),
775 ExcMessage("This tape has not yet been recorded."));
776
777 // Note: ADOL-C's ::function function expects a *double as the last
778 // parameter. Here we take advantage of the fact that the data in the
779 // Vector class is aligned (e.g. stored as an Array)
780 status[active_tape_index] =
781 ::function(active_tape_index,
782 n_dependent_variables,
783 independent_variables.size(),
784 const_cast<scalar_type *>(independent_variables.data()),
785 values.data());
786 }
787
788
789 template <typename ADNumberType>
790 void
791 TapedDrivers<ADNumberType,
792 double,
793 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
795 jacobian(const typename Types<ADNumberType>::tape_index active_tape_index,
796 const unsigned int n_dependent_variables,
797 const std::vector<scalar_type> &independent_variables,
798 FullMatrix<scalar_type> &jacobian) const
799 {
800 Assert(AD::ADNumberTraits<ADNumberType>::n_supported_derivative_levels >=
801 1,
803 AD::ADNumberTraits<ADNumberType>::n_supported_derivative_levels,
804 1));
805 Assert(jacobian.m() == n_dependent_variables,
806 ExcDimensionMismatch(jacobian.m(), n_dependent_variables));
807 Assert(jacobian.n() == independent_variables.size(),
808 ExcDimensionMismatch(jacobian.n(), independent_variables.size()));
809 Assert(is_registered_tape(active_tape_index),
810 ExcMessage("This tape has not yet been recorded."));
811
812 std::vector<scalar_type *> J(n_dependent_variables);
813 for (unsigned int i = 0; i < n_dependent_variables; ++i)
814 J[i] = &jacobian[i][0];
815
816 status[active_tape_index] = ::jacobian(active_tape_index,
817 n_dependent_variables,
818 independent_variables.size(),
819 independent_variables.data(),
820 J.data());
821 }
822
823# else
824
825 // Specialization for taped ADOL-C auto-differentiable numbers.
826
827 template <typename ADNumberType>
828 bool
829 TapedDrivers<ADNumberType,
830 double,
831 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
832 NumberTypes::adolc_taped>>::is_recording()
833 const
834 {
836 return false;
837 }
838
839
840 template <typename ADNumberType>
842 TapedDrivers<
843 ADNumberType,
844 double,
845 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
846 NumberTypes::adolc_taped>>::active_tape_index() const
847 {
850 }
851
852
853 template <typename ADNumberType>
854 bool
855 TapedDrivers<ADNumberType,
856 double,
857 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
859 keep_independent_values() const
860 {
862 return false;
863 }
864
865
866 template <typename ADNumberType>
867 bool
868 TapedDrivers<ADNumberType,
869 double,
870 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
872 is_registered_tape(const typename Types<ADNumberType>::tape_index) const
873 {
875 return false;
876 }
877
878
879 template <typename ADNumberType>
880 void
881 TapedDrivers<ADNumberType,
882 double,
883 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
885 set_tape_buffer_sizes(
890 {
892 }
893
894
895 template <typename ADNumberType>
896 void
897 TapedDrivers<ADNumberType,
898 double,
899 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
901 start_taping(const typename Types<ADNumberType>::tape_index, const bool)
902 {
904 }
905
906
907 template <typename ADNumberType>
908 void
909 TapedDrivers<ADNumberType,
910 double,
911 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
913 stop_taping(const typename Types<ADNumberType>::tape_index, const bool)
914 {
916 }
917
918
919 template <typename ADNumberType>
920 std::vector<typename Types<ADNumberType>::tape_index>
921 TapedDrivers<ADNumberType,
922 double,
923 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
925 get_registered_tape_indices() const
926 {
928 return std::vector<typename Types<ADNumberType>::tape_index>();
929 }
930
931
932 template <typename ADNumberType>
933 void
934 TapedDrivers<ADNumberType,
935 double,
936 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
938 activate_tape(const typename Types<ADNumberType>::tape_index)
939 {
941 }
942
943
944 template <typename ADNumberType>
945 bool
946 TapedDrivers<ADNumberType,
947 double,
948 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
950 requires_retaping(const typename Types<ADNumberType>::tape_index) const
951 {
953 return false;
954 }
955
956
957 template <typename ADNumberType>
958 bool
959 TapedDrivers<ADNumberType,
960 double,
961 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
963 last_action_requires_retaping() const
964 {
966 return false;
967 }
968
969
970 template <typename ADNumberType>
971 void
972 TapedDrivers<ADNumberType,
973 double,
974 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
976 remove_tape(const typename Types<ADNumberType>::tape_index)
977 {
979 }
980
981
982 template <typename ADNumberType>
983 void
984 TapedDrivers<ADNumberType,
985 double,
986 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
987 NumberTypes::adolc_taped>>::reset(const bool)
988 {
990 }
991
992
993 template <typename ADNumberType>
994 void
995 TapedDrivers<ADNumberType,
996 double,
997 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
998 NumberTypes::adolc_taped>>::print(std::ostream
999 &) const
1000 {
1001 AssertThrow(false, ExcRequiresADOLC());
1002 }
1003
1004
1005 template <typename ADNumberType>
1006 void
1007 TapedDrivers<ADNumberType,
1008 double,
1009 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
1011 print_tape_stats(const typename Types<ADNumberType>::tape_index,
1012 std::ostream &) const
1013 {
1014 AssertThrow(false, ExcRequiresADOLC());
1015 }
1016
1017
1018 template <typename ADNumberType>
1019 typename TapedDrivers<
1020 ADNumberType,
1021 double,
1022 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
1023 NumberTypes::adolc_taped>>::scalar_type
1024 TapedDrivers<ADNumberType,
1025 double,
1026 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
1028 value(const typename Types<ADNumberType>::tape_index,
1029 const std::vector<scalar_type> &) const
1030 {
1031 AssertThrow(false, ExcRequiresADOLC());
1032 return 0.0;
1033 }
1034
1035
1036 template <typename ADNumberType>
1037 void
1038 TapedDrivers<ADNumberType,
1039 double,
1040 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
1042 gradient(const typename Types<ADNumberType>::tape_index,
1043 const std::vector<scalar_type> &,
1044 Vector<scalar_type> &) const
1045 {
1046 AssertThrow(false, ExcRequiresADOLC());
1047 }
1048
1049
1050 template <typename ADNumberType>
1051 void
1052 TapedDrivers<ADNumberType,
1053 double,
1054 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
1056 hessian(const typename Types<ADNumberType>::tape_index,
1057 const std::vector<scalar_type> &,
1059 {
1060 AssertThrow(false, ExcRequiresADOLC());
1061 }
1062
1063
1064 template <typename ADNumberType>
1065 void
1066 TapedDrivers<ADNumberType,
1067 double,
1068 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
1070 values(const typename Types<ADNumberType>::tape_index,
1071 const unsigned int,
1072 const std::vector<scalar_type> &,
1073 Vector<scalar_type> &) const
1074 {
1075 AssertThrow(false, ExcRequiresADOLC());
1076 }
1077
1078
1079 template <typename ADNumberType>
1080 void
1081 TapedDrivers<ADNumberType,
1082 double,
1083 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
1085 jacobian(const typename Types<ADNumberType>::tape_index,
1086 const unsigned int,
1087 const std::vector<scalar_type> &,
1089 {
1090 AssertThrow(false, ExcRequiresADOLC());
1091 }
1092
1093# endif // DEAL_II_WITH_ADOLC
1094
1095
1096 // Specialization for ADOL-C taped numbers. It is expected that the
1097 // scalar return type for this class is a float.
1098
1099 template <typename ADNumberType>
1100 bool
1101 TapedDrivers<ADNumberType,
1102 float,
1103 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
1104 NumberTypes::adolc_taped>>::is_recording()
1105 const
1106 {
1107 // ADOL-C only supports 'double', not 'float', so we can forward to
1108 // the 'double' implementation of this function
1109 return taped_driver.is_recording();
1110 }
1111
1112
1113 template <typename ADNumberType>
1115 TapedDrivers<
1116 ADNumberType,
1117 float,
1118 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
1119 NumberTypes::adolc_taped>>::active_tape_index() const
1120 {
1121 // ADOL-C only supports 'double', not 'float', so we can forward to
1122 // the 'double' implementation of this function
1123 return taped_driver.active_tape_index();
1124 }
1125
1126
1127 template <typename ADNumberType>
1128 bool
1129 TapedDrivers<ADNumberType,
1130 float,
1131 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
1133 keep_independent_values() const
1134 {
1135 return taped_driver.keep_independent_values();
1136 }
1137
1138
1139 template <typename ADNumberType>
1140 bool
1141 TapedDrivers<ADNumberType,
1142 float,
1143 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
1145 is_registered_tape(
1146 const typename Types<ADNumberType>::tape_index tape_index) const
1147 {
1148 // ADOL-C only supports 'double', not 'float', so we can forward to
1149 // the 'double' implementation of this function
1150 return taped_driver.is_registered_tape(tape_index);
1151 }
1152
1153
1154 template <typename ADNumberType>
1155 void
1156 TapedDrivers<ADNumberType,
1157 float,
1158 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
1160 set_tape_buffer_sizes(
1161 const typename Types<ADNumberType>::tape_buffer_sizes obufsize,
1162 const typename Types<ADNumberType>::tape_buffer_sizes lbufsize,
1163 const typename Types<ADNumberType>::tape_buffer_sizes vbufsize,
1164 const typename Types<ADNumberType>::tape_buffer_sizes tbufsize)
1165 {
1166 // ADOL-C only supports 'double', not 'float', so we can forward to
1167 // the 'double' implementation of this function
1168 taped_driver.set_tape_buffer_sizes(obufsize,
1169 lbufsize,
1170 vbufsize,
1171 tbufsize);
1172 }
1173
1174
1175 template <typename ADNumberType>
1176 void
1177 TapedDrivers<ADNumberType,
1178 float,
1179 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
1181 start_taping(const typename Types<ADNumberType>::tape_index tape_index,
1182 const bool keep_independent_values)
1183 {
1184 // ADOL-C only supports 'double', not 'float', so we can forward to
1185 // the 'double' implementation of this function
1186 taped_driver.start_taping(tape_index, keep_independent_values);
1187 }
1188
1189
1190 template <typename ADNumberType>
1191 void
1192 TapedDrivers<ADNumberType,
1193 float,
1194 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
1196 stop_taping(
1197 const typename Types<ADNumberType>::tape_index active_tape_index,
1198 const bool write_tapes_to_file)
1199 {
1200 // ADOL-C only supports 'double', not 'float', so we can forward to
1201 // the 'double' implementation of this function
1202 taped_driver.stop_taping(active_tape_index, write_tapes_to_file);
1203 }
1204
1205
1206 template <typename ADNumberType>
1207 std::vector<typename Types<ADNumberType>::tape_index>
1208 TapedDrivers<ADNumberType,
1209 float,
1210 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
1212 get_registered_tape_indices() const
1213 {
1214 return taped_driver.get_registered_tape_indices();
1215 }
1216
1217
1218 template <typename ADNumberType>
1219 void
1220 TapedDrivers<ADNumberType,
1221 float,
1222 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
1224 activate_tape(const typename Types<ADNumberType>::tape_index tape_index)
1225 {
1226 taped_driver.activate_tape(tape_index);
1227 }
1228
1229
1230 template <typename ADNumberType>
1231 bool
1232 TapedDrivers<ADNumberType,
1233 float,
1234 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
1236 requires_retaping(
1237 const typename Types<ADNumberType>::tape_index tape_index) const
1238 {
1239 return taped_driver.requires_retaping(tape_index);
1240 }
1241
1242
1243 template <typename ADNumberType>
1244 bool
1245 TapedDrivers<ADNumberType,
1246 float,
1247 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
1249 last_action_requires_retaping() const
1250 {
1251 return taped_driver.last_action_requires_retaping();
1252 }
1253
1254
1255 template <typename ADNumberType>
1256 void
1257 TapedDrivers<ADNumberType,
1258 float,
1259 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
1261 remove_tape(const typename Types<ADNumberType>::tape_index tape_index)
1262 {
1263 taped_driver.remove_tape(tape_index);
1264 }
1265
1266
1267 template <typename ADNumberType>
1268 void
1269 TapedDrivers<ADNumberType,
1270 float,
1271 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
1273 reset(const bool clear_registered_tapes)
1274 {
1275 taped_driver.reset(clear_registered_tapes);
1276 }
1277
1278
1279 template <typename ADNumberType>
1280 void
1281 TapedDrivers<ADNumberType,
1282 float,
1283 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
1284 NumberTypes::adolc_taped>>::print(std::ostream
1285 &stream)
1286 const
1287 {
1288 taped_driver.print(stream);
1289 }
1290
1291
1292 template <typename ADNumberType>
1293 void
1294 TapedDrivers<ADNumberType,
1295 float,
1296 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
1298 print_tape_stats(
1299 const typename Types<ADNumberType>::tape_index tape_index,
1300 std::ostream &stream) const
1301 {
1302 // ADOL-C only supports 'double', not 'float', so we can forward to
1303 // the 'double' implementation of this function
1304 taped_driver.print_tape_stats(tape_index, stream);
1305 }
1306
1307
1308 template <typename ADNumberType>
1309 typename TapedDrivers<
1310 ADNumberType,
1311 float,
1312 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
1313 NumberTypes::adolc_taped>>::scalar_type
1314 TapedDrivers<ADNumberType,
1315 float,
1316 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
1318 value(const typename Types<ADNumberType>::tape_index active_tape_index,
1319 const std::vector<scalar_type> &independent_variables) const
1320 {
1321 // ADOL-C only supports 'double', not 'float', so we can forward to
1322 // the 'double' implementation of this function
1323 return taped_driver.value(active_tape_index,
1324 vector_float_to_double(independent_variables));
1325 }
1326
1327
1328 template <typename ADNumberType>
1329 void
1330 TapedDrivers<ADNumberType,
1331 float,
1332 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
1334 gradient(const typename Types<ADNumberType>::tape_index active_tape_index,
1335 const std::vector<scalar_type> &independent_variables,
1336 Vector<scalar_type> &gradient) const
1337 {
1338 Vector<double> gradient_double(gradient.size());
1339 // ADOL-C only supports 'double', not 'float', so we can forward to
1340 // the 'double' implementation of this function
1341 taped_driver.gradient(active_tape_index,
1342 vector_float_to_double(independent_variables),
1343 gradient_double);
1344 gradient = gradient_double;
1345 }
1346
1347
1348 template <typename ADNumberType>
1349 void
1350 TapedDrivers<ADNumberType,
1351 float,
1352 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
1354 hessian(const typename Types<ADNumberType>::tape_index active_tape_index,
1355 const std::vector<scalar_type> &independent_variables,
1356 FullMatrix<scalar_type> &hessian) const
1357 {
1358 FullMatrix<double> hessian_double(hessian.m(), hessian.n());
1359 // ADOL-C only supports 'double', not 'float', so we can forward to
1360 // the 'double' implementation of this function
1361 taped_driver.hessian(active_tape_index,
1362 vector_float_to_double(independent_variables),
1363 hessian_double);
1364 hessian = hessian_double;
1365 }
1366
1367
1368 template <typename ADNumberType>
1369 void
1370 TapedDrivers<ADNumberType,
1371 float,
1372 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
1374 values(const typename Types<ADNumberType>::tape_index active_tape_index,
1375 const unsigned int n_dependent_variables,
1376 const std::vector<scalar_type> &independent_variables,
1377 Vector<scalar_type> &values) const
1378 {
1379 Vector<double> values_double(values.size());
1380 // ADOL-C only supports 'double', not 'float', so we can forward to
1381 // the 'double' implementation of this function
1382 taped_driver.values(active_tape_index,
1383 n_dependent_variables,
1384 vector_float_to_double(independent_variables),
1385 values_double);
1386 values = values_double;
1387 }
1388
1389
1390 template <typename ADNumberType>
1391 void
1392 TapedDrivers<ADNumberType,
1393 float,
1394 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
1396 jacobian(const typename Types<ADNumberType>::tape_index active_tape_index,
1397 const unsigned int n_dependent_variables,
1398 const std::vector<scalar_type> &independent_variables,
1399 FullMatrix<scalar_type> &jacobian) const
1400 {
1401 FullMatrix<double> jacobian_double(jacobian.m(), jacobian.n());
1402 // ADOL-C only supports 'double', not 'float', so we can forward to
1403 // the 'double' implementation of this function
1404 taped_driver.jacobian(active_tape_index,
1405 n_dependent_variables,
1406 vector_float_to_double(independent_variables),
1407 jacobian_double);
1408 jacobian = jacobian_double;
1409 }
1410
1411
1412# ifndef DOXYGEN
1413 template <typename ADNumberType>
1414 std::vector<double>
1415 TapedDrivers<ADNumberType,
1416 float,
1417 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
1419 vector_float_to_double(const std::vector<float> &in) const
1420 {
1421 std::vector<double> out(in.size());
1422 std::copy(in.begin(), in.end(), out.begin());
1423 return out;
1424 }
1425# endif
1426
1427
1428 // ------------- TapelessDrivers -------------
1429
1430
1431 template <typename ADNumberType, typename ScalarType, typename T>
1432 void
1438
1439 template <typename ADNumberType, typename ScalarType, typename T>
1440 void
1446
1447 template <typename ADNumberType, typename ScalarType, typename T>
1448 void
1454
1455 template <typename ADNumberType, typename ScalarType, typename T>
1456 bool
1463
1464
1465 template <typename ADNumberType, typename ScalarType, typename T>
1466 ScalarType
1468 const std::vector<ADNumberType> &) const
1469 {
1471 return ScalarType(0.0);
1472 }
1473
1474
1475 template <typename ADNumberType, typename ScalarType, typename T>
1476 void
1478 const std::vector<ADNumberType> &,
1479 const std::vector<ADNumberType> &,
1480 Vector<ScalarType> &) const
1481 {
1483 }
1484
1485
1486 template <typename ADNumberType, typename ScalarType, typename T>
1487 void
1489 const std::vector<ADNumberType> &,
1490 const std::vector<ADNumberType> &,
1491 FullMatrix<ScalarType> &) const
1492 {
1494 }
1495
1496
1497 template <typename ADNumberType, typename ScalarType, typename T>
1498 void
1500 const std::vector<ADNumberType> &,
1501 Vector<ScalarType> &) const
1502 {
1504 }
1505
1506
1507 template <typename ADNumberType, typename ScalarType, typename T>
1508 void
1510 const std::vector<ADNumberType> &,
1511 const std::vector<ADNumberType> &,
1512 FullMatrix<ScalarType> &) const
1513 {
1515 }
1516
1517
1518 namespace internal
1519 {
1524 template <typename ADNumberType>
1525 std::enable_if_t<!(ADNumberTraits<ADNumberType>::type_code ==
1531
1532# ifdef DEAL_II_TRILINOS_WITH_SACADO
1533
1534
1543 template <typename ADNumberType>
1544 std::enable_if_t<
1548 ADNumberType &dependent_variable)
1549 {
1550 // Compute all gradients (adjoints) for this
1551 // reverse-mode Sacado dependent variable.
1552 // For reverse-mode Sacado numbers it is necessary to broadcast to
1553 // all independent variables that it is time to compute gradients.
1554 // For one dependent variable one would just need to call
1555 // ADNumberType::Gradcomp(), but since we have a more
1556 // generic implementation for vectors of dependent variables
1557 // (vector mode) we default to the complex case.
1558 ADNumberType::Outvar_Gradcomp(dependent_variable);
1559 }
1560
1561# endif
1562
1563
1568 template <typename ADNumberType>
1569 std::enable_if_t<!(ADNumberTraits<ADNumberType>::type_code ==
1571 configure_tapeless_mode(const unsigned int)
1572 {}
1573
1574
1575# ifdef DEAL_II_WITH_ADOLC
1576
1577
1585 template <typename ADNumberType>
1586 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
1588 configure_tapeless_mode(const unsigned int n_directional_derivatives)
1589 {
1590# ifdef DEAL_II_ADOLC_WITH_TAPELESS_REFCOUNTING
1591 // See ADOL-C manual section 7.1
1592 //
1593 // NOTE: It is critical that this is done for tapeless mode BEFORE
1594 // any adtl::adouble are created. If this is not done, then we see
1595 // this scary warning:
1596 //
1597 // "
1598 // ADOL-C Warning: Tapeless: Setting numDir could change memory
1599 // allocation of derivatives in existing adoubles and may lead to
1600 // erroneous results or memory corruption
1601 // "
1602 //
1603 // So we use this dummy function to configure this setting before
1604 // we create and initialize our class data
1605 const std::size_t n_live_variables = adtl::refcounter::getNumLiveVar();
1606 if (n_live_variables == 0)
1607 {
1608 adtl::setNumDir(n_directional_derivatives);
1609 }
1610 else
1611 {
1612 // So there are some live active variables floating around. Here we
1613 // check if we ask to increase the number of computable
1614 // directional derivatives. If this really is necessary then it's
1615 // absolutely vital that there exist no live variables before doing
1616 // so.
1617 const std::size_t n_set_directional_derivatives = adtl::getNumDir();
1618 if (n_directional_derivatives > n_set_directional_derivatives)
1620 n_live_variables == 0,
1621 ExcMessage(
1622 "There are currently " + std::to_string(n_live_variables) +
1623 " live "
1624 "adtl::adouble variables in existence. They currently "
1625 "assume " +
1626 std::to_string(n_set_directional_derivatives) +
1627 " directional derivatives "
1628 "but you wish to increase this to " +
1629 std::to_string(n_directional_derivatives) +
1630 ". \n"
1631 "To safely change (or more specifically in this case, "
1632 "increase) the number of directional derivatives, there "
1633 "must be no tapeless doubles in local/global scope."));
1634 }
1635# else
1636 // If ADOL-C is not configured with tapeless number reference counting
1637 // then there is no way that we can guarantee that the following call
1638 // is safe. No comment... :-/
1639 adtl::setNumDir(n_directional_derivatives);
1640# endif
1641 }
1642
1643# else // DEAL_II_WITH_ADOLC
1644
1645 template <typename ADNumberType>
1646 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
1648 configure_tapeless_mode(const unsigned int /*n_directional_derivatives*/)
1649 {
1650 AssertThrow(false, ExcRequiresADOLC());
1651 }
1652
1653# endif
1654
1655 } // namespace internal
1656
1657
1658
1659 // Specialization for auto-differentiable numbers that use
1660 // reverse mode to compute the first derivatives (and, if supported,
1661 // forward mode for the second).
1662
1663# ifndef DOXYGEN
1664 template <typename ADNumberType, typename ScalarType>
1665 TapelessDrivers<
1666 ADNumberType,
1667 ScalarType,
1668 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
1670 ADNumberTraits<ADNumberType>::type_code ==
1671 NumberTypes::sacado_rad_dfad>>::TapelessDrivers()
1672 : dependent_variable_marking_safe(false)
1673 {}
1674# endif
1675
1676
1677 template <typename ADNumberType, typename ScalarType>
1678 void
1679 TapelessDrivers<ADNumberType,
1680 ScalarType,
1681 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
1683 ADNumberTraits<ADNumberType>::type_code ==
1685 initialize_global_environment(const unsigned int n_independent_variables)
1686 {
1687 internal::configure_tapeless_mode<ADNumberType>(n_independent_variables);
1688 }
1689
1690
1691 template <typename ADNumberType, typename ScalarType>
1692 void
1693 TapelessDrivers<
1694 ADNumberType,
1695 ScalarType,
1696 std::enable_if_t<
1697 ADNumberTraits<ADNumberType>::type_code == NumberTypes::sacado_rad ||
1698 ADNumberTraits<ADNumberType>::type_code ==
1699 NumberTypes::sacado_rad_dfad>>::allow_dependent_variable_marking()
1700 {
1701 dependent_variable_marking_safe = true;
1702 }
1703
1704
1705 template <typename ADNumberType, typename ScalarType>
1706 void
1707 TapelessDrivers<
1708 ADNumberType,
1709 ScalarType,
1710 std::enable_if_t<
1711 ADNumberTraits<ADNumberType>::type_code == NumberTypes::sacado_rad ||
1712 ADNumberTraits<ADNumberType>::type_code ==
1713 NumberTypes::sacado_rad_dfad>>::prevent_dependent_variable_marking()
1714 {
1715 dependent_variable_marking_safe = false;
1716 }
1717
1718
1719 template <typename ADNumberType, typename ScalarType>
1720 bool
1721 TapelessDrivers<ADNumberType,
1722 ScalarType,
1723 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
1725 ADNumberTraits<ADNumberType>::type_code ==
1727 is_dependent_variable_marking_allowed() const
1728 {
1729 return dependent_variable_marking_safe;
1730 }
1731
1732
1733 template <typename ADNumberType, typename ScalarType>
1734 ScalarType
1735 TapelessDrivers<ADNumberType,
1736 ScalarType,
1737 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
1739 ADNumberTraits<ADNumberType>::type_code ==
1741 value(const std::vector<ADNumberType> &dependent_variables) const
1742 {
1743 Assert(dependent_variables.size() == 1,
1744 ExcDimensionMismatch(dependent_variables.size(), 1));
1745 return ADNumberTraits<ADNumberType>::get_scalar_value(
1746 dependent_variables[0]);
1747 }
1748
1749
1750 template <typename ADNumberType, typename ScalarType>
1751 void
1752 TapelessDrivers<ADNumberType,
1753 ScalarType,
1754 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
1756 ADNumberTraits<ADNumberType>::type_code ==
1758 gradient(const std::vector<ADNumberType> &independent_variables,
1759 const std::vector<ADNumberType> &dependent_variables,
1760 Vector<ScalarType> &gradient) const
1761 {
1762 Assert(AD::ADNumberTraits<ADNumberType>::n_supported_derivative_levels >=
1763 1,
1765 AD::ADNumberTraits<ADNumberType>::n_supported_derivative_levels,
1766 1));
1767 Assert(dependent_variables.size() == 1,
1768 ExcDimensionMismatch(dependent_variables.size(), 1));
1769 Assert(gradient.size() == independent_variables.size(),
1771 independent_variables.size()));
1772
1773 // In reverse mode, the gradients are computed from the
1774 // independent variables (i.e. the adjoint)
1776 const_cast<ADNumberType &>(dependent_variables[0]));
1777 const std::size_t n_independent_variables = independent_variables.size();
1778 for (unsigned int i = 0; i < n_independent_variables; ++i)
1780 ADNumberTraits<ADNumberType>::get_directional_derivative(
1781 independent_variables[i], 0 /*This number doesn't really matter*/));
1782 }
1783
1784
1785 template <typename ADNumberType, typename ScalarType>
1786 void
1787 TapelessDrivers<ADNumberType,
1788 ScalarType,
1789 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
1791 ADNumberTraits<ADNumberType>::type_code ==
1793 hessian(const std::vector<ADNumberType> &independent_variables,
1794 const std::vector<ADNumberType> &dependent_variables,
1795 FullMatrix<ScalarType> &hessian) const
1796 {
1797 Assert(AD::ADNumberTraits<ADNumberType>::n_supported_derivative_levels >=
1798 2,
1800 AD::ADNumberTraits<ADNumberType>::n_supported_derivative_levels,
1801 2));
1802 Assert(dependent_variables.size() == 1,
1803 ExcDimensionMismatch(dependent_variables.size(), 1));
1804 Assert(hessian.m() == independent_variables.size(),
1805 ExcDimensionMismatch(hessian.m(), independent_variables.size()));
1806 Assert(hessian.n() == independent_variables.size(),
1807 ExcDimensionMismatch(hessian.n(), independent_variables.size()));
1808
1809 // In reverse mode, the gradients are computed from the
1810 // independent variables (i.e. the adjoint)
1812 const_cast<ADNumberType &>(dependent_variables[0]));
1813 const std::size_t n_independent_variables = independent_variables.size();
1814 for (unsigned int i = 0; i < n_independent_variables; ++i)
1815 {
1816 using derivative_type =
1817 typename ADNumberTraits<ADNumberType>::derivative_type;
1818 const derivative_type gradient_i =
1819 ADNumberTraits<ADNumberType>::get_directional_derivative(
1820 independent_variables[i], i);
1821
1822 for (unsigned int j = 0; j <= i; ++j) // Symmetry
1823 {
1824 // Extract higher-order directional derivatives. Depending on
1825 // the AD number type, the result may be another AD number or a
1826 // floating point value.
1827 const ScalarType hessian_ij =
1829 ADNumberTraits<derivative_type>::get_directional_derivative(
1830 gradient_i, j));
1831 hessian[i][j] = hessian_ij;
1832 if (i != j)
1833 hessian[j][i] = hessian_ij; // Symmetry
1834 }
1835 }
1836 }
1837
1838
1839 template <typename ADNumberType, typename ScalarType>
1840 void
1841 TapelessDrivers<ADNumberType,
1842 ScalarType,
1843 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
1845 ADNumberTraits<ADNumberType>::type_code ==
1847 values(const std::vector<ADNumberType> &dependent_variables,
1848 Vector<ScalarType> &values) const
1849 {
1850 Assert(values.size() == dependent_variables.size(),
1851 ExcDimensionMismatch(values.size(), dependent_variables.size()));
1852
1853 const std::size_t n_dependent_variables = dependent_variables.size();
1854 for (unsigned int i = 0; i < n_dependent_variables; ++i)
1855 values[i] = ADNumberTraits<ADNumberType>::get_scalar_value(
1856 dependent_variables[i]);
1857 }
1858
1859
1860 template <typename ADNumberType, typename ScalarType>
1861 void
1862 TapelessDrivers<ADNumberType,
1863 ScalarType,
1864 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
1866 ADNumberTraits<ADNumberType>::type_code ==
1868 jacobian(const std::vector<ADNumberType> &independent_variables,
1869 const std::vector<ADNumberType> &dependent_variables,
1870 FullMatrix<ScalarType> &jacobian) const
1871 {
1872 Assert(AD::ADNumberTraits<ADNumberType>::n_supported_derivative_levels >=
1873 1,
1875 AD::ADNumberTraits<ADNumberType>::n_supported_derivative_levels,
1876 1));
1877 Assert(jacobian.m() == dependent_variables.size(),
1878 ExcDimensionMismatch(jacobian.m(), dependent_variables.size()));
1879 Assert(jacobian.n() == independent_variables.size(),
1880 ExcDimensionMismatch(jacobian.n(), independent_variables.size()));
1881
1882 const std::size_t n_independent_variables = independent_variables.size();
1883 const std::size_t n_dependent_variables = dependent_variables.size();
1884
1885 // In reverse mode, the gradients are computed from the
1886 // independent variables (i.e. the adjoint).
1887 // For a demonstration of why this accumulation process is
1888 // required, see the unit tests
1889 // sacado/basic_01b.cc and sacado/basic_02b.cc
1890 // Here we also take into consideration the derivative type:
1891 // The Sacado number may be of the nested variety, in which
1892 // case the effect of the accumulation process on the
1893 // sensitivities of the nested number need to be accounted for.
1894 using accumulation_type =
1895 typename ADNumberTraits<ADNumberType>::derivative_type;
1896 std::vector<accumulation_type> rad_accumulation(
1897 n_independent_variables,
1899
1900 for (unsigned int i = 0; i < n_dependent_variables; ++i)
1901 {
1903 const_cast<ADNumberType &>(dependent_variables[i]));
1904 for (unsigned int j = 0; j < n_independent_variables; ++j)
1905 {
1906 const accumulation_type df_i_dx_j =
1907 ADNumberTraits<ADNumberType>::get_directional_derivative(
1908 independent_variables[j],
1909 i /*This number doesn't really matter*/) -
1910 rad_accumulation[j];
1911 jacobian[i][j] =
1913 rad_accumulation[j] += df_i_dx_j;
1914 }
1915 }
1916 }
1917
1918
1919
1920 // Specialization for auto-differentiable numbers that use
1921 // forward mode to compute the first (and, if supported, second)
1922 // derivatives.
1923
1924# ifndef DOXYGEN
1925 template <typename ADNumberType, typename ScalarType>
1926 TapelessDrivers<
1927 ADNumberType,
1928 ScalarType,
1929 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
1931 ADNumberTraits<ADNumberType>::type_code ==
1933 ADNumberTraits<ADNumberType>::type_code ==
1934 NumberTypes::sacado_dfad_dfad>>::TapelessDrivers()
1935 : dependent_variable_marking_safe(false)
1936 {}
1937# endif
1938
1939
1940 template <typename ADNumberType, typename ScalarType>
1941 void
1942 TapelessDrivers<ADNumberType,
1943 ScalarType,
1944 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
1946 ADNumberTraits<ADNumberType>::type_code ==
1948 ADNumberTraits<ADNumberType>::type_code ==
1950 initialize_global_environment(const unsigned int n_independent_variables)
1951 {
1952 internal::configure_tapeless_mode<ADNumberType>(n_independent_variables);
1953 }
1954
1955
1956 template <typename ADNumberType, typename ScalarType>
1957 void
1958 TapelessDrivers<
1959 ADNumberType,
1960 ScalarType,
1961 std::enable_if_t<
1962 ADNumberTraits<ADNumberType>::type_code ==
1964 ADNumberTraits<ADNumberType>::type_code == NumberTypes::sacado_dfad ||
1965 ADNumberTraits<ADNumberType>::type_code ==
1966 NumberTypes::sacado_dfad_dfad>>::allow_dependent_variable_marking()
1967 {
1968 dependent_variable_marking_safe = true;
1969 }
1970
1971
1972 template <typename ADNumberType, typename ScalarType>
1973 void
1974 TapelessDrivers<
1975 ADNumberType,
1976 ScalarType,
1977 std::enable_if_t<
1978 ADNumberTraits<ADNumberType>::type_code ==
1980 ADNumberTraits<ADNumberType>::type_code == NumberTypes::sacado_dfad ||
1981 ADNumberTraits<ADNumberType>::type_code ==
1982 NumberTypes::sacado_dfad_dfad>>::prevent_dependent_variable_marking()
1983 {
1984 dependent_variable_marking_safe = false;
1985 }
1986
1987
1988 template <typename ADNumberType, typename ScalarType>
1989 bool
1990 TapelessDrivers<ADNumberType,
1991 ScalarType,
1992 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
1994 ADNumberTraits<ADNumberType>::type_code ==
1996 ADNumberTraits<ADNumberType>::type_code ==
1998 is_dependent_variable_marking_allowed() const
1999 {
2000 return dependent_variable_marking_safe;
2001 }
2002
2003
2004 template <typename ADNumberType, typename ScalarType>
2005 ScalarType
2006 TapelessDrivers<ADNumberType,
2007 ScalarType,
2008 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
2010 ADNumberTraits<ADNumberType>::type_code ==
2012 ADNumberTraits<ADNumberType>::type_code ==
2014 value(const std::vector<ADNumberType> &dependent_variables) const
2015 {
2016 Assert(dependent_variables.size() == 1,
2017 ExcDimensionMismatch(dependent_variables.size(), 1));
2018 return ADNumberTraits<ADNumberType>::get_scalar_value(
2019 dependent_variables[0]);
2020 }
2021
2022
2023 template <typename ADNumberType, typename ScalarType>
2024 void
2025 TapelessDrivers<ADNumberType,
2026 ScalarType,
2027 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
2029 ADNumberTraits<ADNumberType>::type_code ==
2031 ADNumberTraits<ADNumberType>::type_code ==
2033 gradient(const std::vector<ADNumberType> &independent_variables,
2034 const std::vector<ADNumberType> &dependent_variables,
2035 Vector<ScalarType> &gradient) const
2036 {
2037 Assert(AD::ADNumberTraits<ADNumberType>::n_supported_derivative_levels >=
2038 1,
2040 AD::ADNumberTraits<ADNumberType>::n_supported_derivative_levels,
2041 1));
2042 Assert(dependent_variables.size() == 1,
2043 ExcDimensionMismatch(dependent_variables.size(), 1));
2044 Assert(gradient.size() == independent_variables.size(),
2046 independent_variables.size()));
2047
2048 // In forward mode, the gradients are computed from the
2049 // dependent variables
2050 const std::size_t n_independent_variables = independent_variables.size();
2051 for (unsigned int i = 0; i < n_independent_variables; ++i)
2053 ADNumberTraits<ADNumberType>::get_directional_derivative(
2054 dependent_variables[0], i));
2055 }
2056
2057
2058 template <typename ADNumberType, typename ScalarType>
2059 void
2060 TapelessDrivers<ADNumberType,
2061 ScalarType,
2062 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
2064 ADNumberTraits<ADNumberType>::type_code ==
2066 ADNumberTraits<ADNumberType>::type_code ==
2068 hessian(const std::vector<ADNumberType> &independent_variables,
2069 const std::vector<ADNumberType> &dependent_variables,
2070 FullMatrix<ScalarType> &hessian) const
2071 {
2072 Assert(AD::ADNumberTraits<ADNumberType>::n_supported_derivative_levels >=
2073 2,
2075 AD::ADNumberTraits<ADNumberType>::n_supported_derivative_levels,
2076 2));
2077 Assert(dependent_variables.size() == 1,
2078 ExcDimensionMismatch(dependent_variables.size(), 1));
2079 Assert(hessian.m() == independent_variables.size(),
2080 ExcDimensionMismatch(hessian.m(), independent_variables.size()));
2081 Assert(hessian.n() == independent_variables.size(),
2082 ExcDimensionMismatch(hessian.n(), independent_variables.size()));
2083
2084 // In forward mode, the gradients are computed from the
2085 // dependent variables
2086 const std::size_t n_independent_variables = independent_variables.size();
2087 for (unsigned int i = 0; i < n_independent_variables; ++i)
2088 {
2089 using derivative_type =
2090 typename ADNumberTraits<ADNumberType>::derivative_type;
2091 const derivative_type gradient_i =
2092 ADNumberTraits<ADNumberType>::get_directional_derivative(
2093 dependent_variables[0], i);
2094
2095 for (unsigned int j = 0; j <= i; ++j) // Symmetry
2096 {
2097 // Extract higher-order directional derivatives. Depending on
2098 // the AD number type, the result may be another AD number or a
2099 // floating point value.
2100 const ScalarType hessian_ij =
2102 ADNumberTraits<derivative_type>::get_directional_derivative(
2103 gradient_i, j));
2104 hessian[i][j] = hessian_ij;
2105 if (i != j)
2106 hessian[j][i] = hessian_ij; // Symmetry
2107 }
2108 }
2109 }
2110
2111
2112 template <typename ADNumberType, typename ScalarType>
2113 void
2114 TapelessDrivers<ADNumberType,
2115 ScalarType,
2116 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
2118 ADNumberTraits<ADNumberType>::type_code ==
2120 ADNumberTraits<ADNumberType>::type_code ==
2122 values(const std::vector<ADNumberType> &dependent_variables,
2123 Vector<ScalarType> &values) const
2124 {
2125 Assert(values.size() == dependent_variables.size(),
2126 ExcDimensionMismatch(values.size(), dependent_variables.size()));
2127
2128 const std::size_t n_dependent_variables = dependent_variables.size();
2129 for (unsigned int i = 0; i < n_dependent_variables; ++i)
2130 values[i] = ADNumberTraits<ADNumberType>::get_scalar_value(
2131 dependent_variables[i]);
2132 }
2133
2134
2135 template <typename ADNumberType, typename ScalarType>
2136 void
2137 TapelessDrivers<ADNumberType,
2138 ScalarType,
2139 std::enable_if_t<ADNumberTraits<ADNumberType>::type_code ==
2141 ADNumberTraits<ADNumberType>::type_code ==
2143 ADNumberTraits<ADNumberType>::type_code ==
2145 jacobian(const std::vector<ADNumberType> &independent_variables,
2146 const std::vector<ADNumberType> &dependent_variables,
2147 FullMatrix<ScalarType> &jacobian) const
2148 {
2149 Assert(AD::ADNumberTraits<ADNumberType>::n_supported_derivative_levels >=
2150 1,
2152 AD::ADNumberTraits<ADNumberType>::n_supported_derivative_levels,
2153 1));
2154 Assert(jacobian.m() == dependent_variables.size(),
2155 ExcDimensionMismatch(jacobian.m(), dependent_variables.size()));
2156 Assert(jacobian.n() == independent_variables.size(),
2157 ExcDimensionMismatch(jacobian.n(), independent_variables.size()));
2158
2159 const std::size_t n_independent_variables = independent_variables.size();
2160 const std::size_t n_dependent_variables = dependent_variables.size();
2161
2162 // In forward mode, the gradients are computed from the
2163 // dependent variables
2164 for (unsigned int i = 0; i < n_dependent_variables; ++i)
2165 for (unsigned int j = 0; j < n_independent_variables; ++j)
2167 ADNumberTraits<ADNumberType>::get_directional_derivative(
2168 dependent_variables[i], j));
2169 }
2170
2171
2172 } // namespace AD
2173} // namespace Differentiation
2174
2175
2176/* --- Explicit instantiations --- */
2177// We don't build the .inst files if deal.II isn't configured with the
2178// external dependencies, but doxygen doesn't know that and tries to
2179// find that file anyway for parsing -- which then of course it fails
2180// on. So exclude the following from doxygen consideration.
2181# ifndef DOXYGEN
2182# include "differentiation/ad/ad_drivers.inst"
2183# ifdef DEAL_II_WITH_ADOLC
2184# include "differentiation/ad/ad_drivers.inst1"
2185# endif
2186# ifdef DEAL_II_TRILINOS_WITH_SACADO
2187# include "differentiation/ad/ad_drivers.inst2"
2188# endif
2189# endif
2190
2191
2192
2193#endif // defined(DEAL_II_WITH_ADOLC) || defined(DEAL_II_TRILINOS_WITH_SACADO)
size_type n() const
size_type m() const
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
static ::ExceptionBase & ExcSupportedDerivativeLevels(std::size_t arg1, std::size_t arg2)
static ::ExceptionBase & ExcRequiresADNumberSpecialization()
static ::ExceptionBase & ExcRequiresADOLC()
#define Assert(cond, exc)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
static ::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
std::enable_if_t<!(ADNumberTraits< ADNumberType >::type_code==NumberTypes::sacado_rad||ADNumberTraits< ADNumberType >::type_code==NumberTypes::sacado_rad_dfad)> reverse_mode_dependent_variable_activation(ADNumberType &)
std::enable_if_t<!(ADNumberTraits< ADNumberType >::type_code==NumberTypes::adolc_tapeless)> configure_tapeless_mode(const unsigned int)
static const Types< ADNumberType >::tape_index invalid_tape_index
Definition ad_drivers.h:119
void gradient(const typename Types< ADNumberType >::tape_index active_tape_index, const std::vector< ScalarType > &independent_variables, Vector< ScalarType > &gradient) const
bool is_registered_tape(const typename Types< ADNumberType >::tape_index tape_index) const
Definition ad_drivers.cc:74
void stop_taping(const typename Types< ADNumberType >::tape_index active_tape_index, const bool write_tapes_to_file)
void remove_tape(const typename Types< ADNumberType >::tape_index tape_index)
void start_taping(const typename Types< ADNumberType >::tape_index tape_index, const bool keep_independent_values)
void hessian(const typename Types< ADNumberType >::tape_index active_tape_index, const std::vector< ScalarType > &independent_variables, FullMatrix< ScalarType > &hessian) const
void set_tape_buffer_sizes(const typename Types< ADNumberType >::tape_buffer_sizes obufsize=64 *1024 *1024, const typename Types< ADNumberType >::tape_buffer_sizes lbufsize=64 *1024 *1024, const typename Types< ADNumberType >::tape_buffer_sizes vbufsize=64 *1024 *1024, const typename Types< ADNumberType >::tape_buffer_sizes tbufsize=64 *1024 *1024)
Definition ad_drivers.cc:93
void activate_tape(const typename Types< ADNumberType >::tape_index tape_index)
bool requires_retaping(const typename Types< ADNumberType >::tape_index tape_index) const
void print(std::ostream &stream) const
void print_tape_stats(const typename Types< ADNumberType >::tape_index tape_index, std::ostream &stream) const
ScalarType value(const typename Types< ADNumberType >::tape_index active_tape_index, const std::vector< ScalarType > &independent_variables) const
Types< ADNumberType >::tape_index active_tape_index() const
Definition ad_drivers.cc:65
void reset(const bool clear_registered_tapes)
std::vector< typename Types< ADNumberType >::tape_index > get_registered_tape_indices() const
void values(const typename Types< ADNumberType >::tape_index active_tape_index, const unsigned int n_dependent_variables, const std::vector< ScalarType > &independent_variables, Vector< ScalarType > &values) const
void jacobian(const typename Types< ADNumberType >::tape_index active_tape_index, const unsigned int n_dependent_variables, const std::vector< ScalarType > &independent_variables, FullMatrix< ScalarType > &jacobian) const
void gradient(const std::vector< ADNumberType > &independent_variables, const std::vector< ADNumberType > &dependent_variables, Vector< ScalarType > &gradient) const
void hessian(const std::vector< ADNumberType > &independent_variables, const std::vector< ADNumberType > &dependent_variables, FullMatrix< ScalarType > &hessian) const
void values(const std::vector< ADNumberType > &dependent_variables, Vector< ScalarType > &values) const
void jacobian(const std::vector< ADNumberType > &independent_variables, const std::vector< ADNumberType > &dependent_variables, FullMatrix< ScalarType > &jacobian) const
static void initialize_global_environment(const unsigned int n_independent_variables)
ScalarType value(const std::vector< ADNumberType > &dependent_variables) const
unsigned int tape_buffer_sizes
Definition ad_drivers.h:102
static constexpr const T & value(const T &t)
Definition numbers.h:662