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_helpers.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) 2018 - 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
19
20# include <type_traits>
21
22
23
24#endif // defined(DEAL_II_WITH_ADOLC) || defined(DEAL_II_TRILINOS_WITH_SACADO)
25
27
28#if defined(DEAL_II_WITH_ADOLC) || defined(DEAL_II_TRILINOS_WITH_SACADO)
29
30
31namespace Differentiation
32{
33 namespace AD
34 {
35 /* -------------------------- HelperBase -------------------------- */
36
37
38
39 template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
41 const unsigned int n_independent_variables,
42 const unsigned int n_dependent_variables)
43 : independent_variable_values(
44 n_independent_variables,
45 ::internal::NumberType<scalar_type>::value(0.0))
46 , registered_independent_variable_values(n_independent_variables, false)
47 , registered_marked_independent_variables(n_independent_variables, false)
48 , registered_marked_dependent_variables(n_dependent_variables, false)
49 {
50 // We have enabled the compilation of this class for arithmetic
51 // types (i.e. ADNumberTypeCode == NumberTypes::none), but we
52 // can't actually do anything with them. Lets not advance any further
53 // and seemingly allow any operations that will not give any
54 // sensible results.
55 Assert(ADNumberTypeCode != NumberTypes::none,
57 "Floating point/arithmetic numbers have no derivatives."));
58 Assert(
61 "The AD number type does not support the calculation of any derivatives."));
62
63 // Tapeless mode must be configured before any active live
64 // variables are created.
66 {
68 false /*ensure_persistent_setting*/);
69 }
70
71 // For safety, we ensure that the entries in this vector *really* are
72 // initialized correctly by sending in the constructed zero-valued
73 // initializer.
76 0.0));
77 }
78
79
80
81 template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
82 void
83 HelperBase<ADNumberTypeCode,
84 ScalarType>::reset_registered_independent_variables()
85 {
86 std::fill(registered_independent_variable_values.begin(),
87 registered_independent_variable_values.end(),
88 false);
89 }
90
91
92
93 template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
94 void
97 {
98 std::fill(registered_marked_dependent_variables.begin(),
99 registered_marked_dependent_variables.end(),
100 flag);
101 }
102
103
104
105 template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
106 void
108 const unsigned int index,
109 const scalar_type &value)
110 {
112 {
113 // A dummy call in case the user does not encapsulate a set of
114 // calls to tapeless ADHelpers with the initial and final calls to
115 // [start,stop]_recording_operations.
116 if (this->is_recording() == false)
117 start_recording_operations(1 /*tape index*/);
118
119 Assert(this->is_recording() == true,
121 "Cannot change the value of an independent variable "
122 "of the tapeless variety while this class is not set "
123 "in recording operations."));
124 }
126 {
127 Assert(this->active_tape_index() !=
129 ExcMessage("Invalid tape index"));
130 }
131 Assert(
132 index < n_independent_variables(),
134 "Trying to set the value of a non-existent independent variable."));
135
136 independent_variable_values[index] = value;
137 registered_independent_variable_values[index] = true;
138 }
139
140
141
142 template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
143 void
145 const unsigned int index,
146 ad_type &out) const
147 {
148 Assert(index < n_independent_variables(), ExcInternalError());
149 Assert(registered_independent_variable_values[index] == true,
151
152 if (index > 0)
153 {
154 Assert(
155 registered_marked_independent_variables[index - 1] == true,
157 "Need to extract sensitivities in the order they're created."));
158 }
159
161 {
162 Assert(active_tape_index() != Numbers<ad_type>::invalid_tape_index,
163 ExcMessage("Invalid tape index"));
164 Assert(is_recording() == true,
166 "The marking of independent variables is only valid "
167 "during recording."));
168 }
169
171 independent_variable_values[index],
172 index,
173 this->n_independent_variables(),
174 out);
175 registered_marked_independent_variables[index] = true;
176 }
177
178
179
180 template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
181 void
182 HelperBase<ADNumberTypeCode,
183 ScalarType>::finalize_sensitive_independent_variables() const
184 {
185 // Double check that we've actually registered all DoFs
186 Assert(n_registered_independent_variables() == n_independent_variables(),
187 ExcMessage("Not all values of sensitivities have been recorded!"));
188
189 // This should happen only once
190 if (this->independent_variables.empty())
191 {
192 this->independent_variables.resize(
193 this->n_independent_variables(),
195
196 // Indicate the sensitivity that each entry represents
197 for (unsigned int i = 0; i < this->n_independent_variables(); ++i)
198 this->mark_independent_variable(i, this->independent_variables[i]);
199 }
200 }
201
202
203
204 template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
205 void
208 ad_type &out) const
209 {
211 {
212 Assert(active_tape_index() != Numbers<ad_type>::invalid_tape_index,
213 ExcMessage("Invalid tape index"));
214 }
215 Assert(is_recording() == false,
217 "The initialization of non-sensitive independent variables is "
218 "only valid outside of recording operations."));
219
220 Assert(index < n_independent_variables(), ExcInternalError());
221 Assert(registered_independent_variable_values[index] == true,
223
224 out = independent_variable_values[index];
226
227
228
229 template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
230 unsigned int
231 HelperBase<ADNumberTypeCode,
232 ScalarType>::n_registered_independent_variables() const
233 {
234 return std::count(registered_independent_variable_values.begin(),
235 registered_independent_variable_values.end(),
236 true);
237 }
238
239
240
241 template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
242 std::size_t
244 {
245 return independent_variable_values.size();
246 }
247
248
249
250 template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
251 unsigned int
253 const
254 {
255 return std::count(registered_marked_dependent_variables.begin(),
256 registered_marked_dependent_variables.end(),
257 true);
258 }
259
260
261
262 template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
263 std::size_t
266 return dependent_variables.size();
267 }
268
269
270
271 template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
272 bool
274 {
276 return taped_driver.is_recording();
277 else
278 return tapeless_driver.is_dependent_variable_marking_allowed();
279 }
280
281
282
283 template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
284 typename Types<
287 {
289 return taped_driver.active_tape_index();
290 else
291 return 1;
292 }
293
295
296 template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
297 bool
299 const typename Types<ad_type>::tape_index tape_index) const
300 {
302 return taped_driver.is_registered_tape(tape_index);
303 else
304 return true;
305 }
306
307
308
309 template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
310 void
312 {
313 // Store stream flags
314 const std::ios_base::fmtflags stream_flags(stream.flags());
315 // Set stream to print booleans as "true"/"false"
316 stream.setf(std::ios_base::boolalpha);
317
318 stream << "Active tape index: " << active_tape_index() << '\n';
319 stream << "Recording? " << is_recording() << '\n';
320 stream << std::flush;
321
323 taped_driver.print(stream);
324
325 stream << "Registered independent variables: " << '\n';
326 for (unsigned int i = 0; i < n_independent_variables(); ++i)
327 stream << registered_independent_variable_values[i]
328 << (i < (n_independent_variables() - 1) ? "," : "");
329 stream << std::endl;
330
331 stream << "Independent variable values: " << '\n';
332 print_values(stream);
333
334 stream << "Registered marked independent variables: " << '\n';
335 for (unsigned int i = 0; i < n_independent_variables(); ++i)
336 stream << registered_marked_independent_variables[i]
337 << (i < (n_independent_variables() - 1) ? "," : "")
338 << std::flush;
339 stream << std::endl;
341 stream << "Dependent variable values: " << '\n';
342 for (unsigned int i = 0; i < n_dependent_variables(); ++i)
343 stream << dependent_variables[i]
344 << (i < (n_dependent_variables() - 1) ? "," : "");
345 stream << std::endl;
346
347 stream << "Registered dependent variables: " << '\n';
348 for (unsigned int i = 0; i < n_dependent_variables(); ++i)
349 stream << registered_marked_dependent_variables[i]
350 << (i < (n_dependent_variables() - 1) ? "," : "");
351 stream << std::endl;
352
353 // Restore stream flags
354 stream.flags(stream_flags);
355 }
356
357
359 template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
360 void
362 std::ostream &stream) const
363 {
364 for (unsigned int i = 0; i < n_independent_variables(); ++i)
365 stream << independent_variable_values[i]
366 << (i < (n_independent_variables() - 1) ? "," : "")
367 << std::flush;
368 stream << std::endl;
369 }
370
371
372
373 template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
374 void
376 const typename Types<ad_type>::tape_index tape_index,
377 std::ostream &stream) const
378 {
380 return;
381
382 Assert(is_registered_tape(tape_index),
383 ExcMessage("Tape number not registered"));
384
385 this->taped_driver.print_tape_stats(tape_index, stream);
386 }
387
388
389
390 template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
391 void
393 const unsigned int n_independent_variables,
394 const unsigned int n_dependent_variables,
395 const bool clear_registered_tapes)
396 {
397 const unsigned int new_n_independent_variables =
398 (n_independent_variables != ::numbers::invalid_unsigned_int ?
399 n_independent_variables :
400 this->n_independent_variables());
401 const unsigned int new_n_dependent_variables =
402 (n_dependent_variables != ::numbers::invalid_unsigned_int ?
403 n_dependent_variables :
404 this->n_dependent_variables());
405
406 // Here we clear our vectors of AD data with a reallocation of memory
407 // (i.e. we *nuke* them entirely). Why we do this differs for each
408 // AD type:
409 // - ADOL-C taped mode must have their tapes fully cleared of marked data
410 // before the tapes can be overwritten.
411 // - ADOL-C tapeless mode must be configured for before any active live
412 // variables are created.
413 // - Reverse-mode Sacado numbers to must be destroyed to reset their
414 // accumulations.
415 // - Forward-mode Sacado numbers have no specific requirements, but it
416 // doesn't really hurt to perform this operation anyway.
417 {
418 std::vector<ad_type>().swap(independent_variables);
419 std::vector<ad_type>().swap(dependent_variables);
420 }
421
422 // Tapeless mode must be configured before any active live
423 // variables are created.
425 {
426 configure_tapeless_mode(new_n_independent_variables,
427 false /*ensure_persistent_setting*/);
428 }
430 taped_driver.reset(clear_registered_tapes);
431
432 independent_variable_values = std::vector<scalar_type>(
433 new_n_independent_variables,
435 registered_independent_variable_values =
436 std::vector<bool>(new_n_independent_variables, false);
437 registered_marked_independent_variables =
438 std::vector<bool>(new_n_independent_variables, false);
439 dependent_variables =
440 std::vector<ad_type>(new_n_dependent_variables,
442 registered_marked_dependent_variables =
443 std::vector<bool>(new_n_dependent_variables, false);
444 }
445
446
447
448 template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
449 void
451 const unsigned int n_independent_variables,
452 const bool ensure_persistent_setting)
453 {
455 return;
456
457 // Try to safely initialize the global environment
459 n_independent_variables);
460
461 if (ensure_persistent_setting == true)
463 {
464 // In order to ensure that the settings remain for the entire
465 // duration of the simulation, we create a global live variable
466 // that doesn't go out of scope.
467 static ad_type num = 0.0;
468 (void)num;
469 }
470 }
471
472
473
474 template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
475 void
477 const typename Types<ad_type>::tape_index tape_index)
478 {
479 activate_tape(tape_index, true /*read_mode*/);
480 }
481
482
483
484 template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
485 bool
487 const typename Types<ad_type>::tape_index tape_index) const
488 {
490 return false;
491
492 return taped_driver.requires_retaping(tape_index);
493 }
494
495
496
497 template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
498 bool
500 const
501 {
503 return false;
504
505 return taped_driver.last_action_requires_retaping();
506 }
507
508
509
510 template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
511 void
513 {
515 return;
516
517 taped_driver.remove_tape(taped_driver.active_tape_index());
518 }
519
520
521
522 template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
523 void
525 const typename Types<ad_type>::tape_index tape_index,
526 const bool read_mode)
527 {
529 {
531 ExcMessage("Invalid tape index"));
533 ExcMessage("Tape index exceeds maximum allowable value"));
534 taped_driver.activate_tape(tape_index);
535 reset_registered_independent_variables();
536
537 // A tape may have been defined by a different ADHelper, so in this
538 // case we ignore the fact that any dependent variables within the
539 // current data structure have not been marked as dependents
540 if (read_mode == true)
541 {
542 Assert(is_registered_tape(tape_index),
543 ExcMessage("Tape number not registered"));
544 reset_registered_dependent_variables(true);
545 Assert(n_registered_dependent_variables() ==
546 n_dependent_variables(),
547 ExcMessage("Not all dependent variables have been set!"));
548 }
549 }
550 else
551 {
554 }
555 }
556
557
558
559 template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
560 void
562 const typename Types<ad_type>::tape_buffer_sizes obufsize,
563 const typename Types<ad_type>::tape_buffer_sizes lbufsize,
564 const typename Types<ad_type>::tape_buffer_sizes vbufsize,
565 const typename Types<ad_type>::tape_buffer_sizes tbufsize)
566 {
567 // When valid for the chosen AD number type, these values will be used the
568 // next time start_recording_operations() is called.
570 taped_driver.set_tape_buffer_sizes(obufsize,
571 lbufsize,
572 vbufsize,
573 tbufsize);
574 }
576
577
578 template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
579 bool
581 const typename Types<ad_type>::tape_index tape_index,
582 const bool overwrite_tape,
583 const bool keep_independent_values)
584 {
585 // Define this here for clarity when this flag is used later.
586 const bool read_mode = false;
587
589 {
590 if (overwrite_tape != true)
591 {
592 Assert(is_recording() == false,
593 ExcMessage("Already recording..."));
594 }
595
596 // Check conditions to enable tracing
597 if (is_registered_tape(tape_index) == false || overwrite_tape == true)
598 {
599 // Setup the data structures for this class in the
600 // appropriate manner
601 activate_tape(tape_index, read_mode);
602
603 // Start taping
604 taped_driver.start_taping(active_tape_index(),
605 keep_independent_values);
606
607 // Clear the flags that state which independent and
608 // dependent variables have been registered
609 reset_registered_independent_variables();
610 reset_registered_dependent_variables();
611 }
612 else
613 {
614 Assert(is_recording() == false,
616 "Tape recording is unexpectedly still enabled."));
617
618 // Now we activate the pre-recorded tape so that its immediately
619 // available for use
620 activate_recorded_tape(tape_index);
621 }
622 }
623 else
624 {
625 Assert(ADNumberTraits<ad_type>::is_tapeless == true,
627
628 // Set the flag that states that we can safely mark dependent
629 // variables within this current phase of operations
630 tapeless_driver.allow_dependent_variable_marking();
631
632 // Dummy call to ensure that the intuitively correct
633 // value for the active tape (whether "valid" or not)
634 // is always returned to the user.
635 activate_tape(tape_index, read_mode);
636 }
637
638 return is_recording();
639 }
640
641
642
643 template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
644 void
646 const bool write_tapes_to_file)
647 {
648 Assert(is_recording() == true, ExcMessage("Not currently recording..."));
649
650 // Double check that we've actually registered all DoFs
651 Assert(n_registered_independent_variables() == n_independent_variables(),
652 ExcMessage("Not all values of sensitivities have been recorded!"));
653
655 {
656 // Stop tracing
657 taped_driver.stop_taping(active_tape_index(), write_tapes_to_file);
658 }
659 else
660 {
663 // Double check that we've actually registered dependent variables
664 Assert(n_registered_dependent_variables() == n_dependent_variables(),
665 ExcMessage("Not all dependent variables have been set!"));
666
667 // By changing this flag, we ensure that the we can no longer
668 // legally alter the values of the dependent variables using
669 // set_dependent_variable(). This is important because the value of
670 // the tapeless independent variables are set and finalized when
671 // mark_dependent_variable() is called. So we cannot allow this to
672 // be done when not in the "recording" phase.
673 tapeless_driver.prevent_dependent_variable_marking();
675 }
676
677
678
679 template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
680 void
682 const unsigned int index,
683 const ad_type &func)
684 {
685 Assert(index < n_dependent_variables(), ExcMessage("Index out of range"));
686 Assert(registered_marked_dependent_variables[index] == false,
688 "This dependent variable has already been registered."));
689
691 {
692 Assert(active_tape_index() != Numbers<ad_type>::invalid_tape_index,
693 ExcMessage("Invalid tape index"));
694 Assert(is_recording() == true,
696 "Must be recording when registering dependent variables."));
697 }
698
699 // Register the given dependent variable
700 internal::Marking<ad_type>::dependent_variable(dependent_variables[index],
701 func);
702 registered_marked_dependent_variables[index] = true;
703 }
704
705
706
707 /* -------------------- CellLevelBase -------------------- */
709
710
711 template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
713 const unsigned int n_independent_variables,
714 const unsigned int n_dependent_variables)
715 : HelperBase<ADNumberTypeCode, ScalarType>(n_independent_variables,
716 n_dependent_variables)
717 {}
718
719
721 template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
722 void
724 const std::vector<scalar_type> &dof_values)
725 {
726 // This is actually the same thing the set_independent_variable function,
727 // in the sense that we simply populate our array of independent values
728 // with a meaningful number. However, in this case we need to double check
729 // that we're not registering these variables twice
730 Assert(dof_values.size() == this->n_independent_variables(),
732 "Vector size does not match number of independent variables"));
733 for (unsigned int i = 0; i < this->n_independent_variables(); ++i)
734 {
735 Assert(this->registered_independent_variable_values[i] == false,
736 ExcMessage("Independent variable value already registered."));
737 }
738 set_dof_values(dof_values);
739 }
740
741
742
743 template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
744 const std::vector<
747 const
748 {
750 {
751 Assert(this->active_tape_index() !=
753 ExcMessage("Invalid tape index"));
754 }
755
756 // If necessary, initialize the internally stored vector of
757 // AD numbers that represents the independent variables
758 this->finalize_sensitive_independent_variables();
759 Assert(this->independent_variables.size() ==
760 this->n_independent_variables(),
761 ExcDimensionMismatch(this->independent_variables.size(),
762 this->n_independent_variables()));
764 return this->independent_variables;
765 }
766
767
768
769 template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
770 void
772 const std::vector<scalar_type> &values)
773 {
775 {
776 Assert(this->active_tape_index() !=
778 ExcMessage("Invalid tape index"));
779 }
780 Assert(values.size() == this->n_independent_variables(),
782 "Vector size does not match number of independent variables"));
783 for (unsigned int i = 0; i < this->n_independent_variables(); ++i)
785 i, values[i]);
786 }
787
788
789
790 /* ------------------ EnergyFunctional ------------------ */
791
792
793
794 template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
796 const unsigned int n_independent_variables)
797 : CellLevelBase<ADNumberTypeCode, ScalarType>(n_independent_variables, 1)
798 {}
799
800
801
802 template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
803 void
811
812
813
814 template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
817 {
819 this->taped_driver.keep_independent_values() == false) ||
821 {
822 Assert(
823 this->n_registered_independent_variables() ==
824 this->n_independent_variables(),
826 "Not all values of sensitivities have been registered or subsequently set!"));
827 }
828 Assert(this->n_registered_dependent_variables() ==
829 this->n_dependent_variables(),
830 ExcMessage("Not all dependent variables have been registered."));
831
832 Assert(
833 this->n_dependent_variables() == 1,
835 "The EnergyFunctional class expects there to be only one dependent variable."));
836
838 {
839 Assert(this->active_tape_index() !=
841 ExcMessage("Invalid tape index"));
842 Assert(this->is_recording() == false,
844 "Cannot compute value while tape is being recorded."));
845 Assert(this->independent_variable_values.size() ==
846 this->n_independent_variables(),
847 ExcDimensionMismatch(this->independent_variable_values.size(),
848 this->n_independent_variables()));
849
850 return this->taped_driver.value(this->active_tape_index(),
851 this->independent_variable_values);
852 }
853 else
854 {
857 Assert(this->independent_variables.size() ==
858 this->n_independent_variables(),
859 ExcDimensionMismatch(this->independent_variables.size(),
860 this->n_independent_variables()));
861
862 return this->tapeless_driver.value(this->dependent_variables);
863 }
864 }
865
866
867
868 template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
869 void
871 Vector<scalar_type> &gradient) const
872 {
874 this->taped_driver.keep_independent_values() == false) ||
876 {
877 Assert(
878 this->n_registered_independent_variables() ==
879 this->n_independent_variables(),
881 "Not all values of sensitivities have been registered or subsequently set!"));
882 }
883 Assert(this->n_registered_dependent_variables() ==
884 this->n_dependent_variables(),
885 ExcMessage("Not all dependent variables have been registered."));
886
887 Assert(
888 this->n_dependent_variables() == 1,
890 "The EnergyFunctional class expects there to be only one dependent variable."));
891
892 // We can neglect correctly initializing the entries as
893 // we'll be overwriting them immediately in the succeeding call to
894 // Drivers::gradient().
895 if (gradient.size() != this->n_independent_variables())
896 gradient.reinit(this->n_independent_variables(),
897 true /*omit_zeroing_entries*/);
898
900 {
901 Assert(this->active_tape_index() !=
903 ExcMessage("Invalid tape index"));
904 Assert(this->is_recording() == false,
906 "Cannot compute gradient while tape is being recorded."));
907 Assert(this->independent_variable_values.size() ==
908 this->n_independent_variables(),
909 ExcDimensionMismatch(this->independent_variable_values.size(),
910 this->n_independent_variables()));
911
912 this->taped_driver.gradient(this->active_tape_index(),
913 this->independent_variable_values,
914 gradient);
915 }
916 else
917 {
920 Assert(this->independent_variables.size() ==
921 this->n_independent_variables(),
922 ExcDimensionMismatch(this->independent_variables.size(),
923 this->n_independent_variables()));
924
925 this->tapeless_driver.gradient(this->independent_variables,
926 this->dependent_variables,
927 gradient);
928 }
929 }
930
931
932
933 template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
934 void
936 FullMatrix<scalar_type> &hessian) const
937 {
940 "Cannot computed function Hessian: AD number type does "
941 "not support the calculation of second order derivatives."));
942
944 this->taped_driver.keep_independent_values() == false))
945 {
946 Assert(
947 this->n_registered_independent_variables() ==
948 this->n_independent_variables(),
950 "Not all values of sensitivities have been registered or subsequently set!"));
952 Assert(this->n_registered_dependent_variables() ==
953 this->n_dependent_variables(),
954 ExcMessage("Not all dependent variables have been registered."));
955
956 Assert(
957 this->n_dependent_variables() == 1,
959 "The EnergyFunctional class expects there to be only one dependent variable."));
960
961 // We can neglect correctly initializing the entries as
962 // we'll be overwriting them immediately in the succeeding call to
963 // Drivers::hessian().
964 if (hessian.m() != this->n_independent_variables() ||
965 hessian.n() != this->n_independent_variables())
966 hessian.reinit({this->n_independent_variables(),
967 this->n_independent_variables()},
968 true /*omit_default_initialization*/);
969
970 if (ADNumberTraits<ad_type>::is_taped == true)
971 {
972 Assert(this->active_tape_index() !=
974 ExcMessage("Invalid tape index"));
975 Assert(this->is_recording() == false,
977 "Cannot compute hessian while tape is being recorded."));
978 Assert(this->independent_variable_values.size() ==
979 this->n_independent_variables(),
980 ExcDimensionMismatch(this->independent_variable_values.size(),
981 this->n_independent_variables()));
982
983 this->taped_driver.hessian(this->active_tape_index(),
984 this->independent_variable_values,
985 hessian);
986 }
987 else
988 {
991 Assert(this->independent_variables.size() ==
992 this->n_independent_variables(),
993 ExcDimensionMismatch(this->independent_variables.size(),
994 this->n_independent_variables()));
995
996 this->tapeless_driver.hessian(this->independent_variables,
997 this->dependent_variables,
998 hessian);
999 }
1000 }
1001
1002
1003 /* ------------------- ResidualLinearization ------------------- */
1004
1005
1006
1007 template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
1009 const unsigned int n_independent_variables,
1010 const unsigned int n_dependent_variables)
1011 : CellLevelBase<ADNumberTypeCode, ScalarType>(n_independent_variables,
1012 n_dependent_variables)
1013 {}
1014
1015
1016
1017 template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
1018 void
1020 register_residual_vector(const std::vector<ad_type> &residual)
1021 {
1022 Assert(residual.size() == this->n_dependent_variables(),
1023 ExcMessage(
1024 "Vector size does not match number of dependent variables"));
1025 for (unsigned int i = 0; i < this->n_dependent_variables(); ++i)
1027 i, residual[i]);
1028 }
1029
1030
1031
1032 template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
1033 void
1035 Vector<scalar_type> &values) const
1036 {
1037 if ((ADNumberTraits<ad_type>::is_taped == true &&
1038 this->taped_driver.keep_independent_values() == false) ||
1040 {
1041 Assert(
1042 this->n_registered_independent_variables() ==
1043 this->n_independent_variables(),
1044 ExcMessage(
1045 "Not all values of sensitivities have been registered or subsequently set!"));
1046 }
1047 Assert(this->n_registered_dependent_variables() ==
1048 this->n_dependent_variables(),
1049 ExcMessage("Not all dependent variables have been registered."));
1050
1051 // We can neglect correctly initializing the entries as
1052 // we'll be overwriting them immediately in the succeeding call to
1053 // Drivers::values().
1054 if (values.size() != this->n_dependent_variables())
1055 values.reinit(this->n_dependent_variables(),
1056 true /*omit_zeroing_entries*/);
1057
1059 {
1060 Assert(this->active_tape_index() !=
1062 ExcMessage("Invalid tape index"));
1063 Assert(this->is_recording() == false,
1064 ExcMessage(
1065 "Cannot compute values while tape is being recorded."));
1066 Assert(this->independent_variable_values.size() ==
1067 this->n_independent_variables(),
1068 ExcDimensionMismatch(this->independent_variable_values.size(),
1069 this->n_independent_variables()));
1070
1071 this->taped_driver.values(this->active_tape_index(),
1072 this->n_dependent_variables(),
1073 this->independent_variable_values,
1074 values);
1075 }
1076 else
1077 {
1080 this->tapeless_driver.values(this->dependent_variables, values);
1081 }
1082 }
1083
1084
1085
1086 template <enum AD::NumberTypes ADNumberTypeCode, typename ScalarType>
1087 void
1089 FullMatrix<scalar_type> &jacobian) const
1090 {
1091 if ((ADNumberTraits<ad_type>::is_taped == true &&
1092 this->taped_driver.keep_independent_values() == false) ||
1094 {
1095 Assert(
1096 this->n_registered_independent_variables() ==
1097 this->n_independent_variables(),
1098 ExcMessage(
1099 "Not all values of sensitivities have been registered or subsequently set!"));
1100 }
1101 Assert(this->n_registered_dependent_variables() ==
1102 this->n_dependent_variables(),
1103 ExcMessage("Not all dependent variables have been registered."));
1104
1105 // We can neglect correctly initializing the entries as
1106 // we'll be overwriting them immediately in the succeeding call to
1107 // Drivers::jacobian().
1108 if (jacobian.m() != this->n_dependent_variables() ||
1109 jacobian.n() != this->n_independent_variables())
1110 jacobian.reinit({this->n_dependent_variables(),
1111 this->n_independent_variables()},
1112 true /*omit_default_initialization*/);
1113
1115 {
1116 Assert(this->active_tape_index() !=
1118 ExcMessage("Invalid tape index"));
1119 Assert(this->is_recording() == false,
1120 ExcMessage(
1121 "Cannot compute hessian while tape is being recorded."));
1122 Assert(this->independent_variable_values.size() ==
1123 this->n_independent_variables(),
1124 ExcDimensionMismatch(this->independent_variable_values.size(),
1125 this->n_independent_variables()));
1126
1127 this->taped_driver.jacobian(this->active_tape_index(),
1128 this->n_dependent_variables(),
1129 this->independent_variable_values,
1130 jacobian);
1131 }
1132 else
1133 {
1136 Assert(this->independent_variables.size() ==
1137 this->n_independent_variables(),
1138 ExcDimensionMismatch(this->independent_variables.size(),
1139 this->n_independent_variables()));
1140
1141 this->tapeless_driver.jacobian(this->independent_variables,
1142 this->dependent_variables,
1143 jacobian);
1144 }
1145 }
1146
1147
1148
1149 /* ----------------- PointLevelFunctionsBase ----------------- */
1150
1151
1152
1153 template <int dim,
1154 enum AD::NumberTypes ADNumberTypeCode,
1155 typename ScalarType>
1157 PointLevelFunctionsBase(const unsigned int n_independent_variables,
1158 const unsigned int n_dependent_variables)
1159 : HelperBase<ADNumberTypeCode, ScalarType>(n_independent_variables,
1160 n_dependent_variables)
1161 , symmetric_independent_variables(n_independent_variables, false)
1162 {}
1163
1164
1165
1166 template <int dim,
1167 enum AD::NumberTypes ADNumberTypeCode,
1168 typename ScalarType>
1169 void
1171 const unsigned int n_independent_variables,
1172 const unsigned int n_dependent_variables,
1173 const bool clear_registered_tapes)
1174 {
1176 n_dependent_variables,
1177 clear_registered_tapes);
1178
1179 const unsigned int new_n_independent_variables =
1180 (n_independent_variables != ::numbers::invalid_unsigned_int ?
1181 n_independent_variables :
1182 this->n_independent_variables());
1183 symmetric_independent_variables =
1184 std::vector<bool>(new_n_independent_variables, false);
1185 }
1186
1187
1188
1189 template <int dim,
1190 enum AD::NumberTypes ADNumberTypeCode,
1191 typename ScalarType>
1192 bool
1194 is_symmetric_independent_variable(const unsigned int index) const
1195 {
1196 Assert(index < symmetric_independent_variables.size(),
1198 return symmetric_independent_variables[index];
1199 }
1200
1201
1202
1203 template <int dim,
1204 enum AD::NumberTypes ADNumberTypeCode,
1205 typename ScalarType>
1206 unsigned int
1209 {
1210 return std::count(symmetric_independent_variables.begin(),
1211 symmetric_independent_variables.end(),
1212 true);
1213 }
1214
1215
1216
1217 template <int dim,
1218 enum AD::NumberTypes ADNumberTypeCode,
1219 typename ScalarType>
1220 void
1222 register_independent_variables(const std::vector<scalar_type> &values)
1223 {
1224 // This is actually the same thing the set_independent_variable function,
1225 // in the sense that we simply populate our array of independent values
1226 // with a meaningful number. However, in this case we need to double check
1227 // that we're not registering these variables twice
1228 Assert(values.size() == this->n_independent_variables(),
1229 ExcMessage(
1230 "Vector size does not match number of independent variables"));
1231 for (unsigned int i = 0; i < this->n_independent_variables(); ++i)
1232 {
1233 Assert(this->registered_independent_variable_values[i] == false,
1234 ExcMessage("Independent variable value already registered."));
1235 }
1236 set_independent_variables(values);
1237 }
1238
1239
1240
1241 template <int dim,
1242 enum AD::NumberTypes ADNumberTypeCode,
1243 typename ScalarType>
1244 const std::vector<typename PointLevelFunctionsBase<dim,
1245 ADNumberTypeCode,
1246 ScalarType>::ad_type> &
1249 {
1251 {
1252 Assert(this->active_tape_index() !=
1254 ExcMessage("Invalid tape index"));
1255 }
1256
1257 // Just in case the user has not done so, we repeat the call to
1258 // initialize the internally stored vector of AD numbers that
1259 // represents the independent variables.
1260 this->finalize_sensitive_independent_variables();
1261 Assert(this->independent_variables.size() ==
1262 this->n_independent_variables(),
1263 ExcDimensionMismatch(this->independent_variables.size(),
1264 this->n_independent_variables()));
1265
1266 return this->independent_variables;
1267 }
1268
1269
1270
1271 template <int dim,
1272 enum AD::NumberTypes ADNumberTypeCode,
1273 typename ScalarType>
1274 void
1276 set_sensitivity_value(const unsigned int index,
1277 const bool symmetric_component,
1278 const scalar_type &value)
1279 {
1281 value);
1282 Assert(
1283 index < this->n_independent_variables(),
1284 ExcMessage(
1285 "Trying to set the symmetry flag of a non-existent independent variable."));
1286 Assert(index < symmetric_independent_variables.size(),
1288 symmetric_independent_variables[index] = symmetric_component;
1289 }
1290
1291
1292
1293 template <int dim,
1294 enum AD::NumberTypes ADNumberTypeCode,
1295 typename ScalarType>
1296 void
1298 set_independent_variables(const std::vector<scalar_type> &values)
1299 {
1301 {
1302 Assert(this->active_tape_index() !=
1304 ExcMessage("Invalid tape index"));
1305 }
1306 Assert(values.size() == this->n_independent_variables(),
1307 ExcMessage(
1308 "Vector size does not match number of independent variables"));
1309 for (unsigned int i = 0; i < this->n_independent_variables(); ++i)
1311 i, values[i]);
1312 }
1313
1314
1315
1316 /* -------------------- ScalarFunction -------------------- */
1317
1318
1319
1320 template <int dim,
1321 enum AD::NumberTypes ADNumberTypeCode,
1322 typename ScalarType>
1324 const unsigned int n_independent_variables)
1325 : PointLevelFunctionsBase<dim, ADNumberTypeCode, ScalarType>(
1326 n_independent_variables,
1327 1)
1328 {}
1329
1330
1331
1332 template <int dim,
1333 enum AD::NumberTypes ADNumberTypeCode,
1334 typename ScalarType>
1335 void
1343
1344
1345
1346 template <int dim,
1347 enum AD::NumberTypes ADNumberTypeCode,
1348 typename ScalarType>
1351 {
1352 if ((ADNumberTraits<ad_type>::is_taped == true &&
1353 this->taped_driver.keep_independent_values() == false) ||
1355 {
1356 Assert(
1357 this->n_registered_independent_variables() ==
1358 this->n_independent_variables(),
1359 ExcMessage(
1360 "Not all values of sensitivities have been registered or subsequently set!"));
1361 }
1362 Assert(this->n_registered_dependent_variables() ==
1363 this->n_dependent_variables(),
1364 ExcMessage("Not all dependent variables have been registered."));
1365
1366 Assert(
1367 this->n_dependent_variables() == 1,
1368 ExcMessage(
1369 "The ScalarFunction class expects there to be only one dependent variable."));
1370
1372 {
1373 Assert(this->active_tape_index() !=
1375 ExcMessage("Invalid tape index"));
1376 Assert(this->is_recording() == false,
1377 ExcMessage(
1378 "Cannot compute values while tape is being recorded."));
1379 Assert(this->independent_variable_values.size() ==
1380 this->n_independent_variables(),
1381 ExcDimensionMismatch(this->independent_variable_values.size(),
1382 this->n_independent_variables()));
1383
1384 return this->taped_driver.value(this->active_tape_index(),
1385 this->independent_variable_values);
1386 }
1387 else
1388 {
1391 return this->tapeless_driver.value(this->dependent_variables);
1392 }
1393 }
1394
1395
1396 template <int dim,
1397 enum AD::NumberTypes ADNumberTypeCode,
1398 typename ScalarType>
1399 void
1401 Vector<scalar_type> &gradient) const
1402 {
1403 if ((ADNumberTraits<ad_type>::is_taped == true &&
1404 this->taped_driver.keep_independent_values() == false) ||
1406 {
1407 Assert(
1408 this->n_registered_independent_variables() ==
1409 this->n_independent_variables(),
1410 ExcMessage(
1411 "Not all values of sensitivities have been registered or subsequently set!"));
1412 }
1413 Assert(this->n_registered_dependent_variables() ==
1414 this->n_dependent_variables(),
1415 ExcMessage("Not all dependent variables have been registered."));
1416
1417 Assert(
1418 this->n_dependent_variables() == 1,
1419 ExcMessage(
1420 "The ScalarFunction class expects there to be only one dependent variable."));
1421
1422 // We can neglect correctly initializing the entries as
1423 // we'll be overwriting them immediately in the succeeding call to
1424 // Drivers::gradient().
1425 if (gradient.size() != this->n_independent_variables())
1426 gradient.reinit(this->n_independent_variables(),
1427 true /*omit_zeroing_entries*/);
1428
1430 {
1431 Assert(this->active_tape_index() !=
1433 ExcMessage("Invalid tape index"));
1434 Assert(this->is_recording() == false,
1435 ExcMessage(
1436 "Cannot compute gradient while tape is being recorded."));
1437 Assert(this->independent_variable_values.size() ==
1438 this->n_independent_variables(),
1439 ExcDimensionMismatch(this->independent_variable_values.size(),
1440 this->n_independent_variables()));
1441
1442 this->taped_driver.gradient(this->active_tape_index(),
1443 this->independent_variable_values,
1444 gradient);
1445 }
1446 else
1447 {
1450 Assert(this->independent_variables.size() ==
1451 this->n_independent_variables(),
1452 ExcDimensionMismatch(this->independent_variables.size(),
1453 this->n_independent_variables()));
1454
1455 this->tapeless_driver.gradient(this->independent_variables,
1456 this->dependent_variables,
1457 gradient);
1458 }
1459
1460 // Account for symmetries of tensor components
1461 for (unsigned int i = 0; i < this->n_independent_variables(); ++i)
1462 {
1463 if (this->is_symmetric_independent_variable(i) == true)
1464 gradient[i] *= 0.5;
1465 }
1466 }
1467
1468
1469
1470 template <int dim,
1471 enum AD::NumberTypes ADNumberTypeCode,
1472 typename ScalarType>
1473 void
1475 FullMatrix<scalar_type> &hessian) const
1476 {
1478 ExcMessage(
1479 "Cannot computed function Hessian: AD number type does "
1480 "not support the calculation of second order derivatives."));
1481
1482 if ((ADNumberTraits<ad_type>::is_taped == true &&
1483 this->taped_driver.keep_independent_values() == false))
1484 {
1485 Assert(
1486 this->n_registered_independent_variables() ==
1487 this->n_independent_variables(),
1488 ExcMessage(
1489 "Not all values of sensitivities have been registered or subsequently set!"));
1490 }
1491 Assert(this->n_registered_dependent_variables() ==
1492 this->n_dependent_variables(),
1493 ExcMessage("Not all dependent variables have been registered."));
1494
1495 Assert(
1496 this->n_dependent_variables() == 1,
1497 ExcMessage(
1498 "The ScalarFunction class expects there to be only one dependent variable."));
1499
1500 // We can neglect correctly initializing the entries as
1501 // we'll be overwriting them immediately in the succeeding call to
1502 // Drivers::hessian().
1503 if (hessian.m() != this->n_independent_variables() ||
1504 hessian.n() != this->n_independent_variables())
1505 hessian.reinit({this->n_independent_variables(),
1506 this->n_independent_variables()},
1507 true /*omit_default_initialization*/);
1508
1510 {
1511 Assert(this->active_tape_index() !=
1513 ExcMessage("Invalid tape index"));
1514 Assert(this->is_recording() == false,
1515 ExcMessage(
1516 "Cannot compute Hessian while tape is being recorded."));
1517 Assert(this->independent_variable_values.size() ==
1518 this->n_independent_variables(),
1519 ExcDimensionMismatch(this->independent_variable_values.size(),
1520 this->n_independent_variables()));
1521
1522 this->taped_driver.hessian(this->active_tape_index(),
1523 this->independent_variable_values,
1524 hessian);
1525 }
1526 else
1527 {
1530 Assert(this->independent_variables.size() ==
1531 this->n_independent_variables(),
1532 ExcDimensionMismatch(this->independent_variables.size(),
1533 this->n_independent_variables()));
1534
1535 this->tapeless_driver.hessian(this->independent_variables,
1536 this->dependent_variables,
1537 hessian);
1538 }
1539
1540 // Account for symmetries of tensor components
1541 for (unsigned int i = 0; i < this->n_independent_variables(); ++i)
1542 for (unsigned int j = 0; j < i + 1; ++j)
1543 {
1544 if (this->is_symmetric_independent_variable(i) == true &&
1545 this->is_symmetric_independent_variable(j) == true)
1546 {
1547 hessian[i][j] *= 0.25;
1548 if (i != j)
1549 hessian[j][i] *= 0.25;
1550 }
1551 else if ((this->is_symmetric_independent_variable(i) == true &&
1552 this->is_symmetric_independent_variable(j) == false) ||
1553 (this->is_symmetric_independent_variable(j) == true &&
1554 this->is_symmetric_independent_variable(i) == false))
1555 {
1556 hessian[i][j] *= 0.5;
1557 if (i != j)
1558 hessian[j][i] *= 0.5;
1559 }
1560 }
1561 }
1562
1563
1564
1565 template <int dim,
1566 enum AD::NumberTypes ADNumberTypeCode,
1567 typename ScalarType>
1568 Tensor<
1569 0,
1570 dim,
1574 const FEValuesExtractors::Scalar &extractor_row,
1575 const FEValuesExtractors::Scalar &extractor_col)
1576 {
1577 // NOTE: It is necessary to make special provision for the case when the
1578 // HessianType is scalar. Unfortunately Tensor<0,dim> does not provide
1579 // the function unrolled_to_component_indices!
1580 // NOTE: The order of components must be consistently defined throughout
1581 // this class.
1583
1584 // Get indexsets for the subblocks from which we wish to extract the
1585 // matrix values
1586 const std::vector<unsigned int> row_index_set(
1587 internal::extract_field_component_indices<dim>(extractor_row));
1588 const std::vector<unsigned int> col_index_set(
1589 internal::extract_field_component_indices<dim>(extractor_col));
1590 Assert(row_index_set.size() == 1, ExcInternalError());
1591 Assert(col_index_set.size() == 1, ExcInternalError());
1592
1594 0,
1595 hessian[row_index_set[0]][col_index_set[0]]);
1596
1597 return out;
1598 }
1599
1600
1601
1602 template <int dim,
1603 enum AD::NumberTypes ADNumberTypeCode,
1604 typename ScalarType>
1606 4,
1607 dim,
1611 const FullMatrix<scalar_type> &hessian,
1612 const FEValuesExtractors::SymmetricTensor<2> &extractor_row,
1613 const FEValuesExtractors::SymmetricTensor<2> &extractor_col)
1614 {
1615 // NOTE: The order of components must be consistently defined throughout
1616 // this class.
1617 // NOTE: We require a specialisation for rank-4 symmetric tensors because
1618 // they do not define their rank, and setting data using TableIndices is
1619 // somewhat specialised as well.
1621
1622 // Get indexsets for the subblocks from which we wish to extract the
1623 // matrix values
1624 const std::vector<unsigned int> row_index_set(
1625 internal::extract_field_component_indices<dim>(extractor_row));
1626 const std::vector<unsigned int> col_index_set(
1627 internal::extract_field_component_indices<dim>(extractor_col));
1628
1629 for (unsigned int r = 0; r < row_index_set.size(); ++r)
1630 for (unsigned int c = 0; c < col_index_set.size(); ++c)
1631 {
1633 out, r, c, hessian[row_index_set[r]][col_index_set[c]]);
1634 }
1635
1636 return out;
1637 }
1638
1639
1640
1641 /* -------------------- VectorFunction -------------------- */
1642
1643
1644
1645 template <int dim,
1646 enum AD::NumberTypes ADNumberTypeCode,
1647 typename ScalarType>
1649 const unsigned int n_independent_variables,
1650 const unsigned int n_dependent_variables)
1651 : PointLevelFunctionsBase<dim, ADNumberTypeCode, ScalarType>(
1652 n_independent_variables,
1653 n_dependent_variables)
1654 {}
1655
1656
1657
1658 template <int dim,
1659 enum AD::NumberTypes ADNumberTypeCode,
1660 typename ScalarType>
1661 void
1663 register_dependent_variables(const std::vector<ad_type> &funcs)
1664 {
1665 Assert(funcs.size() == this->n_dependent_variables(),
1666 ExcMessage(
1667 "Vector size does not match number of dependent variables"));
1668 for (unsigned int i = 0; i < this->n_dependent_variables(); ++i)
1670 i, funcs[i]);
1671 }
1672
1673
1674
1675 template <int dim,
1676 enum AD::NumberTypes ADNumberTypeCode,
1677 typename ScalarType>
1678 void
1680 Vector<scalar_type> &values) const
1681 {
1682 if ((ADNumberTraits<ad_type>::is_taped == true &&
1683 this->taped_driver.keep_independent_values() == false) ||
1685 {
1686 Assert(
1687 this->n_registered_independent_variables() ==
1688 this->n_independent_variables(),
1689 ExcMessage(
1690 "Not all values of sensitivities have been registered or subsequently set!"));
1691 }
1692 Assert(this->n_registered_dependent_variables() ==
1693 this->n_dependent_variables(),
1694 ExcMessage("Not all dependent variables have been registered."));
1695
1696 // We can neglect correctly initializing the entries as
1697 // we'll be overwriting them immediately in the succeeding call to
1698 // Drivers::values().
1699 if (values.size() != this->n_dependent_variables())
1700 values.reinit(this->n_dependent_variables(),
1701 true /*omit_zeroing_entries*/);
1702
1704 {
1705 Assert(this->active_tape_index() !=
1707 ExcMessage("Invalid tape index"));
1708 Assert(this->is_recording() == false,
1709 ExcMessage(
1710 "Cannot compute values while tape is being recorded."));
1711 Assert(this->independent_variable_values.size() ==
1712 this->n_independent_variables(),
1713 ExcDimensionMismatch(this->independent_variable_values.size(),
1714 this->n_independent_variables()));
1715
1716 this->taped_driver.values(this->active_tape_index(),
1717 this->n_dependent_variables(),
1718 this->independent_variable_values,
1719 values);
1720 }
1721 else
1722 {
1725 this->tapeless_driver.values(this->dependent_variables, values);
1726 }
1727 }
1728
1729
1730
1731 template <int dim,
1732 enum AD::NumberTypes ADNumberTypeCode,
1733 typename ScalarType>
1734 void
1736 FullMatrix<scalar_type> &jacobian) const
1737 {
1738 if ((ADNumberTraits<ad_type>::is_taped == true &&
1739 this->taped_driver.keep_independent_values() == false) ||
1741 {
1742 Assert(
1743 this->n_registered_independent_variables() ==
1744 this->n_independent_variables(),
1745 ExcMessage(
1746 "Not all values of sensitivities have been registered or subsequently set!"));
1747 }
1748 Assert(this->n_registered_dependent_variables() ==
1749 this->n_dependent_variables(),
1750 ExcMessage("Not all dependent variables have been registered."));
1751
1752 // We can neglect correctly initializing the entries as
1753 // we'll be overwriting them immediately in the succeeding call to
1754 // Drivers::jacobian().
1755 if (jacobian.m() != this->n_dependent_variables() ||
1756 jacobian.n() != this->n_independent_variables())
1757 jacobian.reinit({this->n_dependent_variables(),
1758 this->n_independent_variables()},
1759 true /*omit_default_initialization*/);
1760
1762 {
1763 Assert(this->active_tape_index() !=
1765 ExcMessage("Invalid tape index"));
1766 Assert(this->is_recording() == false,
1767 ExcMessage(
1768 "Cannot compute Jacobian while tape is being recorded."));
1769 Assert(this->independent_variable_values.size() ==
1770 this->n_independent_variables(),
1771 ExcDimensionMismatch(this->independent_variable_values.size(),
1772 this->n_independent_variables()));
1773
1774 this->taped_driver.jacobian(this->active_tape_index(),
1775 this->n_dependent_variables(),
1776 this->independent_variable_values,
1777 jacobian);
1778 }
1779 else
1780 {
1783 Assert(this->independent_variables.size() ==
1784 this->n_independent_variables(),
1785 ExcDimensionMismatch(this->independent_variables.size(),
1786 this->n_independent_variables()));
1787
1788 this->tapeless_driver.jacobian(this->independent_variables,
1789 this->dependent_variables,
1790 jacobian);
1791 }
1792
1793 for (unsigned int j = 0; j < this->n_independent_variables(); ++j)
1794 {
1795 // Because we perform just a single differentiation
1796 // operation with respect to the "column" variables,
1797 // we only need to consider them for symmetry conditions.
1798 if (this->is_symmetric_independent_variable(j) == true)
1799 for (unsigned int i = 0; i < this->n_dependent_variables(); ++i)
1800 jacobian[i][j] *= 0.5;
1801 }
1802 }
1803
1804
1805
1806 template <int dim,
1807 enum AD::NumberTypes ADNumberTypeCode,
1808 typename ScalarType>
1809 Tensor<
1810 0,
1811 dim,
1815 const FullMatrix<scalar_type> &jacobian,
1816 const FEValuesExtractors::Scalar &extractor_row,
1817 const FEValuesExtractors::Scalar &extractor_col)
1818 {
1819 // NOTE: It is necessary to make special provision for the case when the
1820 // HessianType is scalar. Unfortunately Tensor<0,dim> does not provide
1821 // the function unrolled_to_component_indices!
1822 // NOTE: The order of components must be consistently defined throughout
1823 // this class.
1825
1826 // Get indexsets for the subblocks from which we wish to extract the
1827 // matrix values
1828 const std::vector<unsigned int> row_index_set(
1829 internal::extract_field_component_indices<dim>(extractor_row));
1830 const std::vector<unsigned int> col_index_set(
1831 internal::extract_field_component_indices<dim>(extractor_col));
1832 Assert(row_index_set.size() == 1, ExcInternalError());
1833 Assert(col_index_set.size() == 1, ExcInternalError());
1834
1836 0,
1837 jacobian[row_index_set[0]][col_index_set[0]]);
1838
1839 return out;
1840 }
1841
1842
1843
1844 template <int dim,
1845 enum AD::NumberTypes ADNumberTypeCode,
1846 typename ScalarType>
1848 4,
1849 dim,
1853 const FullMatrix<scalar_type> &jacobian,
1854 const FEValuesExtractors::SymmetricTensor<2> &extractor_row,
1855 const FEValuesExtractors::SymmetricTensor<2> &extractor_col)
1856 {
1857 // NOTE: The order of components must be consistently defined throughout
1858 // this class.
1859 // NOTE: We require a specialisation for rank-4 symmetric tensors because
1860 // they do not define their rank, and setting data using TableIndices is
1861 // somewhat specialised as well.
1863
1864 // Get indexsets for the subblocks from which we wish to extract the
1865 // matrix values
1866 const std::vector<unsigned int> row_index_set(
1867 internal::extract_field_component_indices<dim>(extractor_row));
1868 const std::vector<unsigned int> col_index_set(
1869 internal::extract_field_component_indices<dim>(extractor_col));
1870
1871 for (unsigned int r = 0; r < row_index_set.size(); ++r)
1872 for (unsigned int c = 0; c < col_index_set.size(); ++c)
1873 {
1875 out, r, c, jacobian[row_index_set[r]][col_index_set[c]]);
1876 }
1877
1878 return out;
1879 }
1880
1881
1882 } // namespace AD
1883} // namespace Differentiation
1884
1885
1886/* --- Explicit instantiations --- */
1887# include "differentiation/ad/ad_helpers.inst"
1888
1889# ifdef DEAL_II_WITH_ADOLC
1890# include "differentiation/ad/ad_helpers.inst1"
1891# endif
1892# ifdef DEAL_II_TRILINOS_WITH_SACADO
1893# include "differentiation/ad/ad_helpers.inst2"
1894# endif
1895
1896
1897
1898#endif // defined(DEAL_II_WITH_ADOLC) || defined(DEAL_II_TRILINOS_WITH_SACADO)
const std::vector< ad_type > & get_sensitive_dof_values() const
typename HelperBase< ADNumberTypeCode, ScalarType >::ad_type ad_type
Definition ad_helpers.h:850
void set_dof_values(const std::vector< scalar_type > &dof_values)
void register_dof_values(const std::vector< scalar_type > &dof_values)
CellLevelBase(const unsigned int n_independent_variables, const unsigned int n_dependent_variables)
void register_energy_functional(const ad_type &energy)
EnergyFunctional(const unsigned int n_independent_variables)
typename HelperBase< ADNumberTypeCode, ScalarType >::ad_type ad_type
void compute_residual(Vector< scalar_type > &residual) const override
virtual void compute_linearization(FullMatrix< scalar_type > &linearization) const override
typename HelperBase< ADNumberTypeCode, ScalarType >::scalar_type scalar_type
unsigned int n_registered_dependent_variables() const
void stop_recording_operations(const bool write_tapes_to_file=false)
typename AD::NumberTraits< ScalarType, ADNumberTypeCode >::scalar_type scalar_type
Definition ad_helpers.h:177
Types< ad_type >::tape_index active_tape_index() const
void print_tape_stats(const typename Types< ad_type >::tape_index tape_index, std::ostream &stream) const
std::size_t n_independent_variables() const
bool start_recording_operations(const typename Types< ad_type >::tape_index tape_index, const bool overwrite_tape=false, const bool keep_independent_values=true)
void mark_independent_variable(const unsigned int index, ad_type &out) const
bool is_registered_tape(const typename Types< ad_type >::tape_index tape_index) const
void reset_registered_dependent_variables(const bool flag=false)
Definition ad_helpers.cc:96
void activate_tape(const typename Types< ad_type >::tape_index tape_index, const bool read_mode)
void set_tape_buffer_sizes(const typename Types< ad_type >::tape_buffer_sizes obufsize=64 *1024 *1024, const typename Types< ad_type >::tape_buffer_sizes lbufsize=64 *1024 *1024, const typename Types< ad_type >::tape_buffer_sizes vbufsize=64 *1024 *1024, const typename Types< ad_type >::tape_buffer_sizes tbufsize=64 *1024 *1024)
void print(std::ostream &stream) const
void set_sensitivity_value(const unsigned int index, const scalar_type &value)
bool active_tape_requires_retaping() const
HelperBase(const unsigned int n_independent_variables, const unsigned int n_dependent_variables)
Definition ad_helpers.cc:40
virtual void reset(const unsigned int n_independent_variables=::numbers::invalid_unsigned_int, const unsigned int n_dependent_variables=::numbers::invalid_unsigned_int, const bool clear_registered_tapes=true)
bool recorded_tape_requires_retaping(const typename Types< ad_type >::tape_index tape_index) const
std::vector< ad_type > dependent_variables
Definition ad_helpers.h:749
std::size_t n_dependent_variables() const
void print_values(std::ostream &stream) const
void register_dependent_variable(const unsigned int index, const ad_type &func)
static void configure_tapeless_mode(const unsigned int n_independent_variables, const bool ensure_persistent_setting=true)
void initialize_non_sensitive_independent_variable(const unsigned int index, ad_type &out) const
typename AD::NumberTraits< ScalarType, ADNumberTypeCode >::ad_type ad_type
Definition ad_helpers.h:184
void activate_recorded_tape(const typename Types< ad_type >::tape_index tape_index)
bool is_symmetric_independent_variable(const unsigned int index) const
PointLevelFunctionsBase(const unsigned int n_independent_variables, const unsigned int n_dependent_variables)
void set_independent_variables(const std::vector< scalar_type > &values)
typename HelperBase< ADNumberTypeCode, ScalarType >::scalar_type scalar_type
unsigned int n_symmetric_independent_variables() const
void register_independent_variables(const std::vector< scalar_type > &values)
void set_sensitivity_value(const unsigned int index, const bool symmetric_component, const scalar_type &value)
const std::vector< ad_type > & get_sensitive_variables() const
virtual void reset(const unsigned int n_independent_variables=::numbers::invalid_unsigned_int, const unsigned int n_dependent_variables=::numbers::invalid_unsigned_int, const bool clear_registered_tapes=true) override
ResidualLinearization(const unsigned int n_independent_variables, const unsigned int n_dependent_variables)
virtual void compute_residual(Vector< scalar_type > &residual) const override
virtual void compute_linearization(FullMatrix< scalar_type > &linearization) const override
void register_residual_vector(const std::vector< ad_type > &residual)
static internal::ScalarFieldHessian< dim, scalar_type, ExtractorType_Row, ExtractorType_Col >::type extract_hessian_component(const FullMatrix< scalar_type > &hessian, const ExtractorType_Row &extractor_row, const ExtractorType_Col &extractor_col)
typename HelperBase< ADNumberTypeCode, ScalarType >::ad_type ad_type
void register_dependent_variable(const ad_type &func)
ScalarFunction(const unsigned int n_independent_variables)
void compute_gradient(Vector< scalar_type > &gradient) const
void compute_hessian(FullMatrix< scalar_type > &hessian) const
typename HelperBase< ADNumberTypeCode, ScalarType >::scalar_type scalar_type
void compute_values(Vector< scalar_type > &values) const
void register_dependent_variables(const std::vector< ad_type > &funcs)
void compute_jacobian(FullMatrix< scalar_type > &jacobian) const
typename HelperBase< ADNumberTypeCode, ScalarType >::scalar_type scalar_type
static internal::VectorFieldJacobian< dim, scalar_type, ExtractorType_Row, ExtractorType_Col >::type extract_jacobian_component(const FullMatrix< scalar_type > &jacobian, const ExtractorType_Row &extractor_row, const ExtractorType_Col &extractor_col)
VectorFunction(const unsigned int n_independent_variables, const unsigned int n_dependent_variables)
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
#define Assert(cond, exc)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
static ::ExceptionBase & ExcMessage(std::string arg1)
void set_tensor_entry(TensorType &t, const unsigned int unrolled_index, const NumberType &value)
constexpr unsigned int invalid_unsigned_int
Definition types.h:228
static const Types< ADNumberType >::tape_index invalid_tape_index
Definition ad_drivers.h:119
static void initialize_global_environment(const unsigned int n_independent_variables)