KratosMultiphysics / Kratos

Kratos Multiphysics (A.K.A Kratos) is a framework for building parallel multi-disciplinary simulation software. Modularity, extensibility and HPC are the main objectives. Kratos has BSD license and is written in C++ with extensive Python interface.
https://kratosmultiphysics.github.io/Kratos/
Other
1.03k stars 245 forks source link

[StructMech][Sensitivity] Finite differencing of structural element matrices and vectors #8375

Closed emiroglu closed 3 years ago

emiroglu commented 3 years ago

Description For the implementation of the modal derivatives as in #8174, and also later on some further implementations, I need to compute the derivatives of several element matrices/vectors. For this, I perform a local finite differencing at the scheme level for each element and each DOF (when rotations are included in the model they have to be perturbed too) but I could not find a consistent way of computing this. The reason mostly being the element internal variables being updated when InitializeNonLinerIteration or FinalizeNonLinearIteration is called. Calling these functions are necessary for some elements, while it is absolutely no go for others. The terms I need to compute are as follows:

here u being degrees of freedom and p some material parameter, such as DENSITY, YOUNG_MODULUS, POISSON_RATIO, THICKNESS etc.

Imagine the workflow and the calls to initialize/finalize functions to be like this and that the same model is being fed to each simulation to include the initial displacement effects.

  1. Static Nonlinear Analysis: this is optional when there isn't any initial loading, sets SolutionStepValue. At each nonlinear iteration 1.i. InitializeNonlinearIteration 1.ii. Solve 1.iii. FinalizeNonlinearIteration
  2. Eigenvalue analysis: does not set SolutionStepValue but updates element internal variables through initialize/finalize 2.i. InitializeNonlinearIteration 2.ii. Solve 2.iii. FinalizeNonlinearIteration
  3. Modal Derivative Analysis: modifies SolutionStepValue temporarily for the derivatives. 3.i. InitializeNonlinearIteration 3.ii. Compute for each element and assemble. 4.iii. Solve 3.iv. Compute for each element and assemble. 5.v Compute for each element and assemble.

One of the problems is that when initialize/finalize is called in eigenvalue analysis, the historical data is updated for the elements that need incremental deformations (CR formulations for example.) and as there isn't any deformation happening there, the increment is set to zero. Consecutively, initialize is also called in the modal derivative analysis which I think makes it impossible to reach the historical variables for these elements. Second problem shows up also in the finite differencing step. Some elements actually need initialize/finalize called so that the internals are updated. But then there is no way of setting them back or setting them back before history is lost.

@armingeiser suggested to Save/Load the element using a Serializer but these functions are protected members of the element class which makes it impossible to use without modifying the base.

I already talked to @MFusseder @KlausBSautter @armingeiser about these, but we could not really find a solution. I believe similar problems should also show up with some adjoint response functions too.

Any comments, helps, etc are very much appreciated since this blocked the implementation for very long time and I believe will remain a problem for the sensitivity analysis in general too.

emiroglu commented 3 years ago

Apparently the convergence criterion in the static analysis plays also a big part in the results. What is the difference in using displacement_criterion or residual_criterion? Does some variable get updated additionally when one or another is used?

philbucher commented 3 years ago

my gut says that you shouldn't call Initialize/FinalizeNonLinIter between the finite differencing steps. Otherwise as you say the internals get updated which means that you will have a different "starting point" for the next step

=> i.e. the elements should compute on the fly what they need

philbucher commented 3 years ago

@armingeiser @MFusseder how are you doing this? you only have linear sensitivities right?

and some time ago in the master thesis you used the serializer if I remember correctly no?

emiroglu commented 3 years ago

my gut says that you shouldn't call Initialize/FinalizeNonLinIter between the finite differencing steps. Otherwise as you say the internals get updated which means that you will have a different "starting point" for the next step

=> i.e. the elements should compute on the fly what they need

this is exactly the problem. the increment is computed using element internals and they cannot be updated without initialize/finalize. when it is updated there is no going back. -> not possible to do finite differencing

armingeiser commented 3 years ago

@mahmoudsesa has used the serializer in order to load the state of a certain load step in a nln analysis into the adjoint elements, in order to do the finite differencing. He needed to do that, because he needed to compute the sensitivities for several load steps after doing the primal nln analysis once.

However, he did only compute the derivatives of LHS and RHS w.r.t the parameters, not the dofs.

@emiroglu, does the finite differencing for computation of derivatives w.r.t parameters also irreversibly change the state of the element or does this only happen when you disturb the dofs?

armingeiser commented 3 years ago

updated there is no going back.

Is it not possible to:

Then the element should be back at its state from before the finite differencing, no?

emiroglu commented 3 years ago

Then the increment becomes wrong. Well the more important is the quaternion I think which is a dependent variable for the rotation matrices. I will give it a try though but as far as I remember it was giving wrong results

armingeiser commented 3 years ago

I just think that there has to be a way to revert a displacement, otherwise a loading-deloading cycle would not be possible?

emiroglu commented 3 years ago

updated there is no going back.

Is it not possible to:

  • apply disturbance
  • initialize
  • calculate
  • finalize
  • revert disturbance
  • initialize
  • finalize

Then the element should be back at its state from before the finite differencing, no?

With the current implementation (because the element internals are updated in the initialize function instead of finalize) of the CRBeam element it only works like this for central differencing:

This does not feel very intuitive (calling finalize before initialize...) to be honest and I am not sure if this is generalizable. Would this apply to the corotational shells too?

emiroglu commented 3 years ago

The order of the calls in my last message seems to be working with ShellThickElementCorotational3D4N too. With this I am closing this issue since it seems to be working for quite some elements. I tested the following elements:

I will extend the list if I test and validate with more elements.