MarmotNumericalDifferentiationForFastor.h
Go to the documentation of this file.
1 /* ---------------------------------------------------------------------
2  * _
3  * _ __ ___ __ _ _ __ _ __ ___ ___ | |_
4  * | '_ ` _ \ / _` | '__| '_ ` _ \ / _ \| __|
5  * | | | | | | (_| | | | | | | | | (_) | |_
6  * |_| |_| |_|\__,_|_| |_| |_| |_|\___/ \__|
7  *
8  * Unit of Strength of Materials and Structural Analysis
9  * University of Innsbruck,
10  * 2020 - today
11  *
12  * festigkeitslehre@uibk.ac.at
13  *
14  * Alexander Dummer alexander.dummer@uibk.ac.at
15  *
16  * This file is part of the MAteRialMOdellingToolbox (marmot).
17  *
18  * This library is free software; you can redistribute it and/or
19  * modify it under the terms of the GNU Lesser General Public
20  * License as published by the Free Software Foundation; either
21  * version 2.1 of the License, or (at your option) any later version.
22  *
23  * The full text of the license can be found in the file LICENSE.md at
24  * the top level directory of marmot.
25  * ---------------------------------------------------------------------
26  */
27 
28 #pragma once
29 #include "Fastor/Fastor.h"
30 #include "Marmot/MarmotConstants.h"
32 #include "Marmot/MarmotMath.h"
34 #include "Marmot/MarmotTypedefs.h"
35 #include <Fastor/config/macros.h>
36 #include <Fastor/tensor/Tensor.h>
37 #include <functional>
38 
39 namespace Marmot {
40  namespace NumericalAlgorithms::Differentiation {
41 
42  namespace ScalarToTensor {
43 
44  template < size_t... Rest >
45  Fastor::Tensor< double, Rest... > forwardDifference(
46  const std::function< Fastor::Tensor< double, Rest... >( const double ) >& F,
47  const double x )
48  {
49 
50  double volatile h = std::max( 1.0, std::abs( x ) ) * Marmot::Constants::SquareRootEps;
51  Fastor::Tensor< double, Rest... > dF = F( x + h ) - F( x );
52  Fastor::Tensor< double, Rest... > dF_dx = multiplyFastorTensorWithScalar( dF, 1. / h );
53  return dF_dx;
54  }
55 
56  template < size_t... Rest >
57  Fastor::Tensor< double, Rest... > centralDifference(
58  const std::function< Fastor::Tensor< double, Rest... >( const double ) >& F,
59  const double x )
60  {
61 
62  double volatile h = std::max( 1.0, std::abs( x ) ) * Marmot::Constants::CubicRootEps;
63  Fastor::Tensor< double, Rest... > dF = F( x + h ) - F( x - h );
64  Fastor::Tensor< double, Rest... > dF_dx = multiplyFastorTensorWithScalar( dF, 1. / ( 2. * h ) );
65  return dF_dx;
66  }
67  } // namespace ScalarToTensor
68 
69  namespace TensorToScalar {
70 
71  template < size_t... Rest >
72  using tensor_to_scalar_function_type = std::function< double( const Fastor::Tensor< double, Rest... >& T ) >;
73 
74  /* template < size_t... Rest > */
75  /* Fastor::Tensor< double, Rest... > forwardDifference( const tensor_to_scalar_function_type< Rest... >& F, */
76  /* const Fastor::Tensor< double, Rest... >& T ) */
77  /* { */
78 
79  /* Fastor::Tensor< double, Rest... > dF_dT; */
80  /* const Fastor::Tensor< double, Rest... > F_ = F( T ); */
81  /* Fastor::Tensor< double, Rest... > T_right = T; */
82 
83  /* double* dF_dT_data = dF_dT.data(); */
84  /* double* T_right_data = T_right.data(); */
85 
86  /* for ( Fastor::FASTOR_INDEX i = 0; i < T.size(); ++i ) { */
87  /* const int dF_dT_mem_idx = dF_dT.get_mem_index( i ); */
88  /* const int T_right_mem_idx = T_right.get_mem_index( i ); */
89  /* double volatile h = std::max( 1.0, std::abs( double( T_right_data[T_right_mem_idx] ) ) ) * */
90  /* Marmot::Constants::SquareRootEps; */
91  /* T_right_data[T_right_mem_idx] += h; */
92  /* dF_dT_data[dF_dT_mem_idx] = ( F( T_right ) - F_ ) / ( 1. * h ); */
93  /* T_right_data[T_right_mem_idx] -= h; */
94  /* } */
95 
96  template < size_t dim >
97  Fastor::Tensor< double, dim, dim > forwardDifference( const tensor_to_scalar_function_type< dim, dim >& f,
98  const Fastor::Tensor< double, dim, dim >& T )
99  {
100  Fastor::Tensor< double, dim, dim > T_right( T );
101  Fastor::Tensor< double, dim, dim > dF_dT( 0.0 );
102  const double f_ = f( T );
103 
104  for ( size_t i = 0; i < dim; i++ ) {
105  for ( size_t j = 0; j < dim; j++ ) {
106  double volatile h = std::max( 1.0, std::abs( T( i, j ) ) ) * Marmot::Constants::SquareRootEps;
107 
108  T_right( i, j ) += h;
109  dF_dT( i, j ) = ( f( T_right ) - f_ ) / ( 1. * h );
110  T_right( i, j ) -= h;
111  }
112  }
113 
114  return dF_dT;
115  }
116 
117  template < size_t dim >
118  Fastor::Tensor< double, dim, dim > centralDifference( const tensor_to_scalar_function_type< dim, dim >& F,
119  const Fastor::Tensor< double, dim, dim >& T )
120  {
121 
122  Fastor::Tensor< double, dim, dim > dF_dT;
123  Fastor::Tensor< double, dim, dim > T_right( T );
124  Fastor::Tensor< double, dim, dim > T_left( T );
125 
126  for ( size_t i = 0; i < dim; i++ ) {
127  for ( size_t j = 0; j < dim; j++ ) {
128  double volatile h = std::max( 1.0, std::abs( T( i, j ) ) ) * Marmot::Constants::CubicRootEps;
129 
130  T_right = T;
131  T_left = T;
132  T_right( i, j ) += h;
133  T_left( i, j ) -= h;
134 
135  dF_dT( i, j ) = ( F( T_right ) - F( T_left ) ) / ( 2. * h );
136  }
137  }
138 
139  return dF_dT;
140  }
141  } // namespace TensorToScalar
142 
143  namespace TensorToTensor {
144 
145  template < size_t... RestF, size_t... RestT >
146  Fastor::Tensor< double, RestF..., RestT... > forwardDifference(
147  const std::function< Fastor::Tensor< double, RestF... >( const Fastor::Tensor< double, RestT... >& ) >& F,
148  const Fastor::Tensor< double, RestT... >& T )
149  {
150 
151  Fastor::Tensor< double, RestF..., RestT... > dF_dT( 0.0 );
152  Fastor::Tensor< double, RestT... > T_right( T );
153 
154  Fastor::Tensor< double, RestF... > F_at_T = F( T );
155  Fastor::Tensor< double, RestF... > F_at_T_right( 0.0 );
156 
157  double* dF_dT_data = dF_dT.data();
158  double* T_right_data = T_right.data();
159  double* F_at_T_data = F_at_T.data();
160  double* F_at_T_right_data = F_at_T_right.data();
161 
162  for ( Fastor::FASTOR_INDEX i = 0; i < T.size(); ++i ) {
163  const int T_right_mem_idx = T_right.get_mem_index( i );
164  double volatile h = std::max( 1.0, std::abs( double( T.data()[T_right_mem_idx] ) ) ) *
166  T_right = T;
167  T_right_data[T_right_mem_idx] += h;
168  F_at_T_right = F( T_right );
169 
170  for ( Fastor::FASTOR_INDEX j = 0; j < F_at_T_right.size(); ++j ) {
171  dF_dT_data[dF_dT.get_mem_index( j * T.size() + i )] = ( F_at_T_right_data[F_at_T_right.get_mem_index( j )] -
172  F_at_T_data[F_at_T.get_mem_index( j )] ) /
173  ( 1. * h );
174  }
175  }
176 
177  return dF_dT;
178  }
179 
180  template < size_t... Rest1, size_t... Rest2 >
181  Fastor::Tensor< double, Rest1..., Rest2... > centralDifference(
182  const std::function< Fastor::Tensor< double, Rest1... >( const Fastor::Tensor< double, Rest2... >& ) >& F,
183  const Fastor::Tensor< double, Rest2... >& T )
184  {
185 
186  Fastor::Tensor< double, Rest1..., Rest2... > dF_dT( 0.0 );
187  Fastor::Tensor< double, Rest2... > T_right( T );
188  Fastor::Tensor< double, Rest2... > T_left( T );
189 
190  Fastor::Tensor< double, Rest1... > F_at_T_right( 0.0 );
191  Fastor::Tensor< double, Rest1... > F_at_T_left( 0.0 );
192 
193  double* dF_dT_data = dF_dT.data();
194  double* T_right_data = T_right.data();
195  double* T_left_data = T_left.data();
196  double* F_at_T_right_data = F_at_T_right.data();
197  double* F_at_T_left_data = F_at_T_left.data();
198 
199  for ( Fastor::FASTOR_INDEX i = 0; i < T.size(); ++i ) {
200  const int T_right_mem_idx = T_right.get_mem_index( i );
201  const int T_left_mem_idx = T_left.get_mem_index( i );
202  double volatile h = std::max( 1.0, std::abs( double( T.data()[T_right_mem_idx] ) ) ) *
204  T_left = T;
205  T_left_data[T_left_mem_idx] -= h;
206  F_at_T_left = F( T_left );
207 
208  T_right = T;
209  T_right_data[T_right_mem_idx] += h;
210  F_at_T_right = F( T_right );
211 
212  for ( Fastor::FASTOR_INDEX j = 0; j < F_at_T_right.size(); ++j ) {
213  dF_dT_data[dF_dT.get_mem_index( j * T.size() + i )] = ( F_at_T_right_data[F_at_T_right.get_mem_index( j )] -
214  F_at_T_left_data[F_at_T_left.get_mem_index( j )] ) /
215  ( 2. * h );
216  }
217  }
218 
219  return dF_dT;
220  }
221  } // namespace TensorToTensor
222 
223  namespace Complex {
224 
225  using complexDouble = std::complex< double >;
226  static const double imaginaryPerturbationSize = 1e-20;
228 
229  template < size_t dim >
230  using tensor_to_scalar_function_type = std::function< std::complex< double >(
231  const Fastor::Tensor< std::complex< double >, dim, dim >& T ) >;
232 
233  template < size_t dim >
234  Fastor::Tensor< double, dim, dim > forwardDifference( const tensor_to_scalar_function_type< dim >& F,
235  const Fastor::Tensor< double, dim, dim >& T )
236  {
237  Fastor::Tensor< double, dim, dim > dF_dT;
238  Fastor::Tensor< std::complex< double >, dim, dim >
239  T_right = fastorTensorFromDoubleTensor< std::complex< double >, dim >( T );
240 
241  for ( size_t i = 0; i < dim; i++ ) {
242  for ( size_t j = 0; j < dim; j++ ) {
243  T_right( i, j ) += imaginaryPerturbation;
244 
245  dF_dT( i, j ) = F( T_right ).imag() / imaginaryPerturbationSize;
246 
247  T_right( i, j ) -= imaginaryPerturbation;
248  }
249  }
250 
251  return dF_dT;
252  }
253  namespace ScalarToTensor {
254 
255  template < size_t... Rest >
256  std::tuple< Fastor::Tensor< double, Rest... >, Fastor::Tensor< double, Rest... > > forwardDifference(
257  const std::function< Fastor::Tensor< complexDouble, Rest... >( const complexDouble ) >& F,
258  const double x )
259  {
260  const complexDouble xRight = x + imaginaryPerturbation;
261  Fastor::Tensor< complexDouble, Rest... > F_ = F( xRight );
262  Fastor::Tensor< double, Rest... > dF_dx( 0.0 );
263  Fastor::Tensor< double, Rest... > FReal( 0.0 );
264  complexDouble* F_data = F_.data();
265  double* dF_dx_data = dF_dx.data();
266  double* FReal_data = FReal.data();
267 
268  for ( Fastor::FASTOR_INDEX j = 0; j < F_.size(); ++j ) {
269  FReal_data[FReal.get_mem_index( j )] = F_data[F_.get_mem_index( j )].real();
270  dF_dx_data[dF_dx.get_mem_index( j )] = F_data[F_.get_mem_index( j )].imag() / imaginaryPerturbationSize;
271  }
272 
273  return { FReal, dF_dx };
274  }
275  } // namespace ScalarToTensor
276 
277  namespace TensorToScalar {
278 
279  template < size_t... Rest >
281  const Fastor::Tensor< complexDouble, Rest... >& T ) >;
282 
283  template < size_t dim >
284  Fastor::Tensor< double, dim, dim > forwardDifference( const tensor_to_scalar_function_type< dim, dim >& f,
285  const Fastor::Tensor< double, dim, dim >& T )
286  {
287  Fastor::Tensor< complexDouble, dim, dim > T_right = fastorTensorFromDoubleTensor< complexDouble >( T );
288  Fastor::Tensor< double, dim, dim > dF_dT( 0.0 );
289 
290  for ( size_t i = 0; i < dim; i++ ) {
291  for ( size_t j = 0; j < dim; j++ ) {
292 
293  T_right( i, j ) += imaginaryPerturbation;
294  dF_dT( i, j ) = f( T_right ).imag() / imaginaryPerturbationSize;
295  T_right( i, j ) -= imaginaryPerturbation;
296  }
297  }
298 
299  return dF_dT;
300  /* Fastor::Tensor< double, Rest... > dF_dT; */
301  /* Fastor::Tensor< complexDouble, Rest... > T_right = fastorTensorFromDoubleTensor<complexDouble>(T); */
302 
303  /* double* dF_dT_data = dF_dT.data(); */
304  /* complexDouble* T_right_data = T_right.data(); */
305 
306  /* for ( Fastor::FASTOR_INDEX i = 0; i < T.size(); ++i ) { */
307  /* const int dF_dT_mem_idx = dF_dT.get_mem_index( i ); */
308  /* const int T_right_mem_idx = T_right.get_mem_index( i ); */
309  /* T_right_data[T_right_mem_idx] += imaginaryPerturbation; */
310  /* dF_dT_data[dF_dT_mem_idx] = f( T_right )/ imaginaryPerturbationSize; */
311  /* T_right_data[T_right_mem_idx] -= imaginaryPerturbation; */
312  /* } */
313 
314  /* return dF_dT; */
315  }
316  } // namespace TensorToScalar
317  namespace TensorToTensor {
318  template < size_t... RestF, size_t... RestT >
319  Fastor::Tensor< double, RestF..., RestT... > forwardDifference(
320  std::function<
321  Fastor::Tensor< complexDouble, RestF... >( const Fastor::Tensor< complexDouble, RestT... >& ) >& F,
322  const Fastor::Tensor< double, RestT... >& T )
323  {
324 
325  Fastor::Tensor< double, RestF..., RestT... > dF_dT( 0.0 );
326  Fastor::Tensor< complexDouble, RestT... > T_right = fastorTensorFromDoubleTensor< complexDouble >( T );
327 
328  Fastor::Tensor< complexDouble, RestF... > F_at_T_right( 0.0 );
329 
330  double* dF_dT_data = dF_dT.data();
331  complexDouble* T_right_data = T_right.data();
332  complexDouble* F_at_T_right_data = F_at_T_right.data();
333 
334  for ( Fastor::FASTOR_INDEX i = 0; i < T.size(); ++i ) {
335  const int T_right_mem_idx = T_right.get_mem_index( i );
336 
337  T_right_data[T_right_mem_idx] += imaginaryPerturbation;
338  F_at_T_right = F( T_right );
339 
340  for ( Fastor::FASTOR_INDEX j = 0; j < F_at_T_right.size(); ++j ) {
341  dF_dT_data[dF_dT.get_mem_index( j * T.size() +
342  i )] = ( F_at_T_right_data[F_at_T_right.get_mem_index( j )] ).imag() /
344  }
345  T_right_data[T_right_mem_idx] -= imaginaryPerturbation;
346  }
347 
348  return dF_dT;
349  }
350  } // namespace TensorToTensor
351  } // namespace Complex
352  } // namespace NumericalAlgorithms::Differentiation
353 } // namespace Marmot
Marmot::NumericalAlgorithms::Differentiation::ScalarToTensor::forwardDifference
Fastor::Tensor< double, Rest... > forwardDifference(const std::function< Fastor::Tensor< double, Rest... >(const double) > &F, const double x)
Definition: MarmotNumericalDifferentiationForFastor.h:45
Marmot::FastorIndices::i
Fastor::Index< i_ > i
Definition: MarmotFastorTensorBasics.h:137
MarmotConstants.h
Marmot::NumericalAlgorithms::Differentiation::Complex::TensorToScalar::tensor_to_scalar_function_type
std::function< complexDouble(const Fastor::Tensor< complexDouble, Rest... > &T) > tensor_to_scalar_function_type
Definition: MarmotNumericalDifferentiationForFastor.h:281
MarmotFastorTensorBasics.h
Marmot::Constants::SquareRootEps
const double SquareRootEps
Definition: MarmotConstants.h:48
Marmot::NumericalAlgorithms::Differentiation::Complex::complexDouble
std::complex< double > complexDouble
Definition: MarmotNumericalDifferentiationForFastor.h:225
Marmot::multiplyFastorTensorWithScalar
Fastor::Tensor< T, Rest... > multiplyFastorTensorWithScalar(Fastor::Tensor< T, Rest... > tensor, T scalar)
Definition: MarmotFastorTensorBasics.h:338
Marmot::NumericalAlgorithms::Differentiation::Complex::imaginaryPerturbationSize
static const double imaginaryPerturbationSize
Definition: MarmotNumericalDifferentiationForFastor.h:226
MarmotTypedefs.h
MarmotMath.h
Marmot::AutomaticDifferentiation::dF_dT
std::pair< Fastor::Tensor< double, RestF... >, Fastor::Tensor< double, RestF..., RestT... > > dF_dT(std::function< Fastor::Tensor< dual, RestF... >(const Fastor::Tensor< dual, RestT... > &) > &F, const Fastor::Tensor< double, RestT... > &T)
Definition: MarmotAutomaticDifferentiationForFastor.h:114
MarmotNumericalDifferentiation.h
Marmot::NumericalAlgorithms::Differentiation::TensorToScalar::tensor_to_scalar_function_type
std::function< double(const Fastor::Tensor< double, Rest... > &T) > tensor_to_scalar_function_type
Definition: MarmotNumericalDifferentiationForFastor.h:72
Marmot::NumericalAlgorithms::Differentiation::TensorToScalar::centralDifference
Fastor::Tensor< double, dim, dim > centralDifference(const tensor_to_scalar_function_type< dim, dim > &F, const Fastor::Tensor< double, dim, dim > &T)
Definition: MarmotNumericalDifferentiationForFastor.h:118
Marmot::NumericalAlgorithms::Differentiation::Complex::forwardDifference
double forwardDifference(const scalar_to_scalar_function_type &f, const double x)
Definition: MarmotNumericalDifferentiation.cpp:84
Marmot::Constants::CubicRootEps
const double CubicRootEps
Definition: MarmotConstants.h:49
Marmot::NumericalAlgorithms::Differentiation::ScalarToTensor::centralDifference
Fastor::Tensor< double, Rest... > centralDifference(const std::function< Fastor::Tensor< double, Rest... >(const double) > &F, const double x)
Definition: MarmotNumericalDifferentiationForFastor.h:57
Marmot::FastorIndices::j
Fastor::Index< j_ > j
Definition: MarmotFastorTensorBasics.h:182
Marmot
This file includes functions needed for calculations with stress and strain tensors written in voigt ...
Definition: MarmotTesting.h:37
Marmot::NumericalAlgorithms::Differentiation::TensorToTensor::forwardDifference
Fastor::Tensor< double, RestF..., RestT... > forwardDifference(const std::function< Fastor::Tensor< double, RestF... >(const Fastor::Tensor< double, RestT... > &) > &F, const Fastor::Tensor< double, RestT... > &T)
Definition: MarmotNumericalDifferentiationForFastor.h:146
Marmot::NumericalAlgorithms::Differentiation::Complex::TensorToScalar::forwardDifference
Fastor::Tensor< double, dim, dim > forwardDifference(const tensor_to_scalar_function_type< dim, dim > &f, const Fastor::Tensor< double, dim, dim > &T)
Definition: MarmotNumericalDifferentiationForFastor.h:284
Marmot::NumericalAlgorithms::Differentiation::TensorToTensor::centralDifference
Fastor::Tensor< double, Rest1..., Rest2... > centralDifference(const std::function< Fastor::Tensor< double, Rest1... >(const Fastor::Tensor< double, Rest2... > &) > &F, const Fastor::Tensor< double, Rest2... > &T)
Definition: MarmotNumericalDifferentiationForFastor.h:181
Marmot::NumericalAlgorithms::Differentiation::Complex::TensorToTensor::forwardDifference
Fastor::Tensor< double, RestF..., RestT... > forwardDifference(std::function< Fastor::Tensor< complexDouble, RestF... >(const Fastor::Tensor< complexDouble, RestT... > &) > &F, const Fastor::Tensor< double, RestT... > &T)
Definition: MarmotNumericalDifferentiationForFastor.h:319
Marmot::NumericalAlgorithms::Differentiation::Complex::ScalarToTensor::forwardDifference
std::tuple< Fastor::Tensor< double, Rest... >, Fastor::Tensor< double, Rest... > > forwardDifference(const std::function< Fastor::Tensor< complexDouble, Rest... >(const complexDouble) > &F, const double x)
Definition: MarmotNumericalDifferentiationForFastor.h:256
Marmot::FiniteElement::EAS::F
Eigen::MatrixXd F(const Eigen::MatrixXd &J)
Marmot::NumericalAlgorithms::Differentiation::TensorToScalar::forwardDifference
Fastor::Tensor< double, dim, dim > forwardDifference(const tensor_to_scalar_function_type< dim, dim > &f, const Fastor::Tensor< double, dim, dim > &T)
Definition: MarmotNumericalDifferentiationForFastor.h:97
Marmot::NumericalAlgorithms::Differentiation::Complex::tensor_to_scalar_function_type
std::function< std::complex< double >(const Fastor::Tensor< std::complex< double >, dim, dim > &T) > tensor_to_scalar_function_type
Definition: MarmotNumericalDifferentiationForFastor.h:231
Marmot::NumericalAlgorithms::Differentiation::Complex::imaginaryPerturbation
static const complexDouble imaginaryPerturbation
Definition: MarmotNumericalDifferentiationForFastor.h:227
Marmot::NumericalAlgorithms::Differentiation::Complex::imaginaryUnit
static const std::complex< double > imaginaryUnit
Definition: MarmotNumericalDifferentiation.h:47