smdogroup / tacs

Finite-element library for analysis and adjoint-based gradient evaluation
Apache License 2.0
108 stars 75 forks source link

Gaussian Process Buckling Constraints in Blade Stiffened Shell Constitutive Subclass #311

Closed sean-engelstad closed 3 weeks ago

sean-engelstad commented 6 months ago

This code is linked to the repo, ml_buckling

TODO:

timryanb commented 6 months ago

@sean-engelstad, before you go further down this path, you should review the element routines that already exists. There already exists sub-routines to compute the mass centroid, moments of inertia, etc. Please review them to avoid duplicating code.

A-CGray commented 6 months ago

Also @sean-engelstad , not sure how you're intending to do the panel length/width computation but you may be able to re-use what I have implemented in the panel length constraint

sean-engelstad commented 6 months ago

@A-CGray I decided to replicate what you did with the panel length constraint, with some small modifications for the panel width constraint. I will just add some code into FUNtoFEM to compute chain rule products of panel length, panel width DVs with the coordinate derivatives sensitivities for our workflow.

sean-engelstad commented 6 months ago

Updates 5/13/2024:

sean-engelstad commented 6 months ago

Update: internal tests for ML in the loop now pass! Next steps: test the failure criterion, etc. and other external tests on the constitutive object. Below is a finite difference test with h = 1e-8 central difference approximation compared to an analytic derivative implemented by hand.

Real Mode: Internal tests

TACSGPBladeStiffened..testAllTests full results::
        testNondimensionalParameters = 1.8179e-07
        testAxialCriticalLoads = 1.3995e-08
        testShearCriticalLoads = 8.3006e-08
        testStiffenerCripplingLoad = 9.8267e-11
        testAxialGP all tests = 1.6610e-08
        testShearGP all tests = 1.6610e-08
        testCripplingGp all tests = 6.2022e-06
        Overall max rel error = 6.2022e-06

Complex Mode: Internal Tests

TACSGPBladeStiffened..testAllTests full results::
        testNondimensionalParameters = 1.0644e-15
        testAxialCriticalLoads = 1.5943e-16
        testShearCriticalLoads = 1.2744e-13
        testStiffenerCripplingLoad = 0.0000e+00
        testAxialGP all tests = 1.5187e-16
        testShearGP all tests = 1.5832e-16
        testCripplingGp all tests = 2.3355e-15
        Overall max rel error = 1.2744e-13
sean-engelstad commented 6 months ago

Complex mode, failStrain test : now passes

Testing the derivative of the failure index w.r.t. strain for object TACSBladeStiffenedShellConstitutive
Max Err: 2.1316e-14 in component 0.
Max REr: 1.0542e-13 in component 4.
          Val[   ]                  Analytic               Approximate                Rel. Error                Abs. Error
d(failure)/de[  0]   -3.8007334173280654e+01   -3.8007334173280633e+01    5.6084654544881153e-16    2.1316282072803006e-14
d(failure)/de[  1]   -3.2745208408550816e+01   -3.2745208408550795e+01    6.5097408472247376e-16    2.1316282072803006e-14
d(failure)/de[  2]    5.9636778818554667e+01    5.9636778818554667e+01    0.0000000000000000e+00    0.0000000000000000e+00
d(failure)/de[  3]    1.2952084768476078e+00    1.2952084768476078e+00    0.0000000000000000e+00    0.0000000000000000e+00
d(failure)/de[  4]   -1.0530991148876019e-03   -1.0530991148874908e-03    1.0542436214503594e-13    1.1102230246251565e-16
d(failure)/de[  5]   -1.0137600641731894e-03   -1.0137600641732471e-03    5.6896653966408030e-14    5.7679555576228836e-17
d(failure)/de[  6]    0.0000000000000000e+00    0.0000000000000000e+00                         -    0.0000000000000000e+00
d(failure)/de[  7]    0.0000000000000000e+00    0.0000000000000000e+00                         -    0.0000000000000000e+00
d(failure)/de[  8]    0.0000000000000000e+00    0.0000000000000000e+00                         -    0.0000000000000000e+00
sean-engelstad commented 6 months ago

