Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ShapeOpt] [WIP] Adding new response with stress aggregation for optimization #5682

Open
wants to merge 15 commits into
base: master
Choose a base branch
from

Conversation

dbaumgaertner
Copy link
Member

@dbaumgaertner dbaumgaertner commented Sep 27, 2019

This PR adds a new response function which allows for stress aggregation using the Kreisselmeier Steinhauser (KS) function.

By that, stress constraints may be considered over big parts of a structural domain whereas the given functionalities in Kratos only allowed for a single maximum value (whose location may heavily jump around). See figure below for an impression. There, a loaded hook structure is optimized for mass, while the stress in each element of the structure is not allowed to exceed a maximum value (dark red). The color plot shows the stresses on the surface for a constant value range. It can be seen, that the stresses significantly increase when reducing the mass (removing material). But they always stay within the specified limits.

ezgif com-crop (2)

This branch is not yet ready to be merged as it revealed an existing problem with thread safety in the current adjoint solution approach in case several elements are considered within the given stress response functions.

Also, this PR first requires an approval and merge of #4364.

Roadmap:

@dbaumgaertner dbaumgaertner self-assigned this Sep 27, 2019
@dbaumgaertner dbaumgaertner changed the title [ShapeOpt] [WIP] Feature ks stress aggregation new [ShapeOpt] [WIP] Adding feature for stress aggregation in optimization Sep 27, 2019
@dbaumgaertner dbaumgaertner changed the title [ShapeOpt] [WIP] Adding feature for stress aggregation in optimization [ShapeOpt] [WIP] Adding new response with stress aggregation for optimization Sep 27, 2019
@dbaumgaertner
Copy link
Member Author

Observations regarding the problematic race conditions so far:

  1. A workaround that eliminates the race condition is to manually set the number of omp threads to 1 just before the StructuralMechanicsAdjointStaticSolver is initialized and reset it to the max values when it is finalized.

  2. The problem gets visible in form of fluctuating shape sensitivities (dJdX) with reach new run.

  3. The race condition only appears when a finite differencing is part of the computation of sensitivities. That is if all partial derivatives involving finite differencing (dpKdpX and dpJdpx) are hard set some values, then the shape sensitivity does not fluctuate anymore.

  4. The adjoint variables are not subjected to the racing conditions and have constant values. This is because, in the case of stress constraints, the right-hand side of the adjoint system (-dpJdpu) is computed analytically and does not involve a finite differencing.

  5. The fluctuating shape sensitivities appear because the function CalculateOnIntegrationPoints(VON_MISES_STRESS,...) sometimes returns meaningless or overly high stress values when it is called through the gradient functions within the class AdjointAggregatedStressResponseFunction. Noteworthy is that the stress values are fine when CalculateOnIntegrationPoints is called directly from a primal element (such as when the value of the response function is computed). By contrast, it returns nonsense values when called through the adjoint element which then internally calls the primal element (happens when the response function calculates its local gradients). So the problem seems to originate from the connection of primal and adjoint elements.

Copy link
Member

@philbucher philbucher left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor

else:
raise Exception("invalid response_type: " + response_type)

self.sensitivity_builder = KratosMultiphysics.SensitivityBuilder(self.settings["sensitivity_settings"], self.main_model_part, self.response_function)
self.sensitivity_builder.Initialize()

self.max_number_of_threads = KratosMultiphysics.OpenMPUtils.GetNumThreads()
KratosMultiphysics.OpenMPUtils.SetNumThreads(1)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

blocking until this is resolved
As you pointed out this should not go into Master

@@ -15,18 +15,23 @@ def CreateResponseFunction(response_id, response_settings, model):
elif response_type == "eigenfrequency":
return structural_response.EigenFrequencyResponseFunction(response_id, response_settings, model)

elif response_type == "adjoint_nodal_displacement":
elif response_type == "adjoint_nodal_displacement" or\
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
elif response_type == "adjoint_nodal_displacement" or\
elif response_type in ["adjoint_nodal_displacement", "adjoint_linear_strain_energy", ...]:

this would be another alternative of doing this

@armingeiser
Copy link
Member

FYI @MFusseder the mentioned bug might be relevant for you as well.

@armingeiser
Copy link
Member

The race condition only appears when a finite differencing is part of the computation of sensitivities. That is if all partial derivatives involving finite differencing (dpKdpX and dpJdpx) are hard set some values, then the shape sensitivity does not fluctuate anymore.

Is dpKdpX also causing problems? Because that is calculated in all other adjoint structural responses as well and there it seems to work (because it is called in serial).
dpJdpx until now was always just dependent on one node (or nodes of one element or even 0). Now with this response it is the first time that all nodal positions have an influence.

By contrast, it returns nonsense values when called through the adjoint element which then internally calls the primal element (happens when the response function calculates its local gradients). So the problem seems to originate from the connection of primal and adjoint elements.

The calculation of stress values at element level is threadsafe - so i would not expect that the calculation of simply the values does create any problems - also not when called from within the adjoints element at the primal element.

The finite differencing of derivatives w.r.t. node coordinates is not thread safe. Thats why i still guess that doing this in parallel is the root of the problem.

@MFusseder
Copy link
Member

MFusseder commented Nov 18, 2019

After using this new response for some days I have a comment. Within CalculateValue you compute also the values for the members mStressScalingFactor, mKSPrefactors and mSumPrefactors which are later needed in order to provide the partial derivatives. This approach perfectly works if you use structural_response.py. But if one uses directly a StructuralMechanicsAnalysis to solve the adjoint problem the function CalculateValueis not called. Therefor a extra custom running script would be needed. In principle I would propose to compute the values for member variables within InitializeSolutionStep of the response but this will lead to the problem that the primal model part is there not available. Right now I also have no better solution for this issue as to call CalculateValue but we should think about the fundamental problem that currently we have insufficient access to primal results (like stresses) during the computation of the partial derivatives which is needed for some responses as this example shows.

@dbaumgaertner
Copy link
Member Author

dbaumgaertner commented Nov 20, 2019

As discussed in person: Indeed this is a problem. But for the sake of getting a first draft up and running, it was implemented this way. The main problem is, that the primal model part is only available in the CalculateValue() function. This again is due to the given structure of the adjoint analysis and requires a much deeper restructuring. Therefore, we first need to find a solution to the previous problem. That is why this PR is just WIP.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants