Closed msandre closed 6 years ago
Hi @msandre a quick question:
Hi @RiccardoRossi thanks for the comments.
The rationale was mainly the proximity to the schemes in the core (the dependency points from adjoint scheme to response function). In this sense, the dependency is local to solving_strategies directory.
I am pasting the results of the first iteration (bold still needs to be resolved):
Q: Where should the ResponseFunction path be located? A: In kratos/solving_strategies/response_functions. Possible scheme dependencies on response function are then contained in kratos/solving_strategies.
Q: What should be implemented in the ResponseFunction base class? A: General assembly of sensitivities from adjoint and partial derivatives. Only the functions that depend on the type of response function, are implemented in the derived class. These include CalculateValue() and CalculatePartialSensitivity(). The base implementation will be based on AdjointStructuralResponseFunction.
Q: Where should we call UpdateSensitivities()? At first we thought in FinalizeSolutionStep() since a scheme is not always present to call UpdateSensitivities. Then interpreting @RiccardoRossi's comment with @jcotela and @sunethwarna, we thought there would be a potential problem with complicated analyses (such as plasticity) where the order in which different processes and strategies execute FinalizeSolutionStep() could cause incorrect program behavior. The new proposal is to call UpdateSensitivities() in the python level from the python solver (which is now also the owner of the response function) separately from the usual FinalizeSolutionStep block.
Q: Should the ModelPart be passed as a function parameter or accessed as a member variable in the ResponseFunction? A: Member variable. This way the model part does not have to accompany the response function and the response function can avoid performing checks on the validity of the model part for every function call.
Q: Should CalculateValue() be pure virtual. A: Yes. It is safer than having a meaningless default return value. It should always be defined.
Q: NEW How should we name the optimizer's response function python interface and the response function in c++ The c++ response function is responsible for defining the drag, strain energy, etc. and their partial sensitivities. The optimizer's response function python interface is used to update the solution (e.g., solve the primal/adjoint solutions) and return the new response function value or sensitivities. We are proposing to handle the python class as a stage. Thus, it would have a name like OptimizationStage or ResponseStage and share the interface of a stage.
There is enough convergence here that we can add the c++ response function to the core as long as there are no further concerns and we can agree to keep the name ResponseFunction.
Q: Where should we call UpdateSensitivities()? I think calling it directly from python is a nice idea to have full flexibility. It will also work for our special case of the strain energy response. @MFusseder any objections?
Q: NEW How should we name the optimizer's response function python interface and the response function in c++ Thinking about the response python interfaces as a stage (that itself has primal and adjoint analysis stage) is what I also had in mind when i created them. So in the optimization we would have a list of ResponseStages ( i don't like OptimizationStage). @dbaumgaertner what do you think?
I would also call it ResponseStage or ResponseFunctionStage. OptimizationStage is clearly the wrong name here as the actual optimization has a whole lot more things around the actual response function.
Ok, I think we can move forward with the response function and defer decisions about the stage until later. I will close this issue then. Thanks.
Several months ago we defined the response function interface (see https://github.com/KratosMultiphysics/Kratos/wiki/Adjoint-API#response-functions). Now we have at least two (rather large) branches which use this (for @KratosMultiphysics/structural-mechanics in #1804 and from the fluid side in https://github.com/KratosMultiphysics/Kratos/tree/migrate-response-function-to-core).
Below I've started a list of issues to be resolved so that we can bring these developments closer together and ease merging them into the master. As a first step I propose we add a ResponseFunction base class as the response function interface to the core (as a separate PR) and update our branches to use this. For example, this will help us to use the structural response functions with the adjoint solvers in the other branch.
Where should the ResponseFunction path be located? In the branch it is
kratos/solving_strategies/response_functions
. Any objections? @KratosMultiphysics/technical-committee.In our separate developments we both added a function to compute partial sensitivities of the response function. In @KratosMultiphysics/structural-mechanics it is a protected member called
ResponseFunction::CalculateSensitivityGradient()
. In the other branch we haveResponseFunctionSensitivityBuilderUtility::CalculatePartialSensitivity()
. Both are used as customization points in a general algorithm, which is implemented in the base class, for assembling sensitivities (template method pattern). Can we put this assembly in the core or should we defer it to the applications? To me it is appealing to have something in the core for multiphysics problems. I also prefer the design of @MFusseder / @armingeiser over the one I started since it doesn't split the response function over more than one class.Where should we call
UpdateSensitivities()
? In structural mechanics they do it inResponseFunction::FinalizeSolutionStep()
, but in other parts we called it from theScheme::Update()
. We need to be consistent here so that the modules can work with each other. Are there any strong arguments for one or the other? If not I would edge towards FinalizeSolutionStep() due to the fact that the scheme is not always present.We usually need access to the model part when we call
Initialize(), UpdateSensitivities(), CalculateValue()
. Should the ModelPart be a member of the ResponseFunction like in #1804 or should it be passed as a function parameter like in https://github.com/KratosMultiphysics/Kratos/tree/migrate-response-function-to-core? I am in favor of the second since the ResponseFunction is usually belonging to the scheme and is called in the scheme which passes the model part as a function parameter. For example:CalculateValue()
method for which there is not appropriate default. This ensures that a concrete definition of the response function exists (comments may be ambiguous). Could we makeCalculateValue()
a pure virtual function?