Current status 5/15/24, complex mode failDV test: some fail Here the DV nums are: [0 - panelLength, 1 - stiffPitch, 2 - panelThick, (3,4,5) - panel ply fracs, 6 - stiffHeight, 7 - stiffThick, (8,9) - stiff ply fracs, 10 - panelWidth]

First without including fails[4] the stiffenerCripplingFailure (so just modes 0-3): all pass

          Val[   ]                  Analytic               Approximate                Rel. Error                Abs. Error
d(failure)/dx[  0]   -2.4917262482262680e-08   -2.4917262482262584e-08    3.8508624743370405e-15    9.5952951056151210e-23
d(failure)/dx[  1]    8.0933741616030596e-06    8.0933741616022278e-06    1.0277374276726334e-13    8.3178635420372293e-19
d(failure)/dx[  2]   -1.9482058118457711e-03   -1.9482058118457898e-03    9.5720263502769913e-15    1.8648277366750676e-17
d(failure)/dx[  3]    6.7302757747794399e-07    6.7302757747499854e-07    4.3764197687246176e-12    2.9454511949584226e-18
d(failure)/dx[  4]    1.1597891871193940e-05    1.1597891871193598e-05    2.9505475175250075e-14    3.4220131069073734e-19
d(failure)/dx[  5]    1.6880611895570803e-06    1.6880611895569016e-06    1.0587528045566319e-13    1.7872395187065737e-19
d(failure)/dx[  6]   -4.5169088937689061e-03   -4.5169088937689009e-03    1.1521530653650334e-15    5.2041704279304213e-18
d(failure)/dx[  7]   -4.5157033072326432e-03   -4.5157033072326406e-03    5.7623033156264800e-16    2.6020852139652106e-18
d(failure)/dx[  8]   -2.5854634340644107e-06   -2.5854634340634307e-06    3.7904891906863540e-13    9.8001711997322549e-19
d(failure)/dx[  9]   -9.5013497223568452e-07   -9.5013497223557398e-07    1.1633904955271950e-13    1.1053779961668619e-19
d(failure)/dx[ 10]    6.4420860130355276e-06    6.4420860130358563e-06    5.1015894986442694e-14    3.2864878353466853e-19

then with including the last failure mode stiffenerCrippling, i.e. fails[4] : some fail namely : 2 - panelThick, 6 - stiffHeight, 7 - stiffThick, (8,9) - stiff ply fracs

Max REr: 1.7883e+00 in component 9.
          Val[   ]                  Analytic               Approximate                Rel. Error                Abs. Error
d(failure)/dx[  0]   -6.2705971332282821e-09   -6.2705971332282821e-09    0.0000000000000000e+00    0.0000000000000000e+00
d(failure)/dx[  1]    1.2217607868101255e-06    1.2217607868103621e-06    1.9360086939627522e-13    2.3653395052076337e-19
d(failure)/dx[  2]   -1.1136900671107634e-03   -1.1135051243354465e-03    1.6609063692208262e-04    1.8494277531687711e-07
d(failure)/dx[  3]    3.0617404435500533e-07    3.0617404435514281e-07    4.4903883195187083e-13    1.3748403525121362e-19
d(failure)/dx[  4]    3.0617404435500533e-07    3.0617404435514281e-07    4.4903883195187083e-13    1.3748403525121362e-19
d(failure)/dx[  5]    3.0617404435500533e-07    3.0617404435514281e-07    4.4903883195187083e-13    1.3748403525121362e-19
d(failure)/dx[  6]   -3.3680506906615644e-03   -3.3679479446752786e-03    3.0506999506418792e-05    1.0274598628585291e-07
d(failure)/dx[  7]   -3.3615820013972115e-03   -3.3608341791145349e-03    2.2251091330950385e-04    7.4782228267657180e-07
d(failure)/dx[  8]   -6.0862821095854106e-07   -2.1827890922525383e-07    1.7883051693760510e+00    3.9034930173328723e-07
d(failure)/dx[  9]   -6.0862821095854127e-07   -2.1827890922525352e-07    1.7883051693760561e+00    3.9034930173328776e-07
d(failure)/dx[ 10]    1.0686834227945663e-06    1.0686834227943772e-06    1.7694679400946116e-13    1.8910010547452255e-19
sean-engelstad commented 6 months ago

