diff --git a/src/elements/basis/TACSHexaBasis.cpp b/src/elements/basis/TACSHexaBasis.cpp index e83fcde2e..5264d61bd 100644 --- a/src/elements/basis/TACSHexaBasis.cpp +++ b/src/elements/basis/TACSHexaBasis.cpp @@ -65,8 +65,8 @@ static void getFaceTangents(int face, double t[]) { t[1] = 0.0; t[2] = 0.0; t[3] = 0.0; - t[4] = 0.0; - t[5] = 1.0; + t[4] = 1.0; + t[5] = 0.0; } } diff --git a/tacs/problems/base.py b/tacs/problems/base.py index 0877bcd09..cdfa22ea9 100644 --- a/tacs/problems/base.py +++ b/tacs/problems/base.py @@ -1006,11 +1006,11 @@ def _addPressureFromPLOAD4(self, auxElems, loadInfo, scale=1.0): Add pressure to tacs static/transient problem from pynastran PLOAD4 card. Should only be called by createTACSProbsFromBDF and not directly by user. """ - # Dictionary mapping nastran element face indices to TACS equivilent numbering + # Dictionary mapping nastran element face indices to TACS equivalent numbering nastranToTACSFaceIDDict = { "CTETRA4": {1: 1, 2: 3, 3: 2, 4: 0}, "CTETRA": {2: 1, 4: 3, 3: 2, 1: 0}, - "CHEXA": {1: 4, 2: 2, 3: 0, 4: 3, 5: 0, 6: 5}, + "CHEXA": {1: 4, 2: 2, 3: 1, 4: 3, 5: 0, 6: 5}, } # We don't support pressure variation across elements, for now just average it diff --git a/tests/integration_tests/input_files/two_hexs.bdf b/tests/integration_tests/input_files/two_hexs.bdf new file mode 100644 index 000000000..ed5c35e7d --- /dev/null +++ b/tests/integration_tests/input_files/two_hexs.bdf @@ -0,0 +1,101 @@ +INIT MASTER(S) +NASTRAN SYSTEM(442)=-1,SYSTEM(319)=1 +ID FEMAP,FEMAP +SOL SESTATIC +CEND + TITLE = Simcenter Nastran Static Analysis Set + ECHO = NONE + DISPLACEMENT(PLOT) = ALL + SPCFORCE(PLOT) = ALL + OLOAD(PLOT) = ALL + FORCE(PLOT,CORNER) = ALL + STRESS(PLOT,CORNER) = ALL +SUBCASE 1 + SUBTITLE = Clamp_+X + SPC = 1 + LOAD = 1 +SUBCASE 2 + SUBTITLE = Clamp_+Y + SPC = 1 + LOAD = 2 +SUBCASE 3 + SUBTITLE = Clamp_-X + SPC = 1 + LOAD = 3 +SUBCASE 4 + SUBTITLE = Clamp_-Y + SPC = 1 + LOAD = 4 +SUBCASE 5 + SUBTITLE = Clamp_+Z + SPC = 1 + LOAD = 5 +SUBCASE 6 + SUBTITLE = Clamp_-Z + SPC = 1 + LOAD = 6 +BEGIN BULK +$ *************************************************************************** +$ Written by : Femap +$ Version : 2021.1.0 +$ Translator : Simcenter Nastran +$ From Model : +$ Date : Thu Apr 13 10:18:32 2023 +$ Output To : C:\Users\trbrooks\AppData\Local\Temp\2\ +$ *************************************************************************** +$ +PARAM,PRGPST,YES +PARAM,POST,-1 +PARAM,OGEOM,NO +PARAM,AUTOSPC,YES +PARAM,K6ROT,100. +PARAM,GRDPNT,0 +CORD2C 1 0 0. 0. 0. 0. 0. 1.+FEMAPC1 ++FEMAPC1 1. 0. 1. +CORD2S 2 0 0. 0. 0. 0. 0. 1.+FEMAPC2 ++FEMAPC2 1. 0. 1. +$ Femap Load Set 1 : Forces +PLOAD4 1 3-100000. 2 9 +PLOAD4 1 4-100000. 3 10 +$ Femap Load Set 2 : +Y +PLOAD4 2 4-100000. 4 11 +$ Femap Load Set 3 : -X +PLOAD4 3 3-100000. 6 7 +PLOAD4 3 4-100000. 5 12 +$ Femap Load Set 4 : -Y +PLOAD4 4 3-100000. 1 8 +$ Femap Load Set 5 : +Z +PLOAD4 5 3-100000. 7 9 +PLOAD4 5 4-100000. 12 10 +$ Femap Load Set 6 : -Z +PLOAD4 6 3-100000. 1 3 +PLOAD4 6 4-100000. 6 4 +$ Femap Constraint Set 1 : Clamp +SPC1 1 123456 1 +SPC1 1 123456 5 +SPC1 1 123456 6 +SPC1 1 123456 7 +SPC1 1 123456 11 +SPC1 1 123456 12 +$ Femap Property 1 : Dummy +PSOLID 1 1 0 +$ Femap Material 1 : Aluminum +MAT1 1 7.+5 .3 2.700 0. 0. + ++ 2.7+3 +GRID 1 0 0. 0. 0. 0 +GRID 2 0 1. 0. 0. 0 +GRID 3 0 1. 1. 0. 0 +GRID 4 0 1. 2. 0. 0 +GRID 5 0 0. 2. 0. 0 +GRID 6 0 0. 1. 0. 0 +GRID 7 0 0. 0. 1. 0 +GRID 8 0 1. 0. 1. 0 +GRID 9 0 1. 1. 1. 0 +GRID 10 0 1. 2. 1. 0 +GRID 11 0 0. 2. 1. 0 +GRID 12 0 0. 1. 1. 0 +CHEXA 3 1 1 2 3 6 7 8+ ++ 9 12 +CHEXA 4 1 6 3 4 5 12 9+ ++ 10 11 +ENDDATA \ No newline at end of file diff --git a/tests/integration_tests/test_elast_linhexa_pressure_3d.py b/tests/integration_tests/test_elast_linhexa_pressure_3d.py new file mode 100644 index 000000000..53d0de1ec --- /dev/null +++ b/tests/integration_tests/test_elast_linhexa_pressure_3d.py @@ -0,0 +1,147 @@ +import os + +from pytacs_analysis_base_test import PyTACSTestCase +from tacs import pytacs, functions + +""" +This model features two adjacent linear hex elements, clamped on one face. +Six load conditions are considered: a pressure applied to each of the six faces using PLOAD4 cards. +This test verifies that pyTACS/TACS applies pressure load on the consistent face based on the PLOAD4 information. + +tests KSDisplacement, StructuralMass, and Compliance functions and sensitivities. +""" + +base_dir = os.path.dirname(os.path.abspath(__file__)) +bdf_file = os.path.join(base_dir, "./input_files/two_hexs.bdf") + +ksweight = 10.0 + + +class ProblemTest(PyTACSTestCase.PyTACSTest): + N_PROCS = 2 # this is how many MPI processes to use for this TestCase. + + FUNC_REFS = { + "Clamp_+X_-x_disp": -0.2716543418951961, + "Clamp_+X_-y_disp": 0.1944965504786221, + "Clamp_+X_-z_disp": 0.1122082988741163, + "Clamp_+X_compliance": 25788.7451098405, + "Clamp_+X_mass": 5.400000000000001, + "Clamp_+X_x_disp": 1.0274069094117648, + "Clamp_+X_y_disp": 0.19449655047862183, + "Clamp_+X_z_disp": 0.11220829887411632, + "Clamp_+Y_-x_disp": 0.372199546911399, + "Clamp_+Y_-y_disp": -0.2108822590307131, + "Clamp_+Y_-z_disp": 0.07859767285648897, + "Clamp_+Y_compliance": 11409.61367995888, + "Clamp_+Y_mass": 5.400000000000001, + "Clamp_+Y_x_disp": 0.10005467583046843, + "Clamp_+Y_y_disp": 1.4357366919830612, + "Clamp_+Y_z_disp": 0.07859767285648912, + "Clamp_-X_-x_disp": 0.06931471805599453, + "Clamp_-X_-y_disp": 0.06931471805599453, + "Clamp_-X_-z_disp": 0.06931471805599453, + "Clamp_-X_compliance": 0.0, + "Clamp_-X_mass": 5.400000000000001, + "Clamp_-X_x_disp": 0.06931471805599453, + "Clamp_-X_y_disp": 0.06931471805599453, + "Clamp_-X_z_disp": 0.06931471805599453, + "Clamp_-Y_-x_disp": 0.37219954691139895, + "Clamp_-Y_-y_disp": 1.435736691983061, + "Clamp_-Y_-z_disp": 0.0785976728564891, + "Clamp_-Y_compliance": 11409.61367995888, + "Clamp_-Y_mass": 5.400000000000001, + "Clamp_-Y_x_disp": 0.10005467583046848, + "Clamp_-Y_y_disp": -0.21088225903071312, + "Clamp_-Y_z_disp": 0.07859767285648898, + "Clamp_+Z_-x_disp": 0.6483960432371099, + "Clamp_+Z_-y_disp": 0.1708538959664814, + "Clamp_+Z_-z_disp": -0.6532709558080134, + "Clamp_+Z_compliance": 36425.924866297384, + "Clamp_+Z_mass": 5.400000000000001, + "Clamp_+Z_x_disp": 0.423860759605031, + "Clamp_+Z_y_disp": 0.1708538959664828, + "Clamp_+Z_z_disp": 2.6861025015727664, + "Clamp_-Z_-x_disp": 0.6483960432371095, + "Clamp_-Z_-y_disp": 0.17085389596648218, + "Clamp_-Z_-z_disp": 2.6861025015727664, + "Clamp_-Z_compliance": 36425.924866297384, + "Clamp_-Z_mass": 5.400000000000001, + "Clamp_-Z_x_disp": 0.4238607596050309, + "Clamp_-Z_y_disp": 0.17085389596648243, + "Clamp_-Z_z_disp": -0.6532709558080131, + } + + def setup_tacs_problems(self, comm): + """ + Setup mesh and pytacs object for problem we will be testing. + """ + + # Overwrite default check values + if self.dtype == complex: + self.rtol = 1e-6 + self.atol = 1e-6 + self.dh = 1e-50 + else: + self.rtol = 2e-1 + self.atol = 1e-3 + self.dh = 1e-6 + + # Instantiate FEA Assembler + struct_options = {} + + fea_assembler = pytacs.pyTACS(bdf_file, comm, options=struct_options) + + # Set up constitutive objects and elements + fea_assembler.initialize() + + # Read in forces from BDF and create tacs struct problems + tacs_probs = fea_assembler.createTACSProbsFromBDF() + # Convert from dict to list + tacs_probs = tacs_probs.values() + # Set convergence to be tight for test + for problem in tacs_probs: + problem.setOption("L2Convergence", 1e-20) + problem.setOption("L2ConvergenceRel", 1e-20) + + # Add Functions + for problem in tacs_probs: + problem.addFunction("mass", functions.StructuralMass) + problem.addFunction("compliance", functions.Compliance) + problem.addFunction( + "x_disp", + functions.KSDisplacement, + ksWeight=ksweight, + direction=[10.0, 0.0, 0.0], + ) + problem.addFunction( + "y_disp", + functions.KSDisplacement, + ksWeight=ksweight, + direction=[0.0, 10.0, 0.0], + ) + problem.addFunction( + "z_disp", + functions.KSDisplacement, + ksWeight=ksweight, + direction=[0.0, 0.0, 10.0], + ) + problem.addFunction( + "-x_disp", + functions.KSDisplacement, + ksWeight=ksweight, + direction=[-10.0, 0.0, 0.0], + ) + problem.addFunction( + "-y_disp", + functions.KSDisplacement, + ksWeight=ksweight, + direction=[0.0, -10.0, 0.0], + ) + problem.addFunction( + "-z_disp", + functions.KSDisplacement, + ksWeight=ksweight, + direction=[0.0, 0.0, -10.0], + ) + + return tacs_probs, fea_assembler