All the failureDV tests pass now! A few small fixes with the strain transform computation from panelStrain -> stiffenerStrain did the trick. Another problem was a local variable t was supposed to be stiffener thick but was actually panelThick because wasn't redefined locally.

All 10 tests pass now! namely in the test script test_gp_blade_shell_constitutive.py

Complex step test of failure DV test

Max Err: 1.8865e-17 in component 2.
Max REr: 4.3805e-12 in component 3.
          Val[   ]                  Analytic               Approximate                Rel. Error                Abs. Error
d(failure)/dx[  0]   -3.2584854162225586e-08   -3.2584854162225474e-08    3.4524188062079851e-15    1.1249656330721176e-22
d(failure)/dx[  1]    8.0933749272162201e-06    8.0933749272153866e-06    1.0298304818370740e-13    8.3348042009823153e-19
d(failure)/dx[  2]   -1.9474018924833293e-03   -1.9474018924833482e-03    9.6873264188886932e-15    1.8865117801247777e-17
d(failure)/dx[  3]    6.7302764114468927e-07    6.7302764114174107e-07    4.3805096132984838e-12    2.9482040520369991e-18
d(failure)/dx[  4]    1.1597892968325800e-05    1.1597892968325456e-05    2.9651539079076256e-14    3.4389537658524594e-19
d(failure)/dx[  5]    1.6880613492434901e-06    1.6880613492433107e-06    1.0625160433979342e-13    1.7935922658109810e-19
d(failure)/dx[  6]   -4.5232780788233059e-03   -4.5232780788233033e-03    5.7526536476884563e-16    2.6020852139652106e-18
d(failure)/dx[  7]   -4.5084343173967456e-03   -4.5084343173967430e-03    5.7715939299027094e-16    2.6020852139652106e-18
d(failure)/dx[  8]   -3.4248925127256912e-06   -3.4248925127247099e-06    2.8651634051237215e-13    9.8128766939410694e-19
d(failure)/dx[  9]   -6.8563572486820331e-07   -6.8563572486809235e-07    1.6183712730497074e-13    1.1096131609031334e-19
d(failure)/dx[ 10]    6.4420866224409167e-06    6.4420866224412454e-06    5.1015890160465777e-14    3.2864878353466853e-19

Result of all 10 constitutive tests in complex mode

..........
----------------------------------------------------------------------
Ran 10 tests in 0.015s

OK
sean-engelstad commented 6 months ago

Fixed a problem with the Newton iteration abs tolerance (too strict and couldn't converge due to floating point limit). Switched to relative tolerance and added max_iter limit for Newton iteration in closed-form solution for shear critical loads.

sean-engelstad commented 1 month ago

@A-CGray @timryanb I merged in your code Ali and tried just overwriting the evalLocalPanelBuckling, evalGlobalPanelBuckling methods to use the base class computeFailureValues method. However, these buckling load methods are not virtual so even though I define a new evalLocalPanelBuckling method, it still uses your method. I could copy and paste your computeFailureValues method into my subclass, but then we have code duplication.

Maybe you can store the function pointers and lambda expressions used for the buckling load predictions => and use those in the computeFailureValues method in the base class. And then I can change the value in the function pointers in my subclass. @A-CGray I might take a crack at this for you to review

sean-engelstad commented 1 month ago

I recovered the same buckling load predictions as before (for low aspect ratios) with the new implementation by overwriting Ali's methods (also I did use the functors and lambda expressions approach). Here before and after merge refer to my results after I merged with Ali's PR that was merged.

Low aspect ratio panel

TACS GP closed-form (before merge): N11,cr =  6,057,629 N/m  N12,cr = 18,523,089 N/m
TACS GP closed-form (after merge)   : N11,cr = 6.0576e6 N/m,   N12,cr = 1.8523089e7 N/m

High aspect ratio panel

TACS GP closed-form (before merge) : N11,cr = 1.141e6 N/m,  N12,cr = 1.01e6 N/m
TACS GP closed-form (after merge)    : N11,cr = 1.141e6 N/m,  N12,cr =  1.01e6 N/m
sean-engelstad commented 1 month ago

I'm ready for you guys to review it now @timryanb @A-CGray. I did implement function pointers and lambda expressions in order to remove the code duplication from Ali's BladeStiffenedShellConstitutive class

sean-engelstad commented 1 month ago

@A-CGray, ok I switched to virtual functions in your base class for the methods that I need to override in my subclass and use the override keyword (optional but extra compiler check) for the methods I override. I double checked that my buckling load predictions are still the same as well. No functors or lambda expressions now so much cleaner

sean-engelstad commented 1 month ago

@timryanb I finished adding the docstrings for all methods, classes in the constitutive.pyx file that I added.

timryanb commented 4 weeks ago

@A-CGray, did you have a chance to take a look at this?

sean-engelstad commented 3 weeks ago

Hey @sean-engelstad this is really good work. I have a lot of comments but they're mostly duplicates about using new and delete[] in places that you don't need to. I commented all the examples of this that I saw in the constitutive class, I think there are some more cases in the GPModel classes that I didn't leave comments on but should still be fixed.

Also, you could add a panel width constraint to this integration test that already tests the panel length constraint

Thanks @A-CGray, I'm resolving the comment discussions as I go through and update the code if that's good with you. For comments where there might be more discussion I'll leave it unresolved

sean-engelstad commented 3 weeks ago

@A-CGray @timryanb, alright I'm done addressing all the items in Ali's review. The only point left up for debate is whether I should change my constitutive object to be a subclass of Ali's in constitutive.pyx which would cleanup a few repeated methods. It caused me quite a bit of problems last time I tried that, but maybe I would be able to figure it out now since I have more experience with the Cython.

Also I verified that the buckling loads still match my trained ML models in ml_buckling repo, so the changes I made didn't break anything.

timryanb commented 3 weeks ago

@sean-engelstad @A-CGray, I believe it should be possible to make this class into a cython sub-class. Both the GP and regular version of the cython class would have to inherit from a parent base class that held the common API between the two classes.

An example of this would be the ShellConstitutive parent class that all shell constitutive classes inherit from (IsoShellConstitutive, CompShellConstitutive, etc.).

In this case you could add the new common baseclass to the constitutive.pxd file like below:

cdef class StiffenedShellConstitutive(ShellConstitutive):
    cdef TACSBladeStiffenedShellConstitutive *base_ptr

 cdef class BladeStiffenedShellConstitutive(StiffenedShellConstitutive):
    cdef TACSBladeStiffenedShellConstitutive *blade_ptr

cdef class GPBladeStiffenedShell(StiffenedShellConstitutive):
    cdef TACSGPBladeStiffenedShell *blade_ptr

You can then add the API to the constitutive.pyx file using ShellConstitutive as a template (see here)

Both your and @A-CGray's class would have to be updated in the constitutive.pyx file to inherit from this new class rather than ShellConstitutive

Also make sure to set the cptr, base_ptr, and blade_ptr during the cinit for both of your classes, see here for example

sean-engelstad commented 3 weeks ago

Ok @timryanb @A-CGray => I removed the redundant code in constitutive.pyx using Tim's suggestions. As long as these tests pass, it should be good to go now.

sean-engelstad commented 3 weeks ago

@timryanb Wait => don't merge it yet, there is a problem when running on big cases right now which I've traced back to incref(). Unittests pass, but large case doesn't work at the moment

sean-engelstad commented 3 weeks ago

Update: I needed to also store one of the other constitutive subclass ptrs namely cptr otherwise constructing any elements (from element.pyx) will fail in self.cptr.incref(). So I added the copy self.cptr = back in the constructors

sean-engelstad commented 3 weeks ago

@timryanb should be good to merge now if you wanna take one more look. I can run the wing examples and the tests pass now with the updates to constitutive.pyx

timryanb commented 3 weeks ago

I should be able to take a look at it sometime tomorrow @sean-engelstad

timryanb commented 3 weeks ago

@sean-engelstad also can you add your new panel constraints to the constraint autodocs list here. You just have to add the name of the python file in the constraints module folder that your new code lives in

sean-engelstad commented 3 weeks ago

@timryanb - ok I added the docs for panel width and fixed constitutive.pyx

sean-engelstad commented 3 weeks ago

@timryanb I fixed the docs mistake you just caught