From 985263a2fa0c5da2f326ef69c726d05f632fe7cc Mon Sep 17 00:00:00 2001 From: David John Neiferd <13425967+JohnDN90@users.noreply.github.com> Date: Wed, 19 Feb 2020 12:31:11 -0500 Subject: [PATCH 01/27] Removed requirement of arbitrary orientation vector for elements with no bending. Addresses enhancment discussed in GitHub Issue #40 This was done to increase intuitiveness of MAST and bring it more closely inline with commerical FEA programs. This was originally done on Oct 11 2019 in GitLab develop branch with commit b0647ec. --- src/mesh/geom_elem.cpp | 27 +++++++++++++++++++ src/mesh/geom_elem.h | 14 ++++++++++ src/property_cards/element_property_card_1D.h | 2 ++ .../element_property_card_base.h | 9 +++++++ 4 files changed, 52 insertions(+) diff --git a/src/mesh/geom_elem.cpp b/src/mesh/geom_elem.cpp index c19ae1de..ddb05352 100644 --- a/src/mesh/geom_elem.cpp +++ b/src/mesh/geom_elem.cpp @@ -124,6 +124,12 @@ MAST::GeomElem::set_local_y_vector(const RealVectorX& y_vec) { } +void +MAST::GeomElem::set_bending(bool onoff) { + _bending = onoff;; +} + + void MAST::GeomElem::init(const libMesh::Elem& elem, const MAST::SystemInitialization& sys_init) { @@ -387,6 +393,27 @@ MAST::GeomElem::_init_local_elem_1d() { libmesh_assert(_local_y.size()); libmesh_assert_equal_to(_ref_elem->dim(), 1); + if (_local_y.size()==0) // if the orientation vector has not been defined + { + if (!_bending) // if bending is not used in this element + { // then create a random orientation vector that is not collinear + // with the element's local x-axis. Added for github issue #40 + + // Get element x-axis vector + libMesh::Point v1; + v1 = *_ref_elem->node_ptr(1); v1 -= *_ref_elem->node_ptr(0); + + // Perturb it by an arbitrary value and assign it to the _local_y vector. + _local_y = RealVectorX::Zero(3); + _local_y(0) = v1(0)+1.000; + _local_y(1) = v1(1)-0.625; + _local_y(2) = v1(2)+0.275; + } + else + { + libmesh_error_msg("ERROR: y_vector (for orientation of 1D element) not defined; In " << __PRETTY_FUNCTION__ << " in " << __FILE__ << " at line " << __LINE__); + } + } // first node is the origin of the new cs // calculate the coordinate system for the plane of the element diff --git a/src/mesh/geom_elem.h b/src/mesh/geom_elem.h index 83ea373f..1c991368 100644 --- a/src/mesh/geom_elem.h +++ b/src/mesh/geom_elem.h @@ -109,6 +109,14 @@ namespace MAST { */ void set_local_y_vector(const RealVectorX& y_vec); + /*! + * This sets the 1D elements to extension/torsional stiffness only. + * This is useful when modeling truss structures (e.g. using CROD + * elements in Nastran) which do not require an orientation vector + * like beam elements do. By default, 1D elements include bending. + */ + void set_bending(bool onoff); + /*! * initialize the object for the specified reference \p elem. */ @@ -259,6 +267,12 @@ namespace MAST { * obtained as a_j = T an_i */ RealMatrixX _T_mat; + + /*! + * Defines if bending is used in this element or not. True by default + * Added for github issue #40 + */ + bool _bending = true; }; } diff --git a/src/property_cards/element_property_card_1D.h b/src/property_cards/element_property_card_1D.h index 10dda39c..f660a609 100644 --- a/src/property_cards/element_property_card_1D.h +++ b/src/property_cards/element_property_card_1D.h @@ -63,6 +63,8 @@ namespace MAST */ virtual MAST::BendingOperatorType bending_model(const MAST::GeomElem& elem) const; + //virtual MAST::BendingOperatorType bending_model(const libMesh::Elem& elem) const; + /*! * returns the extra quadrature order (on top of the system) that diff --git a/src/property_cards/element_property_card_base.h b/src/property_cards/element_property_card_base.h index ffa50cf2..ed43ba9c 100644 --- a/src/property_cards/element_property_card_base.h +++ b/src/property_cards/element_property_card_base.h @@ -151,6 +151,15 @@ namespace MAST } + /*! + * sets the bending model to be used for the 1D element + * Added by DJN to increase section polymorphism + */ + virtual void set_bending_model(MAST::BendingOperatorType b) { + libmesh_error_msg("Not implemented, this needs to be reimplemented for individual card type; In " << __PRETTY_FUNCTION__ << " in " << __FILE__ << " at line " << __LINE__); + } + + /*! * sets the mass matrix to be diagonal or consistent */ From e76e00c509ac5e8e9e5c6df73e652cabaaca5f23 Mon Sep 17 00:00:00 2001 From: David John Neiferd <13425967+JohnDN90@users.noreply.github.com> Date: Wed, 19 Feb 2020 12:40:23 -0500 Subject: [PATCH 02/27] Increased polymorphism for 1D section. Added virtual set_material method to element_property_card_base.h Allows enhanced polymorphism between derived section classes by allowing 1D, 2D, and 3D section pointers to be stored in the same data structure (i.e. std::map), while still having access to the set_material method. Added init() and y_vector() methods to element_property_card_base to increase the polymorphism capability of 1D sections. Originially added on Sept 23 2019 in commits 635ba2c and a04a113 on GitLab in develop branch. --- .../element_property_card_base.h | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/property_cards/element_property_card_base.h b/src/property_cards/element_property_card_base.h index ed43ba9c..7acc471d 100644 --- a/src/property_cards/element_property_card_base.h +++ b/src/property_cards/element_property_card_base.h @@ -128,6 +128,49 @@ namespace MAST } + /*! + * return the material property. This needs to be reimplemented + * for individual card type, and should be used only for isotropic + * cards. + * + * Added by DJN. Reference cplusplus.com/forum/beginner/10639 + */ + virtual const MAST::MaterialPropertyCardBase& set_material(MAST::MaterialPropertyCardBase& mat) const { + libmesh_error_msg("Not Implemented, this needs to be reimplemented for individual card type; In " << __PRETTY_FUNCTION__ << " in " << __FILE__ << " at line " << __LINE__); + } + + + /*! + * vector in the x-y plane of the element. This should not be the same + * as the element x-axis. + * Only used by 1D sections. Added for polymorphism enhancement. + * Added by DJN. + */ + virtual RealVectorX& y_vector() { + libmesh_error_msg("Not Implemented, this needs to be reimplemented for individual card type; In " << __PRETTY_FUNCTION__ << " in " << __FILE__ << " at line " << __LINE__); + } + + + /*! + * constant reference to vector in the x-y plane of the element. + * This should not be the same as the element x-axis. + * Only used by 1D sections. Added for polymorphism enhancement. + * Added by DJN. + */ + virtual const RealVectorX& y_vector() const { + libmesh_error_msg("Not Implemented, this needs to be reimplemented for individual card type; In " << __PRETTY_FUNCTION__ << " in " << __FILE__ << " at line " << __LINE__); + } + + /*! + * Only used by 1D sections. Added for polymorphism enhancement. + * + * Added by DJN. + */ + virtual void init() { + libmesh_error_msg("Not Implemented, this needs to be reimplemented for individual card type; In " << __PRETTY_FUNCTION__ << " in " << __FILE__ << " at line " << __LINE__); + } + + /*! * dimension of the element for which this property is defined */ From 301612c3af4d65511b6fa9cb42cf10fe04cb801a Mon Sep 17 00:00:00 2001 From: David John Neiferd <13425967+JohnDN90@users.noreply.github.com> Date: Wed, 19 Feb 2020 13:16:48 -0500 Subject: [PATCH 03/27] Added methods to get geometry points, hole points, centriod, shear center, and stress evaluation points (and the derivative of these points) to 1D section. This was originally done over multiple commits on the GitLab MAST-Library repository on the develop branch. --- .../element_property_card_base.h | 106 ++++++++- ...solid_1d_section_element_property_card.cpp | 223 ++++++++++++++++++ .../solid_1d_section_element_property_card.h | 16 ++ 3 files changed, 340 insertions(+), 5 deletions(-) diff --git a/src/property_cards/element_property_card_base.h b/src/property_cards/element_property_card_base.h index 7acc471d..f1dd33e3 100644 --- a/src/property_cards/element_property_card_base.h +++ b/src/property_cards/element_property_card_base.h @@ -124,7 +124,7 @@ namespace MAST * cards. */ virtual const MAST::MaterialPropertyCardBase& get_material() const { - libmesh_error(); + libmesh_error_msg("Must be implemented in derived class; " << __PRETTY_FUNCTION__ << " in " << __FILE__ << " at line number " << __LINE__); } @@ -136,7 +136,7 @@ namespace MAST * Added by DJN. Reference cplusplus.com/forum/beginner/10639 */ virtual const MAST::MaterialPropertyCardBase& set_material(MAST::MaterialPropertyCardBase& mat) const { - libmesh_error_msg("Not Implemented, this needs to be reimplemented for individual card type; In " << __PRETTY_FUNCTION__ << " in " << __FILE__ << " at line " << __LINE__); + libmesh_error_msg("Must be implemented in derived class; " << __PRETTY_FUNCTION__ << " in " << __FILE__ << " at line number " << __LINE__); } @@ -147,7 +147,7 @@ namespace MAST * Added by DJN. */ virtual RealVectorX& y_vector() { - libmesh_error_msg("Not Implemented, this needs to be reimplemented for individual card type; In " << __PRETTY_FUNCTION__ << " in " << __FILE__ << " at line " << __LINE__); + libmesh_error_msg("Must be implemented in derived class; " << __PRETTY_FUNCTION__ << " in " << __FILE__ << " at line number " << __LINE__); } @@ -158,16 +158,112 @@ namespace MAST * Added by DJN. */ virtual const RealVectorX& y_vector() const { - libmesh_error_msg("Not Implemented, this needs to be reimplemented for individual card type; In " << __PRETTY_FUNCTION__ << " in " << __FILE__ << " at line " << __LINE__); + libmesh_error_msg("Must be implemented in derived class; " << __PRETTY_FUNCTION__ << " in " << __FILE__ << " at line number " << __LINE__); } + + /*! + * Returns location of shear center of the section + */ + virtual const libMesh::Point get_shear_center(const libMesh::Point& p, const Real t) const + { + libmesh_error_msg("Must be implemented in derived class; " << __PRETTY_FUNCTION__ << " in " << __FILE__ << " at line number " << __LINE__); + } + + + /*! + * Returns derivative of location of shear center of the section + */ + virtual const libMesh::Point get_shear_center_derivative(MAST::FunctionBase& f, const libMesh::Point& p, const Real t) + { + libmesh_error_msg("Must be implemented in derived class; " << __PRETTY_FUNCTION__ << " in " << __FILE__ << " at line number " << __LINE__); + } + + + /*! + * Returns the location of the centroid of the section + */ + virtual const libMesh::Point get_centroid(const libMesh::Point& p, const Real t) const + { + libmesh_error_msg("Must be implemented in derived class; " << __PRETTY_FUNCTION__ << " in " << __FILE__ << " at line number " << __LINE__); + } + + + /*! + * Returns the derivative of the location of the centroid of the section + */ + virtual const libMesh::Point get_centroid_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t) const + { + libmesh_error_msg("Must be implemented in derived class; " << __PRETTY_FUNCTION__ << " in " << __FILE__ << " at line number " << __LINE__); + } + + + /*! + * Returns the points which define the geometry of the cross section. + */ + virtual const std::vector get_geom_points(const libMesh::Point& p, const Real t, const uint n=201) const + { + libmesh_error_msg("Must be implemented in derived class; " << __PRETTY_FUNCTION__ << " in " << __FILE__ << " at line number " << __LINE__); + } + + + /*! + * Return the derivative of points which define the geometry of the + * cross section. + */ + virtual const std::vector get_geom_points_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, const uint n=201) const + { + libmesh_error_msg("Must be implemented in derived class; " << __PRETTY_FUNCTION__ << " in " << __FILE__ << " at line number " << __LINE__); + } + + + /*! + * Returns a list containing vectors of points which define the + * geometry of each hole in the cross section. + */ + virtual const std::vector> get_holes_points(const libMesh::Point& p, const Real t, const uint n=201) const + { + std::vector> empty_hole_list; + return empty_hole_list; + } + + + /*! + * Returns a list containing vectors of points which define the + * hole geometry sensitivity to a parameter + */ + virtual const std::vector> get_holes_points_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, const uint n=201) const + { + std::vector> empty_hole_list; + return empty_hole_list; + } + + + /*! + * Returns location of stress evaluation points of the section + */ + virtual const std::vector get_stress_points(const libMesh::Point& p, const Real t, const libMesh::Point ps) const + { + libmesh_error_msg("Must be implemented in derived class; " << __PRETTY_FUNCTION__ << " in " << __FILE__ << " at line number " << __LINE__); + } + + + /*! + * Returns location of stress evaluation points of the section + */ + virtual const std::vector get_stress_points_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, const libMesh::Point dps) const + { + libmesh_error_msg("Must be implemented in derived class; " << __PRETTY_FUNCTION__ << " in " << __FILE__ << " at line number " << __LINE__); + } + + /*! * Only used by 1D sections. Added for polymorphism enhancement. * * Added by DJN. */ virtual void init() { - libmesh_error_msg("Not Implemented, this needs to be reimplemented for individual card type; In " << __PRETTY_FUNCTION__ << " in " << __FILE__ << " at line " << __LINE__); + libmesh_error_msg("Must be implemented in derived class; " << __PRETTY_FUNCTION__ << " in " << __FILE__ << " at line number " << __LINE__); } diff --git a/src/property_cards/solid_1d_section_element_property_card.cpp b/src/property_cards/solid_1d_section_element_property_card.cpp index f5a4fa17..ce1a83eb 100644 --- a/src/property_cards/solid_1d_section_element_property_card.cpp +++ b/src/property_cards/solid_1d_section_element_property_card.cpp @@ -2086,3 +2086,226 @@ section() const { return *_A; } + + +const libMesh::Point +MAST::Solid1DSectionElementPropertyCard:: +get_shear_center(const libMesh::Point& p, const Real t) const +{ + const MAST::FieldFunction + &hy = this->get >("hy"), + &hz = this->get >("hz"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real h_y, h_z, h_y_off, h_z_off; + hy(p, t, h_y); + hz(p, t, h_z); + hy_off(p, t, h_y_off); + hz_off(p, t, h_z_off); + + libMesh::Point offset(h_z_off, h_y_off); + + libMesh::Point ps(0., 0.); + return ps+offset; +} + + +const libMesh::Point +MAST::Solid1DSectionElementPropertyCard:: +get_shear_center_derivative(MAST::FunctionBase& f, const libMesh::Point& p, + const Real t) +{ + const MAST::FieldFunction + &hy = this->get >("hy"), + &hz = this->get >("hz"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real h_y, h_z, h_y_off, h_z_off; + Real dh_y, dh_z, dh_y_off, dh_z_off; + + hy(p, t, h_y); hy.derivative(f, p, t, dh_y); + hz(p, t, h_z); hz.derivative(f, p, t, dh_z); + hy_off(p, t, h_y_off); hy_off.derivative(f, p, t, dh_y_off); + hz_off(p, t, h_z_off); hz_off.derivative(f, p, t, dh_z_off); + + libMesh::Point offset(h_z_off, h_y_off); + libMesh::Point doffset(dh_z_off, dh_y_off); + + return doffset; +} + + +const libMesh::Point +MAST::Solid1DSectionElementPropertyCard:: +get_centroid(const libMesh::Point& p, const Real t) const +{ + const MAST::FieldFunction + &hy = this->get >("hy"), + &hz = this->get >("hz"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real h_y, h_z, h_y_off, h_z_off; + hy(p, t, h_y); + hz(p, t, h_z); + hy_off(p, t, h_y_off); + hz_off(p, t, h_z_off); + + libMesh::Point offset(h_z_off, h_y_off); + + libMesh::Point ps(0., 0.); + return ps+offset; +} + + +const libMesh::Point +MAST::Solid1DSectionElementPropertyCard:: +get_centroid_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, + const Real t) const +{ + const MAST::FieldFunction + &hy = this->get >("hy"), + &hz = this->get >("hz"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real h_y, h_z, h_y_off, h_z_off; + Real dh_y, dh_z, dh_y_off, dh_z_off; + + hy(p, t, h_y); hy.derivative(f, p, t, dh_y); + hz(p, t, h_z); hz.derivative(f, p, t, dh_z); + hy_off(p, t, h_y_off); hy_off.derivative(f, p, t, dh_y_off); + hz_off(p, t, h_z_off); hz_off.derivative(f, p, t, dh_z_off); + + libMesh::Point offset(h_z_off, h_y_off); + libMesh::Point doffset(dh_z_off, dh_y_off); + + return doffset; +} + + +const std::vector +MAST::Solid1DSectionElementPropertyCard:: +get_geom_points(const libMesh::Point& p, const Real t, const uint n) const +{ + const MAST::FieldFunction + &hy = this->get >("hy"), + &hz = this->get >("hz"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real h_y, h_z, h_y_off, h_z_off; + hy(p, t, h_y); + hz(p, t, h_z); + hy_off(p, t, h_y_off); + hz_off(p, t, h_z_off); + + libMesh::Point offset(h_z_off, h_y_off); + + std::vector geom_points = { + libMesh::Point(-0.5*h_z, -0.5*h_y) + offset, + libMesh::Point(0.5*h_z, -0.5*h_y) + offset, + libMesh::Point(0.5*h_z, 0.5*h_y) + offset, + libMesh::Point(-0.5*h_z, 0.5*h_y) + offset + }; + + return geom_points; +} + + +const std::vector +MAST::Solid1DSectionElementPropertyCard:: +get_geom_points_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, + const Real t, const uint n) const +{ + const MAST::FieldFunction + &hy = this->get >("hy"), + &hz = this->get >("hz"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real h_y, h_z, h_y_off, h_z_off; + Real dh_y, dh_z, dh_y_off, dh_z_off; + + hy(p, t, h_y); hy.derivative(f, p, t, dh_y); + hz(p, t, h_z); hz.derivative(f, p, t, dh_z); + hy_off(p, t, h_y_off); hy_off.derivative(f, p, t, dh_y_off); + hz_off(p, t, h_z_off); hz_off.derivative(f, p, t, dh_z_off); + + libMesh::Point offset(h_z_off, h_y_off); + libMesh::Point doffset(dh_z_off, dh_y_off); + + std::vector geom_points = { + libMesh::Point(-0.5*dh_z, -0.5*dh_y) + doffset, + libMesh::Point(0.5*dh_z, -0.5*dh_y) + doffset, + libMesh::Point(0.5*dh_z, 0.5*dh_y) + doffset, + libMesh::Point(-0.5*dh_z, 0.5*dh_y) + doffset + }; + + return geom_points; +} + + +const std::vector +MAST::Solid1DSectionElementPropertyCard:: +get_stress_points(const libMesh::Point& p, const Real t, const libMesh::Point ps) const +{ + const MAST::FieldFunction + &hy = this->get >("hy"), + &hz = this->get >("hz"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real h_y, h_z, h_y_off, h_z_off; + hy(p, t, h_y); + hz(p, t, h_z); + hy_off(p, t, h_y_off); + hz_off(p, t, h_z_off); + + libMesh::Point offset(h_z_off, h_y_off); + + std::vector stress_points = { + libMesh::Point(0.5*h_z, 0.5*h_y) + offset - ps, + libMesh::Point(0.5*h_z, -0.5*h_y) + offset - ps, + libMesh::Point(-0.5*h_z, -0.5*h_y) + offset - ps, + libMesh::Point(-0.5*h_z, 0.5*h_y) + offset - ps + }; + + return stress_points; +} + + +const std::vector +MAST::Solid1DSectionElementPropertyCard:: +get_stress_points_derivative(const MAST::FunctionBase& f, + const libMesh::Point& p, const Real t, + const libMesh::Point dps) const +{ + const MAST::FieldFunction + &hy = this->get >("hy"), + &hz = this->get >("hz"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real h_y, h_z, h_y_off, h_z_off; + Real dh_y, dh_z, dh_y_off, dh_z_off; + + hy(p, t, h_y); hy.derivative(f, p, t, dh_y); + hz(p, t, h_z); hz.derivative(f, p, t, dh_z); + hy_off(p, t, h_y_off); hy_off.derivative(f, p, t, dh_y_off); + hz_off(p, t, h_z_off); hz_off.derivative(f, p, t, dh_z_off); + + libMesh::Point offset(h_z_off, h_y_off); + libMesh::Point doffset(dh_z_off, dh_y_off); + + std::vector stress_points = { + libMesh::Point(0.5*dh_z, 0.5*dh_y) + doffset - dps, + libMesh::Point(0.5*dh_z, -0.5*dh_y) + doffset - dps, + libMesh::Point(-0.5*dh_z, -0.5*dh_y) + doffset - dps, + libMesh::Point(-0.5*dh_z, 0.5*dh_y) + doffset - dps + }; + + return stress_points; +} diff --git a/src/property_cards/solid_1d_section_element_property_card.h b/src/property_cards/solid_1d_section_element_property_card.h index fd2deaab..51c40447 100644 --- a/src/property_cards/solid_1d_section_element_property_card.h +++ b/src/property_cards/solid_1d_section_element_property_card.h @@ -255,6 +255,22 @@ namespace MAST { virtual void init(); + virtual const std::vector get_geom_points(const libMesh::Point& p, const Real t, const uint n=201) const override; + + virtual const std::vector get_geom_points_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, const uint n=201) const override; + + virtual const libMesh::Point get_shear_center(const libMesh::Point& p, const Real t) const override; + + virtual const libMesh::Point get_shear_center_derivative(MAST::FunctionBase& f, const libMesh::Point& p, const Real t) override; + + virtual const libMesh::Point get_centroid(const libMesh::Point& p, const Real t) const override; + + virtual const libMesh::Point get_centroid_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t) const override; + + virtual const std::vector get_stress_points(const libMesh::Point& p, const Real t, const libMesh::Point ps) const override; + + virtual const std::vector get_stress_points_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, const libMesh::Point dps) const override; + protected: bool _initialized; From 6d8c6ad002e24e15ad8ccdba4463ae95c508b370 Mon Sep 17 00:00:00 2001 From: David John Neiferd <13425967+JohnDN90@users.noreply.github.com> Date: Wed, 19 Feb 2020 13:50:31 -0500 Subject: [PATCH 04/27] Added arbitrary 1D section proeprty card and tests for it. This was originally done on GitLab MAST-Library repo in develop branch. --- src/property_cards/CMakeLists.txt | 4 +- ...rbitrary_section_element_property_card.cpp | 690 ++++++++++++++++++ ..._arbitrary_section_element_property_card.h | 88 +++ tests/property/CMakeLists.txt | 25 +- ...rbitrary_section_element_property_card.cpp | 254 +++++++ 5 files changed, 1052 insertions(+), 9 deletions(-) create mode 100644 src/property_cards/solid_1d_arbitrary_section_element_property_card.cpp create mode 100644 src/property_cards/solid_1d_arbitrary_section_element_property_card.h create mode 100644 tests/property/mast_solid_1d_arbitrary_section_element_property_card.cpp diff --git a/src/property_cards/CMakeLists.txt b/src/property_cards/CMakeLists.txt index cb2008bc..01eba612 100644 --- a/src/property_cards/CMakeLists.txt +++ b/src/property_cards/CMakeLists.txt @@ -20,9 +20,11 @@ target_sources(mast ${CMAKE_CURRENT_LIST_DIR}/orthotropic_material_property_card.h ${CMAKE_CURRENT_LIST_DIR}/solid_1d_section_element_property_card.cpp ${CMAKE_CURRENT_LIST_DIR}/solid_1d_section_element_property_card.h + ${CMAKE_CURRENT_LIST_DIR}/solid_1d_arbitrary_section_element_property_card.cpp + ${CMAKE_CURRENT_LIST_DIR}/solid_1d_arbitrary_section_element_property_card.h ${CMAKE_CURRENT_LIST_DIR}/solid_2d_section_element_property_card.cpp ${CMAKE_CURRENT_LIST_DIR}/solid_2d_section_element_property_card.h) # Install MAST headers for this directory. install(DIRECTORY ./ DESTINATION include/property_cards - FILES_MATCHING PATTERN "*.h") \ No newline at end of file + FILES_MATCHING PATTERN "*.h") diff --git a/src/property_cards/solid_1d_arbitrary_section_element_property_card.cpp b/src/property_cards/solid_1d_arbitrary_section_element_property_card.cpp new file mode 100644 index 00000000..8b19fe98 --- /dev/null +++ b/src/property_cards/solid_1d_arbitrary_section_element_property_card.cpp @@ -0,0 +1,690 @@ +/* + * MAST: Multidisciplinary-design Adaptation and Sensitivity Toolkit + * Copyright (C) 2013-2019 Manav Bhatia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +//TODO: Arbitrary cross sections currently only support sensitivites w.r.t. +// offsets. Other sensitivies will be returned as zero. + +// MAST includes +#include "property_cards/solid_1d_arbitrary_section_element_property_card.h" +#include "property_cards/material_property_card_base.h" +#include "base/field_function_base.h" +#include "base/elem_base.h" + +#define PI 3.1415926535897932 + +namespace MAST { + namespace Solid1DArbitrarySectionProperty { + + class Area: public MAST::FieldFunction { + public: + Area(const MAST::FieldFunction& A): + MAST::FieldFunction("Area"), _A(A){ + _functions.insert(&A); + } + + virtual ~Area() { } + + virtual void operator() (const libMesh::Point& p, + const Real t, + Real& m) const { + Real A; + _A(p, t, A); + m = A; + } + + virtual void derivative ( const MAST::FunctionBase& f, + const libMesh::Point& p, + const Real t, + Real& m) const { + Real A, dA; + _A(p, t, A); _A.derivative(f, p, t, dA); + m = dA; + } + protected: + const MAST::FieldFunction& _A; + + }; + + + class TorsionalConstant: public MAST::FieldFunction { + public: + TorsionalConstant(const MAST::FieldFunction& T): + MAST::FieldFunction("TorsionalConstant"), _T(T){ + _functions.insert(&T); + } + + virtual ~TorsionalConstant() { } + + virtual void operator() (const libMesh::Point& p, + const Real t, + Real& m) const { + Real T; + _T(p, t, T); + m = T; + } + + + virtual void derivative ( const MAST::FunctionBase& f, + const libMesh::Point& p, + const Real t, + Real& m) const { + Real T, dT; + _T(p, t, T); _T.derivative(f, p, t, dT); + m = dT; + } + protected: + const MAST::FieldFunction& _T; + + }; + + + class WarpingConstant: public MAST::FieldFunction { + public: + WarpingConstant(const MAST::FieldFunction& W): + MAST::FieldFunction("WarpingConstant"), _W(W) + { + _functions.insert(&W); + } + + virtual ~WarpingConstant() { } + + virtual void operator() (const libMesh::Point& p, + const Real t, + Real& m) const { + Real W; + _W(p, t, W); + m = W; + } + + virtual void derivative (const MAST::FunctionBase& f, + const libMesh::Point& p, + const Real t, + Real& m) const { + Real W, dW; + _W(p, t, W); _W.derivative(f, p, t, dW); + m = dW; + } + protected: + const MAST::FieldFunction& _W; + + }; + + + class ShearCoefficientMatrix: public MAST::FieldFunction { + public: + ShearCoefficientMatrix(const MAST::FieldFunction& Kzz, + const MAST::FieldFunction& Kyy): + MAST::FieldFunction("ShearCoefficientMatrix"), + _Kzz(Kzz), + _Kyy(Kyy) + { + _functions.insert(&Kzz); + _functions.insert(&Kyy); + } + + virtual ~ShearCoefficientMatrix() { } + + virtual void operator() (const libMesh::Point& p, + const Real t, + RealMatrixX& m) const { + Real Kzz; + Real Kyy; + _Kzz(p, t, Kzz); + _Kyy(p, t, Kyy); + m = RealMatrixX::Zero(2,2); + m(0,0) = Kzz; + m(1,1) = Kyy; + } + + virtual void derivative (const MAST::FunctionBase& f, + const libMesh::Point& p, + const Real t, + RealMatrixX& m) const { + Real dKzz, dKyy; + _Kyy.derivative(f, p, t, dKyy); + _Kzz.derivative(f, p, t, dKzz); + m = RealMatrixX::Zero(2,2); + m(0,0) = dKzz; + m(1,1) = dKyy; + } + protected: + const MAST::FieldFunction& _Kyy; + const MAST::FieldFunction& _Kzz; + }; + + + class PolarInertia: public MAST::FieldFunction { + public: + PolarInertia(const MAST::FieldFunction& J, + const MAST::FieldFunction& A, + const MAST::FieldFunction& hy_offset, + const MAST::FieldFunction& hz_offset): + MAST::FieldFunction("PolarInertia"), + _J(J), _A(A), + _hy_offset(hy_offset), + _hz_offset(hz_offset) { + _functions.insert(&J); + _functions.insert(&A); + _functions.insert(&hy_offset); + _functions.insert(&hz_offset); + } + + virtual ~PolarInertia() { } + + virtual void operator() (const libMesh::Point& p, + const Real t, + Real& m) const { + Real A, J, offy, offz; + _A(p, t, A); + _J(p, t, J); + _hy_offset(p, t, offy); + _hz_offset(p, t, offz); + + m = J + A*pow(offy,2) + A*pow(offz,2); + } + + virtual void derivative (const MAST::FunctionBase& f, + const libMesh::Point& p, + const Real t, + Real& m) const { + Real A, dA, J, dJ, offy, offz, doffy, doffz; + _A(p, t, A); _A.derivative(f, p, t, dA); + _J(p, t, J); _J.derivative(f, p, t, dJ); + _hy_offset (p, t, offy); _hy_offset.derivative( f, p, t, doffy); + _hz_offset (p, t, offz); _hz_offset.derivative( f, p, t, doffz); + + m = dJ + pow(offy,2)*dA + 2.*A*offy*doffy + pow(offz,2)*dA + 2.*A*offz*doffz; + } + + protected: + const MAST::FieldFunction &_J, &_A, &_hy_offset, &_hz_offset; + }; + + + /*! + * calculates the area moment about the Y-axis due to an offset + * along the Z-axis + */ + class AreaYMoment: public MAST::FieldFunction { + public: + AreaYMoment(const MAST::FieldFunction& A, + const MAST::FieldFunction& hz_offset): + MAST::FieldFunction("AreaYMoment"), + _A(A), + _hz_offset(hz_offset) { + _functions.insert(&A); + _functions.insert(&hz_offset); + } + + + virtual ~AreaYMoment() { } + + virtual void operator() (const libMesh::Point& p, + const Real t, + Real& m) const { + Real A, off; + _A(p, t, A); + _hz_offset(p, t, off); + + m = A * off; + } + + + virtual void derivative ( const MAST::FunctionBase& f, + const libMesh::Point& p, + const Real t, + Real& m) const { + Real A, dA, off, doff; + _A(p, t, A); _A.derivative(f, p, t, dA); + _hz_offset (p, t, off); _hz_offset.derivative( f, p, t, doff); + + m = dA*off + A*doff; + } + + protected: + const MAST::FieldFunction& _A; + const MAST::FieldFunction &_hz_offset; + }; + + + + /*! + * calculates the area moment about the Z-axis due to an offset + * along the Y-axis + */ + class AreaZMoment: public MAST::FieldFunction { + public: + AreaZMoment(const MAST::FieldFunction& A, + const MAST::FieldFunction& hy_offset): + MAST::FieldFunction("AreaZMoment"), + _A(A), + _hy_offset(hy_offset) { + _functions.insert(&A); + _functions.insert(&hy_offset); + } + + virtual ~AreaZMoment() { } + + virtual void operator() (const libMesh::Point& p, + const Real t, + Real& m) const { + Real A, off; + _A(p, t, A); + _hy_offset(p, t, off); + + m = A*off; + } + + + virtual void derivative ( const MAST::FunctionBase& f, + const libMesh::Point& p, + const Real t, + Real& m) const { + Real A, dA, off, doff; + _A(p, t, A); _A.derivative(f, p, t, dA); + _hy_offset(p, t, off); _hy_offset.derivative( f, p, t, doff); + + m = dA*off + A*doff; + } + + protected: + const MAST::FieldFunction& _A; + const MAST::FieldFunction &_hy_offset; + }; + + + + /*! + * calculates the 2x2 matrix of area inertia for the section with + * individual entries as + * + * 0 x 0 = int_omega (y+yoff)^2 dy dz + * 0 x 1 = int_omega (y+yoff) (z+zoff) dy dz + * 1 x 0 = int_omega (y+yoff) (z+zoff) dy dz + * 1 x 1 = int_omega (z+zoff)^2 dy dz + */ + class AreaInertiaMatrix: public MAST::FieldFunction { + public: + AreaInertiaMatrix(const MAST::FieldFunction& Izz, + const MAST::FieldFunction& Iyy, + const MAST::FieldFunction& Izy, + const MAST::FieldFunction& A, + const MAST::FieldFunction& hy_offset, + const MAST::FieldFunction& hz_offset): + MAST::FieldFunction("AreaInertiaMatrix"), + _Izz(Izz), _Iyy(Iyy), _Izy(Izy), _A(A), + _hy_offset(hy_offset), + _hz_offset(hz_offset) { + _functions.insert(&Izz); + _functions.insert(&Iyy); + _functions.insert(&Izy); + _functions.insert(&A); + _functions.insert(&hy_offset); + _functions.insert(&hz_offset); + } + + virtual ~AreaInertiaMatrix() { } + + virtual void operator() (const libMesh::Point& p, + const Real t, + RealMatrixX& m) const { + Real Izz, Iyy, Izy, A, offy, offz; + m = RealMatrixX::Zero(2,2); + _A(p, t, A); + _Izz(p, t, Izz); + _Iyy(p, t, Iyy); + _Izy(p, t, Izy); + _hy_offset(p, t, offy); + _hz_offset(p, t, offz); + + m(0,0) = Izz + A*pow(offy,2); // Izz for v-bending + m(0,1) = Izy + A * offy * offz; // Izy + m(1,0) = m(0,1); + m(1,1) = Iyy + A*pow(offz,2); // Iyy for w-bending + } + + + virtual void derivative ( const MAST::FunctionBase& f, + const libMesh::Point& p, + const Real t, + RealMatrixX& m) const { + Real A, dA, Izz, dIzz, Iyy, dIyy, Izy, dIzy; + Real offy, offz, doffy, doffz; + m = RealMatrixX::Zero(2,2); + _A(p, t, A); _A.derivative(f, p, t, dA); + _Izz(p, t, Izz); _Izz.derivative(f, p, t, dIzz); + _Iyy(p, t, Iyy); _Iyy.derivative(f, p, t, dIyy); + _Izy(p, t, Izy); _Izy.derivative(f, p, t, dIzy); + _hy_offset(p, t, offy); _hy_offset.derivative(f, p, t, doffy); + _hz_offset(p, t, offz); _hz_offset.derivative(f, p, t, doffz); + + m(0,0) = dIzz + dA*pow(offy,2) + A*2.0*offy*doffy; + m(0,1) = dIzy + dA*offy*offz + A*doffy*offz + A*offy*doffz; + m(1,0) = m(0,1); + m(1,1) = dIyy + dA*pow(offz,2) + A*2.0*offz*doffz; + } + + protected: + const MAST::FieldFunction &_Izz, &_Iyy, &_Izy, &_A; + const MAST::FieldFunction &_hy_offset, &_hz_offset; + }; + } +} + + +// // FIXME: Need this to autocreate FieldFunction from calculated properties +// void MAST::Solid1DArbitrarySectionElementPropertyCard::init(libMesh::MeshBase& mesh){ +// +// libmesh_assert(!_initialized); +// +// this->calculateGeometricProperties(mesh); +// +// MAST::FieldFunction +// &hy_off = this->get >("hy_off"), +// &hz_off = this->get >("hz_off"); +// +// // _A.reset(new MAST::Solid1DArbitrarySectionProperty::Area(_A_val)); +// _Ay.reset(new MAST::Solid1DArbitrarySectionProperty::AreaYMoment(_A_val, hz_off)); +// _Az.reset(new MAST::Solid1DArbitrarySectionProperty::AreaZMoment(_A_val, hy_off)); +// _J.reset(new MAST::Solid1DArbitrarySectionProperty::TorsionalConstant(_J_val)); +// _Ip.reset(new MAST::Solid1DArbitrarySectionProperty::PolarInertia(_Ip_val, _A_val, +// hy_off, +// hz_off)); +// _AI.reset(new MAST::Solid1DArbitrarySectionProperty::AreaInertiaMatrix(_Izz_val, +// _Iyy_val, +// _A_val, hy_off, +// hz_off)); +// +// _initialized = true; +// } + + +// // FIXME: Need this to autocreate FieldFunction from calculated properties +// void MAST::Solid1DArbitrarySectionElementPropertyCard::init(RealMatrixX& vertices){ +// +// libmesh_assert(!_initialized); +// +// this->calculateGeometricProperties(vertices); +// +// MAST::FieldFunction +// &hy_off = this->get >("hy_off"), +// &hz_off = this->get >("hz_off"); +// +// // _A.reset(new MAST::Solid1DArbitrarySectionProperty::Area(_A_val)); +// _Ay.reset(new MAST::Solid1DArbitrarySectionProperty::AreaYMoment(_A_val, hz_off)); +// _Az.reset(new MAST::Solid1DArbitrarySectionProperty::AreaZMoment(_A_val, hy_off)); +// _J.reset(new MAST::Solid1DArbitrarySectionProperty::TorsionalConstant(_J_val)); +// _Ip.reset(new MAST::Solid1DArbitrarySectionProperty::PolarInertia(_Ip_val, _A_val, +// hy_off, +// hz_off)); +// _AI.reset(new MAST::Solid1DArbitrarySectionProperty::AreaInertiaMatrix(_Izz_val, +// _Iyy_val, +// _A_val, hy_off, +// hz_off)); +// +// _initialized = true; +// } + + +// // FIXME: Need this to autocreate FieldFunction from specified properties +// void MAST::Solid1DArbitrarySectionElementPropertyCard::init(Real A, Real Izz, +// Real Iyy, Real Ip, +// Real J){ +// libmesh_assert(!_initialized); +// +// _A_val = A; +// _Izz_val = Izz; +// _Iyy_val = Iyy; +// _Ip_val = Ip; +// _J_val = J; +// +// MAST::FieldFunction +// &Af = this->get >("A"), +// &hy_off = this->get >("hy_off"), +// &hz_off = this->get >("hz_off"); +// +// _A.reset(new MAST::Solid1DArbitrarySectionProperty::Area(Af)); +// _Ay.reset(new MAST::Solid1DArbitrarySectionProperty::AreaYMoment(_A_val, hz_off)); +// _Az.reset(new MAST::Solid1DArbitrarySectionProperty::AreaZMoment(_A_val, hy_off)); +// _J.reset(new MAST::Solid1DArbitrarySectionProperty::TorsionalConstant(_J_val)); +// _Ip.reset(new MAST::Solid1DArbitrarySectionProperty::PolarInertia(_Ip_val, _A_val, +// hy_off, +// hz_off)); +// _AI.reset(new MAST::Solid1DArbitrarySectionProperty::AreaInertiaMatrix(_Izz_val, +// _Iyy_val, +// _A_val, hy_off, +// hz_off)); +// +// _initialized = true; +// } + + +void MAST::Solid1DArbitrarySectionElementPropertyCard::init() +{ + libmesh_assert(!_initialized); + + MAST::FieldFunction + &A = this->get >("A"), + &Izz = this->get >("Izz"), + &Iyy = this->get >("Iyy"), + &Izy = this->get >("Izy"), + &Ip = this->get >("Ip"), + &J = this->get >("J"), + &W = this->get >("W"), + &Kappazz = this->get >("Kappazz"), + &Kappayy = this->get >("Kappayy"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + _A.reset(new MAST::Solid1DArbitrarySectionProperty::Area(A)); + _Ay.reset(new MAST::Solid1DArbitrarySectionProperty::AreaYMoment(A, hz_off)); + _Az.reset(new MAST::Solid1DArbitrarySectionProperty::AreaZMoment(A, hy_off)); + _J.reset(new MAST::Solid1DArbitrarySectionProperty::TorsionalConstant(J)); + _Ip.reset(new MAST::Solid1DArbitrarySectionProperty::PolarInertia(Ip, A, + hy_off, + hz_off)); + _AI.reset(new MAST::Solid1DArbitrarySectionProperty::AreaInertiaMatrix(Izz, + Iyy, Izy, A, hy_off, hz_off)); + _Gamma.reset(new MAST::Solid1DArbitrarySectionProperty::WarpingConstant(W)); + _Kappa.reset(new MAST::Solid1DArbitrarySectionProperty::ShearCoefficientMatrix(Kappazz, Kappayy)); + + _initialized = true; +} + + +void MAST::Solid1DArbitrarySectionElementPropertyCard::clear() { + + libmesh_assert(!_initialized); + + _A.reset(); + _Ay.reset(); + _Az.reset(); + _J.reset(); + _Ip.reset(); + _AI.reset(); + _Kappa.reset(); + _Gamma.reset(); + + _A_val=0; + _Izz_val=0; + _Iyy_val=0; + _Ip_val=0; + _J_val=0; + _W_val=0; + _Kxx_val=0; + _Kyy_val=0; + + _torsionConstantSet = false; + + _initialized = false; +} + + +void MAST::Solid1DArbitrarySectionElementPropertyCard::setTorsionalConstant(Real J){ + _J_val = J; + _torsionConstantSet = true; +} + +const std::vector MAST::Solid1DArbitrarySectionElementPropertyCard::get_stress_points(const libMesh::Point& p, const Real t, const libMesh::Point ps) const +{ + return _stress_points; +} + +void MAST::Solid1DArbitrarySectionElementPropertyCard::add_stress_point(const libMesh::Point stress_point) +{ + _stress_points.push_back(stress_point); +} + +const libMesh::Point MAST::Solid1DArbitrarySectionElementPropertyCard::get_centroid(const libMesh::Point& p, const Real t) const +{ + return libMesh::Point(0., 0., 0.); +} + +const libMesh::Point MAST::Solid1DArbitrarySectionElementPropertyCard::get_shear_center(const libMesh::Point& p, const Real t) const +{ + return libMesh::Point(0., 0., 0.); +} + +const libMesh::Point MAST::Solid1DArbitrarySectionElementPropertyCard::get_centroid_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t) const +{ + return libMesh::Point(0., 0., 0.); +} + +const libMesh::Point MAST::Solid1DArbitrarySectionElementPropertyCard::get_shear_center_derivative(MAST::FunctionBase& f, const libMesh::Point& p, const Real t) +{ + return libMesh::Point(0., 0., 0.); +} + +const std::vector MAST::Solid1DArbitrarySectionElementPropertyCard::get_stress_points_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, const libMesh::Point dps) const +{ + std::vector dstress_points(_stress_points.size()); + for (uint i=0; i<_stress_points.size(); i++) + { + dstress_points[i] = libMesh::Point(0., 0., 0.); + } + return dstress_points; +} + +void MAST::Solid1DArbitrarySectionElementPropertyCard::calculateGeometricProperties(libMesh::MeshBase& mesh){ + Real C_x, C_y, A, Ix, Iy, Ixy; + C_x = 0.0; C_y = 0.0; A = 0.0; Ix = 0.0; Iy = 0.0; Ixy = 0.0; + libMesh::MeshBase::const_element_iterator el_it = mesh.elements_begin(); + libMesh::MeshBase::const_element_iterator end_el_it = mesh.elements_end(); + for ( ; el_it != end_el_it; el_it++) + { + for (uint i=0; i<(*el_it)->n_nodes(); i++) + { + Real xi = (*el_it)->point(i)(0); + Real yi = (*el_it)->point(i)(1); + Real xi1, yi1; + + if (i==(*el_it)->n_nodes()-1) + { + xi1 = (*el_it)->point(0)(0); + yi1 = (*el_it)->point(0)(1); + } + else + { + xi1 = (*el_it)->point(i+1)(0); + yi1 = (*el_it)->point(i+1)(1); + } + Real Ibase = (xi*yi1 - xi1*yi); + Ix += Ibase*(yi*yi + yi*yi1 + yi1*yi1); + Iy += Ibase*(xi*xi + xi*xi1 + xi1*xi1); + Ixy += Ibase*(xi*yi1 + 2*xi*yi + 2*xi1*yi1 + xi1*yi); + } + A += (*el_it)->volume(); // Returns the area for 2D elements. + C_x += (*el_it)->centroid()(0)*(*el_it)->volume(); + C_y += (*el_it)->centroid()(1)*(*el_it)->volume(); + } + C_x /= A; + C_y /= A; + Ix /= 12.0; + Iy /= 12.0; + Ixy /= 24.0; + _A_val = A; + _Izz_val = Ix-A*C_y*C_y; + _Iyy_val= Iy - A*C_x*C_x; + _Ip_val = _Izz_val + _Iyy_val; // Perpendicular Axis Theory + + if (not _torsionConstantSet) + { + // A very very rough approximation to the torsion constant + Real a = sqrt(A); // Length of side of square with equivalent area as mesh + _J_val = 0.189*pow(a,4); + // FIXME: For arbitrary sections, it may be necessary to perform FEA + } +} + + +void MAST::Solid1DArbitrarySectionElementPropertyCard::calculateGeometricProperties(RealMatrixX& vertices){ + Real C_x, C_y, A, Ix, Iy, Ixy; + C_x = 0.0; C_y = 0.0; A = 0.0; Ix = 0.0; Iy = 0.0; Ixy = 0.0; + for (uint i=0; i get_stress_points(const libMesh::Point& p, const Real t, const libMesh::Point ps) const override; + + virtual const libMesh::Point get_shear_center_derivative(MAST::FunctionBase& f, const libMesh::Point& p, const Real t) override; + + virtual const libMesh::Point get_centroid_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t) const override; + + virtual const std::vector get_stress_points_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, const libMesh::Point dps) const override; + + virtual void add_stress_point(const libMesh::Point stress_point); + + protected: + + bool _torsionConstantSet = false; + + void calculateGeometricProperties(libMesh::MeshBase& mesh); + void calculateGeometricProperties(RealMatrixX& vertices); + + Real _A_val; + Real _Izz_val; + Real _Iyy_val; + Real _Ip_val; + Real _J_val; + Real _W_val; + Real _Kxx_val; + Real _Kyy_val; + std::vector _stress_points; + }; + +} + + +#endif // __mast__solid_1d_arbitrary_section_element_property_card__ diff --git a/tests/property/CMakeLists.txt b/tests/property/CMakeLists.txt index 88e0046c..96faebe8 100644 --- a/tests/property/CMakeLists.txt +++ b/tests/property/CMakeLists.txt @@ -1,6 +1,7 @@ target_sources(mast_catch_tests PRIVATE ${CMAKE_CURRENT_LIST_DIR}/mast_solid_1d_section_element_property_card.cpp + ${CMAKE_CURRENT_LIST_DIR}/mast_solid_1d_arbitrary_section_element_property_card.cpp ${CMAKE_CURRENT_LIST_DIR}/mast_solid_2d_section_element_property_card.cpp ${CMAKE_CURRENT_LIST_DIR}/mast_3d_isotropic_element_property_card.cpp) @@ -284,14 +285,22 @@ set_tests_properties(Element_Property_Card_1D_Dynamic_mpi FIXTURES_REQUIRED Isotropic_Material_1D_Dynamic_mpi) -# ## ============================================================================ -# # 1D Arbitrary Cross Section -# add_test(NAME Arbitrary_Element_Property_Card_1D_Base -# COMMAND mast_catch_tests "arbitrary_element_property_card_constant_base_1d") -# set_tests_properties(Arbitrary_Element_Property_Card_1D_Base -# PROPERTIES -# FIXTURES_REQUIRED Isotropic_Material_1D_Structural) -# ## ============================================================================ +## ============================================================================ +# 1D Arbitrary Cross Section +add_test(NAME Arbitrary_Element_Property_Card_1D_Base + COMMAND $ -w NoTests "arbitrary_element_property_card_constant_base_1d") +set_tests_properties(Arbitrary_Element_Property_Card_1D_Base + PROPERTIES + LABELS "SEQ" + FIXTURES_REQUIRED Isotropic_Material_1D_Structural) + +add_test(NAME Arbitrary_Element_Property_Card_1D_Base_mpi + COMMAND ${MPIEXEC_EXECUTABLE} -np 2 $ -w NoTests "arbitrary_element_property_card_constant_base_1d") +set_tests_properties(Arbitrary_Element_Property_Card_1D_Base_mpi + PROPERTIES + LABELS "MPI" + FIXTURES_REQUIRED Isotropic_Material_1D_Structural_mpi) +## ============================================================================ # ## ============================================================================ diff --git a/tests/property/mast_solid_1d_arbitrary_section_element_property_card.cpp b/tests/property/mast_solid_1d_arbitrary_section_element_property_card.cpp new file mode 100644 index 00000000..cb2d1fe5 --- /dev/null +++ b/tests/property/mast_solid_1d_arbitrary_section_element_property_card.cpp @@ -0,0 +1,254 @@ +// Catch2 includes +#include "catch.hpp" + +// libMesh includes +#include "libmesh/point.h" + +// MAST includes +#include "base/parameter.h" +#include "base/constant_field_function.h" +#include "property_cards/isotropic_material_property_card.h" +#include "property_cards/solid_1d_arbitrary_section_element_property_card.h" + +// Custom includes +#include "test_helpers.h" + +extern libMesh::LibMeshInit* p_global_init; + + +TEST_CASE("arbitrary_element_property_card_constant_base_1d", + "[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + + const Real A_test = 11.3; + const Real Iyyc_test = 3.1; + const Real Izzc_test = 4.2; + const Real Izyc_test = 2.6; + const Real Ipc_test = Iyyc_test + Izzc_test; + const Real J_test = 5.2; + const Real W_test = 3.2; + const Real kappa_zz_test = 0.66; + const Real kappa_yy_test = 0.23; + + //const Real offset_y_test = 0.547; + //const Real offset_z_test = -0.258; + + const Real offset_y_test = 0.0; + const Real offset_z_test = 0.0; + + const Real Qz_true = A_test * offset_y_test; + const Real Qy_true = A_test * offset_z_test; + + const Real Iyy_true = Iyyc_test + A_test * offset_z_test * offset_z_test; + const Real Izz_true = Izzc_test + A_test * offset_y_test * offset_y_test; + const Real Izy_true = Izyc_test + A_test * offset_y_test * offset_z_test; + const Real Ip_true = Iyy_true + Izz_true; + + // Define Material Properties as MAST Parameters + MAST::Parameter rho("rho_param", 1420.5); // Density + MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity + MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio + MAST::Parameter kappa("kappa_param", 5.0/6.0); // Shear coefficient + MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity + MAST::Parameter k("k_param", 237.0); // Thermal Conductivity + + // Define Section Properties as MAST Parameters + MAST::Parameter A("A", A_test); + MAST::Parameter Iyyc("Iyyc", Iyyc_test); + MAST::Parameter Izzc("Izzc", Izzc_test); + MAST::Parameter Izyc("Izyc", Izyc_test); + MAST::Parameter Ipc("Ipc", Ipc_test); + MAST::Parameter J("J", J_test); + MAST::Parameter W("W", W_test); + MAST::Parameter Kzz("Kzz", kappa_zz_test); + MAST::Parameter Kyy("Kyy", kappa_yy_test); + + MAST::Parameter offset_y("offy_param", offset_y_test); // Section offset in y-direction + MAST::Parameter offset_z("offz_param", offset_z_test); // Section offset in z-direction + + // Create field functions to dsitribute these constant parameters throughout the model + // Section Property Field Functions + MAST::ConstantFieldFunction A_f("A", A); + MAST::ConstantFieldFunction Iyy_f("Iyy", Iyyc); + MAST::ConstantFieldFunction Izz_f("Izz", Izzc); + MAST::ConstantFieldFunction Izy_f("Izy", Izyc); + MAST::ConstantFieldFunction Ip_f("Ip", Ipc); + MAST::ConstantFieldFunction J_f("J", J); + MAST::ConstantFieldFunction W_f("W", W); + MAST::ConstantFieldFunction Kzz_f("Kappazz", Kzz); + MAST::ConstantFieldFunction Kyy_f("Kappayy", Kyy); + MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); + MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); + // Material Property Field Functions + MAST::ConstantFieldFunction rho_f("rho", rho); + MAST::ConstantFieldFunction E_f("E", E); + MAST::ConstantFieldFunction nu_f("nu", nu); + MAST::ConstantFieldFunction kappa_f("kappa", kappa); + MAST::ConstantFieldFunction cp_f("cp", cp); + MAST::ConstantFieldFunction k_f("k_th", k); + + // Initialize the material + MAST::IsotropicMaterialPropertyCard material; + + // Add the material property constant field functions to the material card + material.add(rho_f); + material.add(k_f); + material.add(cp_f); + material.add(E_f); + material.add(nu_f); + material.add(kappa_f); + + // Initialize the section + MAST::Solid1DArbitrarySectionElementPropertyCard section; + + // Add the section property constant field functions to the section card + section.add(A_f); + section.add(Iyy_f); + section.add(Izz_f); + section.add(Izy_f); + section.add(Ip_f); + section.add(J_f); + section.add(W_f); + section.add(Kzz_f); + section.add(Kyy_f); + section.add(offsety_f); + section.add(offsetz_f); + + // Add the material card to the section card + section.set_material(material); + + // Specify a section orientation point and add it to the section. + RealVectorX orientation = RealVectorX::Zero(3); + orientation(1) = 1.0; + section.y_vector() = orientation; + + // Now initialize the section + section.init(); + + const libMesh::Point point(4.3, -3.5, -6.7); + const Real time = 8.22; + const libMesh::Point Zp(0.0, 0.0, 0.0); + + SECTION("cross_sectional_properties") + { + REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional + REQUIRE( section.depends_on(A) ); + REQUIRE( section.depends_on(Iyyc) ); + REQUIRE( section.depends_on(Izzc) ); + REQUIRE( section.depends_on(Izyc) ); + REQUIRE( section.depends_on(Ipc) ); + REQUIRE( section.depends_on(J) ); + REQUIRE( section.depends_on(W) ); + REQUIRE( section.depends_on(Kzz) ); + REQUIRE( section.depends_on(Kyy) ); + REQUIRE( section.depends_on(offset_y) ); + REQUIRE( section.depends_on(offset_z) ); + REQUIRE( section.depends_on(k) ); + REQUIRE( section.depends_on(cp) ); + REQUIRE( section.depends_on(rho) ); + REQUIRE( section.if_isotropic() ); + + Real area; + const MAST::FieldFunction& Area = section.A(); + Area(point, time, area); + REQUIRE( area == Approx(A_test) ); + + Real first_area_moment_y; + const MAST::FieldFunction& Ay = section.Ay(); + Ay(point, time, first_area_moment_y); + CHECK( first_area_moment_y == Approx(Qy_true) ); + + Real first_area_moment_z; + const MAST::FieldFunction& Az = section.Az(); + Az(point, time, first_area_moment_z); + CHECK( first_area_moment_z == Approx(Qz_true) ); + + RealMatrixX I; + const MAST::FieldFunction& Inertias = section.I(); + Inertias(point, time, I); + REQUIRE( I(0,1) == I(1,0) ); + Real Iyyv = I(1,1); + Real Izzv = I(0,0); + Real Izyv = I(0,1); + REQUIRE( Izzv == Approx(Izz_true) ); + REQUIRE( Iyyv == Approx(Iyy_true) ); + REQUIRE( Izyv == Approx(Izy_true) ); + + Real Ipv; + const MAST::FieldFunction& PolarInertia = section.Ip(); + PolarInertia(point, time, Ipv); + REQUIRE( Ipv == Approx(Ip_true) ); + + Real torsion_constant; + const MAST::FieldFunction& TorsionConstant = section.J(); + TorsionConstant(point, time, torsion_constant); + REQUIRE( torsion_constant == Approx(J_test)); + + Real warping_constant; + const MAST::FieldFunction& WarpingConstant = section.Gam(); + WarpingConstant(point, time, warping_constant); + REQUIRE( warping_constant == Approx(W_test) ); + + RealMatrixX shear_coefficients; + const MAST::FieldFunction& ShearCoefficientMatrix = section.Kap(); + ShearCoefficientMatrix(point, time, shear_coefficients); + REQUIRE( shear_coefficients(0,0) == Approx(kappa_zz_test) ); + REQUIRE( shear_coefficients(1,1) == Approx(kappa_yy_test) ); + } + + SECTION("diagonal_mass_matrix_flag") + { + REQUIRE_FALSE( section.if_diagonal_mass_matrix() ); + + section.set_diagonal_mass_matrix(true); + REQUIRE( section.if_diagonal_mass_matrix() ); + } + + SECTION("stress_points") + { + const libMesh::Point Cp(0.1, 2.0, 0.0); + const libMesh::Point Dp(0.5, -3.1, 0.0); + const libMesh::Point Ep(-0.6, -0.7, 0.0); + const libMesh::Point Fp(-0.7, 1.1, 0.0); + + section.add_stress_point(Cp); + section.add_stress_point(Dp); + section.add_stress_point(Ep); + section.add_stress_point(Fp); + + std::vector stress_points = section.get_stress_points(point, time, Zp); + + REQUIRE( stress_points.size() == 4 ); + REQUIRE( stress_points[0] == Cp ); + REQUIRE( stress_points[1] == Dp ); + REQUIRE( stress_points[2] == Ep ); + REQUIRE( stress_points[3] == Fp ); + + std::vector dstress_points = section.get_stress_points_derivative(rho, point, time, Zp); + for (uint i=0; i Date: Fri, 21 Feb 2020 11:29:01 -0500 Subject: [PATCH 05/27] Replaced libmesh_error() with detailed error messages. --- src/base/field_function_base.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/base/field_function_base.h b/src/base/field_function_base.h index 2b777366..e7922cd9 100644 --- a/src/base/field_function_base.h +++ b/src/base/field_function_base.h @@ -58,7 +58,7 @@ namespace MAST { */ virtual void operator() (ValType& v) const { - libmesh_error(); // must be implemented in derived class + libmesh_error_msg("Must be implemented in derived class; " << __PRETTY_FUNCTION__ << " in " << __FILE__ << " at line " << __LINE__); } @@ -67,7 +67,7 @@ namespace MAST { */ virtual void perturbation (ValType& v) const { - libmesh_error(); // must be implemented in derived class + libmesh_error_msg("Must be implemented in derived class; " << __PRETTY_FUNCTION__ << " in " << __FILE__ << " at line " << __LINE__); } @@ -78,7 +78,7 @@ namespace MAST { virtual void derivative (const MAST::FunctionBase& f, ValType& v) const { - libmesh_error(); // must be implemented in derived class + libmesh_error_msg("Must be implemented in derived class; " << __PRETTY_FUNCTION__ << " in " << __FILE__ << " at line " << __LINE__); } @@ -90,7 +90,7 @@ namespace MAST { const Real t, ValType& v) const { - libmesh_error(); // must be implemented in derived class + libmesh_error_msg("Must be implemented in derived class; " << __PRETTY_FUNCTION__ << " in " << __FILE__ << " at line " << __LINE__); } @@ -103,7 +103,7 @@ namespace MAST { const Real t, ValType& v) const { - libmesh_error(); // must be implemented in derived class + libmesh_error_msg("Must be implemented in derived class; " << __PRETTY_FUNCTION__ << " in " << __FILE__ << " at line " << __LINE__); } @@ -117,7 +117,7 @@ namespace MAST { const Real t, ValType& v) const { - libmesh_error(); // must be implemented in derived class + libmesh_error_msg("Must be implemented in derived class; " << __PRETTY_FUNCTION__ << " in " << __FILE__ << " at line " << __LINE__); } protected: From ff8060b9eb04390969dde561425d09e214394168 Mon Sep 17 00:00:00 2001 From: David John Neiferd <13425967+JohnDN90@users.noreply.github.com> Date: Fri, 21 Feb 2020 14:52:10 -0500 Subject: [PATCH 06/27] Added Pilkey elasticity and shoelace methods to calculate section properties. Added ROD cross section and corresponding supporting base classes. --- src/base/CMakeLists.txt | 4 +- src/base/field_function_base.h | 14 + src/base/warping_assembly.cpp | 802 +++++++++ src/base/warping_assembly.h | 238 +++ src/elasticity/CMakeLists.txt | 4 +- src/elasticity/structural_element_2d.cpp | 222 ++- src/elasticity/structural_element_2d.h | 11 + .../warping_system_initialization.cpp | 48 + .../warping_system_initialization.h | 46 + src/mesh/fe_base.cpp | 12 +- src/property_cards/CMakeLists.txt | 10 +- .../cross_section_property_pilkey.cpp | 1152 ++++++++++++ .../cross_section_property_pilkey.h | 164 ++ ...arameter_section_element_property_card.cpp | 285 +++ ...1parameter_section_element_property_card.h | 229 +++ ...arameter_section_element_property_card.cpp | 215 +++ ...nparameter_section_element_property_card.h | 237 +++ ...d_1d_rod_section_element_property_card.cpp | 345 ++++ ...lid_1d_rod_section_element_property_card.h | 139 ++ ...solid_1d_section_element_property_card.cpp | 47 +- .../solid_1d_section_element_property_card.h | 12 +- tests/property/CMakeLists.txt | 90 +- ...d_1d_rod_section_element_property_card.cpp | 1546 +++++++++++++++++ ...solid_1d_section_element_property_card.cpp | 24 +- 24 files changed, 5750 insertions(+), 146 deletions(-) create mode 100644 src/base/warping_assembly.cpp create mode 100644 src/base/warping_assembly.h create mode 100644 src/elasticity/warping_system_initialization.cpp create mode 100644 src/elasticity/warping_system_initialization.h create mode 100644 src/property_cards/cross_section_property_pilkey.cpp create mode 100644 src/property_cards/cross_section_property_pilkey.h create mode 100644 src/property_cards/solid_1d_1parameter_section_element_property_card.cpp create mode 100644 src/property_cards/solid_1d_1parameter_section_element_property_card.h create mode 100644 src/property_cards/solid_1d_nparameter_section_element_property_card.cpp create mode 100644 src/property_cards/solid_1d_nparameter_section_element_property_card.h create mode 100644 src/property_cards/solid_1d_rod_section_element_property_card.cpp create mode 100644 src/property_cards/solid_1d_rod_section_element_property_card.h create mode 100644 tests/property/mast_solid_1d_rod_section_element_property_card.cpp diff --git a/src/base/CMakeLists.txt b/src/base/CMakeLists.txt index 75ad7ea4..fba7d7c2 100644 --- a/src/base/CMakeLists.txt +++ b/src/base/CMakeLists.txt @@ -45,7 +45,9 @@ target_sources(mast ${CMAKE_CURRENT_LIST_DIR}/transient_assembly.cpp ${CMAKE_CURRENT_LIST_DIR}/transient_assembly.h ${CMAKE_CURRENT_LIST_DIR}/transient_assembly_elem_operations.cpp - ${CMAKE_CURRENT_LIST_DIR}/transient_assembly_elem_operations.h) + ${CMAKE_CURRENT_LIST_DIR}/transient_assembly_elem_operations.h + ${CMAKE_CURRENT_LIST_DIR}/warping_assembly.cpp + ${CMAKE_CURRENT_LIST_DIR}/warping_assembly.h) configure_file(${CMAKE_CURRENT_LIST_DIR}/mast_config.h.in ${CMAKE_CURRENT_LIST_DIR}/mast_config.h) diff --git a/src/base/field_function_base.h b/src/base/field_function_base.h index e7922cd9..75adab4b 100644 --- a/src/base/field_function_base.h +++ b/src/base/field_function_base.h @@ -120,6 +120,20 @@ namespace MAST { libmesh_error_msg("Must be implemented in derived class; " << __PRETTY_FUNCTION__ << " in " << __FILE__ << " at line " << __LINE__); } + + /*! + * calculates the value of the derivative of function with respect to + * the function \p f at the specified point, \p p, and time, + * \p t using finite differences, and returns it in \p v. + */ + virtual void derivative (MAST::FunctionBase& f, + const libMesh::Point& p, + const Real t, + ValType& v) { + + libmesh_error_msg("Must be implemented in derived class; " << __PRETTY_FUNCTION__ << " in " << __FILE__ << " at line " << __LINE__); + } + protected: }; diff --git a/src/base/warping_assembly.cpp b/src/base/warping_assembly.cpp new file mode 100644 index 00000000..46db96b4 --- /dev/null +++ b/src/base/warping_assembly.cpp @@ -0,0 +1,802 @@ +/* + * MAST: Multidisciplinary-design Adaptation and Sensitivity Toolkit + * Copyright (C) 2013-2019 Manav Bhatia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +// MAST includes +#include "base/warping_assembly.h" +#include "base/system_initialization.h" +#include "base/physics_discipline_base.h" +#include "base/mesh_field_function.h" +#include "base/nonlinear_system.h" +#include "base/nonlinear_implicit_assembly_elem_operations.h" +#include "boundary_condition/point_load_condition.h" +#include "numerics/utility.h" +#include "mesh/geom_elem.h" +#include "mesh/fe_base.h" +#include "property_cards/element_property_card_2D.h" +#include "property_cards/material_property_card_base.h" + +// libMesh includes +#include "libmesh/nonlinear_solver.h" +#include "libmesh/numeric_vector.h" +#include "libmesh/sparse_matrix.h" +#include "libmesh/dof_map.h" +#include "libmesh/petsc_matrix.h" + + + +MAST::WarpingAssembly:: +WarpingAssembly():MAST::AssemblyBase(), +_post_assembly (nullptr), +_res_l2_norm (0.), +_first_iter_res_l2_norm (-1.) { + +} + + + +MAST::WarpingAssembly::~WarpingAssembly() { + +} + + + +void +MAST::WarpingAssembly:: +set_post_assembly_operation(MAST::WarpingAssembly::PostAssemblyOperation& post) { + + _post_assembly = &post; +} + + +void +MAST::WarpingAssembly:: +make_matrix_symmetric(libMesh::SparseMatrix* J) +{ + libMesh::PetscMatrix Jt(_system->system().comm()); + J->close(); // Necessary to be able to do the transpose + J->get_transpose(Jt); + J->add(1.0, Jt); + J->add(-0.5, *J); +} + + +const geometric_properties MAST::WarpingAssembly::calculate_geometric_properties() const +{ + geometric_properties gp; + + MAST::NonlinearSystem& nonlin_sys = _system->system(); + + libMesh::MeshBase::const_element_iterator el = nonlin_sys.get_mesh().active_local_elements_begin(); + + const libMesh::MeshBase::const_element_iterator end_el = nonlin_sys.get_mesh().active_local_elements_end(); + + for ( ; el != end_el; ++el) + { + const libMesh::Elem* elem = *el; + + uint n_nodes = elem->n_nodes(); + + MAST::GeomElem geom_elem; + geom_elem.init(*elem, *_system); + + /** Default number of quadrature points for second order triangular + * elements is 7. We only need six for full integration of section + * properties. So, we set the number of extra quadrature points to -1 + * for 6 quadrature points + */ + const MAST::ElementPropertyCard2D& property = + dynamic_cast(_discipline->get_property_card(*elem)); + + std::unique_ptr fe(geom_elem.init_fe(true, false, property.extra_quadrature_order(geom_elem))); + + const std::vector& JxW = fe->get_JxW(); + const std::vector& qpoint = fe->get_xyz(); + const std::vector>& phi = fe->get_phi(); + //const std::vector>& dphi = fe->get_dphi(); + + gp.A += elem->volume(); + + // Get column vectors of x and y coordinates +// RealVectorX xe = RealVectorX::Zero(n_nodes); +// RealVectorX ye = RealVectorX::Zero(n_nodes); +// for (uint i=0; ipoint(i)(0); +// ye(i) = elem->point(i)(1); +// } + + // Loop over quadrature points + for (unsigned int qp=0; qp& F_warp, + const libMesh::NumericVector& Omega, + const libMesh::NumericVector& Psi, + const libMesh::NumericVector& Phi, + const Real A, const Real Ixxc, const Real Iyyc, const Real Ixyc, + const Real xc, const Real yc) const +{ + warping_properties wp; + + MAST::NonlinearSystem& nonlin_sys = _system->system(); + + std::vector dof_indices; + const libMesh::DofMap& dof_map = nonlin_sys.get_dof_map(); + + const uint w_var = _system->system().variable_number("warping_w"); + const uint lambda_var = _system->system().variable_number("warping_lambda"); + + libMesh::MeshBase::const_element_iterator el = nonlin_sys.get_mesh().active_local_elements_begin(); + + const libMesh::MeshBase::const_element_iterator end_el = nonlin_sys.get_mesh().active_local_elements_end(); + + Real kappa_x = 0.0; + Real kappa_y = 0.0; + Real kappa_xy = 0.0; + + Real inv_kappa_x = 0.0; + Real inv_kappa_y = 0.0; + Real inv_kappa_xy = 0.0; + + Real nu, delta_s; + + for ( ; el != end_el; ++el) + { + const libMesh::Elem* elem = *el; + + uint n_nodes = elem->n_nodes(); + + MAST::GeomElem geom_elem; + geom_elem.init(*elem, *_system); + + dof_map.dof_indices(elem, dof_indices, w_var); + + const MAST::ElementPropertyCard2D& property = + dynamic_cast(_discipline->get_property_card(*elem)); + + const MAST::FieldFunction& nu_f = property.get_material().get>("nu"); + + /** Default number of quadrature points for second order triangular + * elements is 7. We only need six for full integration of section + * properties. So, we set the number of extra quadrature points to -1 + * for 6 quadrature points + */ + std::unique_ptr fe(geom_elem.init_fe(true, false, property.extra_quadrature_order(geom_elem))); + + const std::vector& JxW = fe->get_JxW(); + const std::vector& qpoint = fe->get_xyz(); + const std::vector>& phi = fe->get_phi(); + const std::vector>& dphi = fe->get_dphi(); + + // Get column vectors of x and y coordinates +// RealVectorX xe = RealVectorX::Zero(n_nodes); +// RealVectorX ye = RealVectorX::Zero(n_nodes); + RealVectorX we = RealVectorX::Zero(n_nodes); + RealVectorX psie = RealVectorX::Zero(n_nodes); + RealVectorX phie = RealVectorX::Zero(n_nodes); + for (uint i=0; ipoint(i)(0); +// ye(i) = elem->point(i)(1); + we(i) = Omega(dof_indices[i]); + psie(i) = Psi(dof_indices[i]); + phie(i) = Phi(dof_indices[i]); + } + + // Loop over quadrature points + for (unsigned int qp=0; qp> scaled_F_warp = F_warp.clone(); +// uint i=0; +// for (const auto node_ptr : nonlin_sys.get_mesh().node_ptr_range()) +// { +// dof_map.dof_indices(node_ptr, dof_indices, w_var); +// nu_f(*node_ptr, 0.0, nu); +// delta_s = 2.0*(1.0+nu)*(Ixxc*Iyyc - Ixyc*Ixyc); +// scaled_F_warp->operator()(i) /= delta_s; +// dof_indices.clear(); +// } +// wp.xs -= scaled_F_warp->dot(Phi); +// wp.ys += scaled_F_warp->dot(Psi); + + Real denom = Ixxc*Iyyc - Ixyc*Ixyc; + wp.xs_t = (Ixyc * wp.Ixw - Iyyc * wp.Iyw) / denom; + wp.ys_t = (Ixxc * wp.Ixw - Ixyc * wp.Iyw) / denom; + wp.gamma = wp.Iw - wp.Qw * wp.Qw / A - wp.ys * wp.Ixw + wp.xs * wp.Iyw; + + wp.kappa_x = 1.0/(A*inv_kappa_x); + wp.kappa_y = 1.0/(A*inv_kappa_y); + wp.kappa_xy = 1.0/(A*inv_kappa_xy); + + wp.J = Ixxc + Iyyc - Omega.dot(F_warp); + + // Shift the shear centers to account for the shifting of the mesh's + // global coordinates to the sections geometric centroid + wp.xs_t += xc; + wp.ys_t += yc; + wp.xs += xc; + wp.ys += yc; + + return wp; +} + + +void +MAST::WarpingAssembly:: +get_loads(libMesh::NumericVector& F_warp, + libMesh::NumericVector& F_shearx, + libMesh::NumericVector& F_sheary, + const Real xc, const Real yc, + const Real Ixxc, const Real Iyyc, const Real Ixyc) +{ + MAST::NonlinearSystem& nonlin_sys = _system->system(); + + std::vector dof_indices; + const libMesh::DofMap& dof_map = nonlin_sys.get_dof_map(); + + libMesh::MeshBase::const_element_iterator el = + nonlin_sys.get_mesh().active_local_elements_begin(); + + const libMesh::MeshBase::const_element_iterator end_el = + nonlin_sys.get_mesh().active_local_elements_end(); + + const uint w_var = _system->system().variable_number("warping_w"); + const uint lambda_var = _system->system().variable_number("warping_lambda"); + + for ( ; el != end_el; ++el) + { + const libMesh::Elem* elem = *el; + + MAST::GeomElem geom_elem; + geom_elem.init(*elem, *_system); + + const MAST::ElementPropertyCard2D& property = + dynamic_cast(_discipline->get_property_card(*elem)); + + const MAST::FieldFunction& nu_f = property.get_material().get>("nu"); + + dof_map.dof_indices(elem, dof_indices, w_var); + + /** Default number of quadrature points for second order triangular + * elements is 7. We only need six for full integration of section + * properties. So, we set the number of extra quadrature points to -1 + * for 6 quadrature points + */ + std::unique_ptr fe(geom_elem.init_fe(true, false, property.extra_quadrature_order(geom_elem))); + + const std::vector& JxW = fe->get_JxW(); + const std::vector& qpoint = fe->get_xyz(); + const std::vector>& phi = fe->get_phi(); + const std::vector>& dphi = fe->get_dphi(); + + // Get column vectors of x and y coordinates of element nodes, shifted + // so that structures centriod is at (0,0). + uint n_nodes = elem->n_nodes(); +// RealVectorX xe = RealVectorX::Zero(n_nodes); +// RealVectorX ye = RealVectorX::Zero(n_nodes); +// for (uint i=0; inode_ref(i)(0);// - xc; +// ye(i) = elem->node_ref(i)(1);// - yc; +// } + + RealVectorX f_warp_e = RealVectorX::Zero(n_nodes); + RealVectorX f_shear_x_e = RealVectorX::Zero(n_nodes); + RealVectorX f_shear_y_e = RealVectorX::Zero(n_nodes); + + // Loop over quadrature points + for (unsigned int qp=0; qp& X, + libMesh::NumericVector* R, + libMesh::SparseMatrix* J, + libMesh::NonlinearImplicitSystem& S) { + + libmesh_assert(_system); + libmesh_assert(_discipline); + libmesh_assert(_elem_ops); + + MAST::NonlinearSystem& nonlin_sys = _system->system(); + + // make sure that the system for which this object was created, + // and the system passed through the function call are the same + libmesh_assert_equal_to(&S, &(nonlin_sys)); + + if (R) R->zero(); + if (J) J->zero(); + + // iterate over each element, initialize it and get the relevant + // analysis quantities + RealVectorX vec, sol; + RealMatrixX mat; + + std::vector dof_indices; + const libMesh::DofMap& dof_map = _system->system().get_dof_map(); + + + std::unique_ptr > localized_solution; + localized_solution.reset(build_localized_vector(nonlin_sys, + X).release()); + + + // if a solution function is attached, initialize it + if (_sol_function) + _sol_function->init( X); + + + libMesh::MeshBase::const_element_iterator el = + nonlin_sys.get_mesh().active_local_elements_begin(); + const libMesh::MeshBase::const_element_iterator end_el = + nonlin_sys.get_mesh().active_local_elements_end(); + + MAST::NonlinearImplicitAssemblyElemOperations& + ops = dynamic_cast(*_elem_ops); + + const uint w_var = _system->system().variable_number("warping_w"); + const uint lambda_var = _system->system().variable_number("warping_lambda"); + + for ( ; el != end_el; ++el) + { + const libMesh::Elem* elem = *el; + + dof_map.dof_indices (elem, dof_indices, w_var); + + MAST::GeomElem geom_elem; + ops.set_elem_data(elem->dim(), *elem, geom_elem); + geom_elem.init(*elem, *_system); + + ops.init(geom_elem); + + // get the solution + unsigned int ndofs = (unsigned int)dof_indices.size(); + sol.setZero(ndofs); + vec.setZero(ndofs); + mat.setZero(ndofs, ndofs); + + for (unsigned int i=0; iattach_active_solution_function(*_sol_function); + + //_check_element_numerical_jacobian(*physics_elem, sol); + + // perform the element level calculations + ops.elem_calculations(J!=nullptr?true:false, + vec, mat); + +// physics_elem->detach_active_solution_function(); + + ops.clear_elem(); + + // copy to the libMesh matrix for further processing + DenseRealVector v; + DenseRealMatrix m; + if (R) + MAST::copy(v, vec); + if (J) + MAST::copy(m, mat); + + // constrain the quantities to account for hanging dofs, + // Dirichlet constraints, etc. + if (R && J) + dof_map.constrain_element_matrix_and_vector(m, v, dof_indices); + else if (R) + dof_map.constrain_element_vector(v, dof_indices); + else + dof_map.constrain_element_matrix(m, dof_indices); + + // add to the global matrices + if (R) R->add_vector(v, dof_indices); + if (J) J->add_matrix(m, dof_indices); + dof_indices.clear(); + } + + if (J) + { + uint n = J->n(); + for (uint i=0; iadd(n-1,i,1.0); + J->add(i,n-1,1.0); + } + //J->add(J->m()-1, J->n()-1, 1.5e-08); + } + + // call the post assembly object, if provided by user + if (_post_assembly) + _post_assembly->post_assembly(X, R, J, S); + + + // if a solution function is attached, clear it + if (_sol_function) + _sol_function->clear(); + + if (R) { + + R->close(); + _res_l2_norm = R->l2_norm(); + if (_first_iter_res_l2_norm < 0.) + _first_iter_res_l2_norm = _res_l2_norm; + } + + if ((J) and (_force_jacobian_symmetry)) + { + make_matrix_symmetric(J); + } + + if (J && close_matrix) J->close(); +} + + + + +void +MAST::WarpingAssembly:: +linearized_jacobian_solution_product (const libMesh::NumericVector& X, + const libMesh::NumericVector& dX, + libMesh::NumericVector& JdX, + libMesh::NonlinearImplicitSystem& S) +{ + libmesh_error_msg("linearized_jacobian_solution_product not implemented in warping_assembly.cpp"); +} + + + +void +MAST::WarpingAssembly:: +second_derivative_dot_solution_assembly (const libMesh::NumericVector& X, + const libMesh::NumericVector& dX, + libMesh::SparseMatrix& d_JdX_dX, + libMesh::NonlinearImplicitSystem& S) +{ + libmesh_error_msg("second_derivative_dot_solution_assembly not implemented in warping_assembly.cpp"); +} + + + + + +bool +MAST::WarpingAssembly:: +sensitivity_assemble (const MAST::FunctionBase& f, + libMesh::NumericVector& sensitivity_rhs) +{ + libmesh_error_msg("sensitivity_assemble not implemented in warping_assembly.cpp"); + + libmesh_assert(_system); + libmesh_assert(_discipline); + libmesh_assert(_elem_ops); + + MAST::NonlinearSystem& nonlin_sys = _system->system(); + + sensitivity_rhs.zero(); + + // iterate over each element, initialize it and get the relevant + // analysis quantities + RealVectorX vec, sol; + + std::vector dof_indices; + const libMesh::DofMap& dof_map = nonlin_sys.get_dof_map(); + + + std::unique_ptr > localized_solution; + localized_solution.reset(build_localized_vector(nonlin_sys, + *nonlin_sys.solution).release()); + + // if a solution function is attached, initialize it + if (_sol_function) + _sol_function->init( *nonlin_sys.solution); + + libMesh::MeshBase::const_element_iterator el = + nonlin_sys.get_mesh().active_local_elements_begin(); + const libMesh::MeshBase::const_element_iterator end_el = + nonlin_sys.get_mesh().active_local_elements_end(); + + MAST::NonlinearImplicitAssemblyElemOperations& + ops = dynamic_cast(*_elem_ops); + + for ( ; el != end_el; ++el) { + + const libMesh::Elem* elem = *el; + + // no sensitivity computation assembly is neeed in these cases + if (_param_dependence && + // if object is specified and elem does not depend on it + !_param_dependence->if_elem_depends_on_parameter(*elem, f)) + continue; + + dof_map.dof_indices (elem, dof_indices); + + MAST::GeomElem geom_elem; + ops.set_elem_data(elem->dim(), *elem, geom_elem); + geom_elem.init(*elem, *_system); + + ops.init(geom_elem); + + // get the solution + unsigned int ndofs = (unsigned int)dof_indices.size(); + sol.setZero(ndofs); + vec.setZero(ndofs); + + for (unsigned int i=0; iattach_active_solution_function(*_sol_function); + + ops.elem_sensitivity_calculations(f, vec); + +// physics_elem->detach_active_solution_function(); + ops.clear_elem(); + + // copy to the libMesh matrix for further processing + DenseRealVector v; + MAST::copy(v, vec); + + // constrain the quantities to account for hanging dofs, + // Dirichlet constraints, etc. + dof_map.constrain_element_vector(v, dof_indices); + + // add to the global matrices + sensitivity_rhs.add_vector(v, dof_indices); + dof_indices.clear(); + } + + // add the point loads if any in the discipline + if (_discipline->point_loads().size()) { + + const MAST::PointLoadSetType& + loads = _discipline->point_loads(); + + vec = RealVectorX::Zero(_system->n_vars()); + + MAST::PointLoadSetType::const_iterator + it = loads.begin(), + end = loads.end(); + + const libMesh::dof_id_type + first_dof = dof_map.first_dof(nonlin_sys.comm().rank()), + end_dof = dof_map.end_dof(nonlin_sys.comm().rank()); + + for ( ; it != end; it++) { + + // get the point load function + const MAST::FieldFunction + &func = (*it)->get>("load"); + + // get the nodes on which this object defines the load + const std::set + nodes = (*it)->get_nodes(); + + std::set::const_iterator + n_it = nodes.begin(), + n_end = nodes.end(); + + for (; n_it != n_end; n_it++) { + + // load at the node + vec.setZero(); + func.derivative(f, **n_it, nonlin_sys.time, vec); + vec *= -1.; + + dof_map.dof_indices(*n_it, dof_indices); + + libmesh_assert_equal_to(dof_indices.size(), vec.rows()); + + // zero the components of the vector if they do not + // belong to this processor + for (unsigned int i=0; i= end_dof) + vec(i) = 0.; + + DenseRealVector v; + MAST::copy(v, vec); + + dof_map.constrain_element_vector(v, dof_indices); + sensitivity_rhs.add_vector(v, dof_indices); + dof_indices.clear(); + } + } + } + + // if a solution function is attached, initialize it + if (_sol_function) + _sol_function->clear(); + + sensitivity_rhs.close(); + + return true; +} + +void MAST::WarpingAssembly::set_force_jacobian_symmetry(bool tf) +{ + _force_jacobian_symmetry = tf; +} + +const bool MAST::WarpingAssembly::get_force_jacobian_symmetry() const +{ + return _force_jacobian_symmetry; +} diff --git a/src/base/warping_assembly.h b/src/base/warping_assembly.h new file mode 100644 index 00000000..37fd2331 --- /dev/null +++ b/src/base/warping_assembly.h @@ -0,0 +1,238 @@ +/* + * MAST: Multidisciplinary-design Adaptation and Sensitivity Toolkit + * Copyright (C) 2013-2019 Manav Bhatia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __mast__warping_assembly__ +#define __mast__warping_assembly__ + +// MAST includes +#include "base/assembly_base.h" + +// libMesh includes +#include "libmesh/nonlinear_implicit_system.h" + +struct geometric_properties +{ + Real A = 0.0; + Real Qx = 0.0; + Real Qy = 0.0; + Real xc = 0.0; + Real yc = 0.0; + Real Ixxc = 0.0; + Real Iyyc = 0.0; + Real Ixyc = 0.0; + Real Ixx = 0.0; + Real Iyy = 0.0; + Real Ixy = 0.0; + Real Ip = 0.0; + Real I11 = 0.0; + Real I22 = 0.0; + Real phi_p = 0.0; + Real rx = 0.0; + Real ry = 0.0;; +}; + + +struct warping_properties +{ + Real J = 0.0; + Real xs = 0.0; + Real ys = 0.0; + Real xs_t = 0.0; + Real ys_t = 0.0; + Real gamma = 0.0; + Real kappa_x = 0.0; + Real kappa_y = 0.0; + Real kappa_xy = 0.0; + Real Ixw = 0.0; + Real Iyw = 0.0; + Real Qw = 0.0; + Real Iw = 0.0; +}; + +namespace MAST { + + // Forward declerations + class NonlinearImplicitAssemblyElemOperations; + + + class WarpingAssembly: + public MAST::AssemblyBase { + public: + + + /*! + * user-provided object to perform actions + * after assembly and before returning to the solver. Use + * \p set_post_assembly_object to provide a pointer to the object. + */ + class PostAssemblyOperation{ + + public: + PostAssemblyOperation() {} + virtual ~PostAssemblyOperation() {} + virtual void post_assembly(const libMesh::NumericVector& X, + libMesh::NumericVector* R, + libMesh::SparseMatrix* J, + libMesh::NonlinearImplicitSystem& S) = 0; + }; + + /*! + * constructor associates this assembly object with the system + */ + WarpingAssembly(); + + + /*! + * destructor resets the association of this assembly object with + * the system + */ + virtual ~WarpingAssembly(); + + + + /*! + * L2 norm of the last-assembled residual + */ + Real res_l2_norm() const { return _res_l2_norm; } + + Real first_iter_res_l2_norm() const { return _first_iter_res_l2_norm; } + + /*! + * reset L2 norm of the last-assembled residual + */ + void reset_residual_norm_history() { + _res_l2_norm = 0.; + _first_iter_res_l2_norm = -1.; + } + + /*! + * sets the PostAssemblyOperation object for use after assembly. + * Note that calling \p clear_discipline_and_system() will + * clear this pointer and the user will have to call this function + * again. + */ + void + set_post_assembly_operation(MAST::WarpingAssembly::PostAssemblyOperation& post); + + /*! + * function that assembles the matrices and vectors quantities for + * nonlinear solution + */ + virtual void + residual_and_jacobian (const libMesh::NumericVector& X, + libMesh::NumericVector* R, + libMesh::SparseMatrix* J, + libMesh::NonlinearImplicitSystem& S); + + + /*! + * calculates the product of the Jacobian and a perturbation in solution + * vector \f$ [J] \{\Delta X\} \f$. For a single discipline system the + * solution vector and linearized solution provided here are used. For + * a multiphysics system, the user must ensure that all relevant + * multidisciplinary data-structures are initialized before calling + * this method. + */ + virtual void + linearized_jacobian_solution_product(const libMesh::NumericVector& X, + const libMesh::NumericVector& dX, + libMesh::NumericVector& JdX, + libMesh::NonlinearImplicitSystem& S); + + + /*! + * calculates \f$ d ([J] \{\Delta X\})/ dX \f$. + */ + virtual void + second_derivative_dot_solution_assembly(const libMesh::NumericVector& X, + const libMesh::NumericVector& dX, + libMesh::SparseMatrix& d_JdX_dX, + libMesh::NonlinearImplicitSystem& S); + + + /** + * Assembly function. This function will be called + * to assemble the RHS of the sensitivity equations (which is -1 times + * sensitivity of system residual) prior to a solve and must + * be provided by the user in a derived class. The method provides dR/dp + * for \p f parameter. + * + * If the routine is not able to provide sensitivity for this parameter, + * then it should return false, and the system will attempt to use + * finite differencing. + */ + virtual bool + sensitivity_assemble (const MAST::FunctionBase& f, + libMesh::NumericVector& sensitivity_rhs); + + /** + * Forces the systems matrix to be symmetric using A = (A + A^T)/2 + */ + virtual void make_matrix_symmetric(libMesh::SparseMatrix* J); + + virtual void set_force_jacobian_symmetry(bool tf); + + virtual const bool get_force_jacobian_symmetry() const; + +// void cross_section_properties (const libMesh::NumericVector& W, +// const libMesh::NumericVector& R, +// const libMesh::SparseMatrix& J); + + void get_loads(libMesh::NumericVector& F_warp, + libMesh::NumericVector& F_shearx, + libMesh::NumericVector& F_sheary, + const Real xc, const Real yc, const Real Ixxc, + const Real Iyyc, const Real Ixyc); + + const geometric_properties calculate_geometric_properties() const; + + const warping_properties calculate_warping_properties( + const libMesh::NumericVector& F_warp, + const libMesh::NumericVector& Omega, + const libMesh::NumericVector& Psi, + const libMesh::NumericVector& Phi, + const Real A, const Real Ixxc, const Real Iyyc, const Real Ixyc, + const Real xc, const Real yc) const; + + protected: + + + + /*! + * this object, if non-NULL is user-provided to perform actions + * after assembly and before returning to the solver + */ + MAST::WarpingAssembly::PostAssemblyOperation* _post_assembly; + + /*! + * L2 norm of the last-assembled residual + */ + Real _res_l2_norm, _first_iter_res_l2_norm; + + /** + * Defines if Jacobian should be forced to be symmetric. + * Default is false. + */ + bool _force_jacobian_symmetry = false; + + }; +} + + +#endif //__mast__warping_assembly__ diff --git a/src/elasticity/CMakeLists.txt b/src/elasticity/CMakeLists.txt index d66edcb5..25b4c768 100644 --- a/src/elasticity/CMakeLists.txt +++ b/src/elasticity/CMakeLists.txt @@ -66,7 +66,9 @@ target_sources(mast ${CMAKE_CURRENT_LIST_DIR}/structural_transient_assembly.cpp ${CMAKE_CURRENT_LIST_DIR}/structural_transient_assembly.h ${CMAKE_CURRENT_LIST_DIR}/timoshenko_bending_operator.cpp - ${CMAKE_CURRENT_LIST_DIR}/timoshenko_bending_operator.h) + ${CMAKE_CURRENT_LIST_DIR}/timoshenko_bending_operator.h + ${CMAKE_CURRENT_LIST_DIR}/warping_system_initialization.cpp + ${CMAKE_CURRENT_LIST_DIR}/warping_system_initialization.h) # Install MAST headers for this directory. install(DIRECTORY ./ DESTINATION include/elasticity diff --git a/src/elasticity/structural_element_2d.cpp b/src/elasticity/structural_element_2d.cpp index 80b1261f..2ae89ce9 100644 --- a/src/elasticity/structural_element_2d.cpp +++ b/src/elasticity/structural_element_2d.cpp @@ -250,6 +250,24 @@ initialize_green_lagrange_strain_operator(const unsigned int qp, +void MAST::StructuralElement2D::initialize_warping_strain_operator( + const unsigned int qp, const MAST::FEBase& fe, + RealMatrixX& Bmat_warp) +{ + // Get the shape function derivatives + const std::vector>& dphis = fe.get_dphi(); + + unsigned int n_phi = (unsigned int)dphis.size(); + + for (uint i=0; iget_phi().size(), n1 = this->n_direct_strain_components(), - n2 =6*n_phi, + n2 = 6*n_phi, n3 = this->n_von_karman_strain_components(); RealMatrixX @@ -1115,98 +1133,125 @@ MAST::StructuralElement2D::internal_residual (bool request_jacobian, strain = RealVectorX::Zero(3), local_f = RealVectorX::Zero(n2); - FEMOperatorMatrix - Bmat_lin, - Bmat_nl_x, - Bmat_nl_y, - Bmat_nl_u, - Bmat_nl_v, - Bmat_bend, - Bmat_vk; - - Bmat_lin.reinit(n1, _system.n_vars(), n_phi); // three stress-strain components - Bmat_nl_x.reinit(2, _system.n_vars(), n_phi); - Bmat_nl_y.reinit(2, _system.n_vars(), n_phi); - Bmat_nl_u.reinit(2, _system.n_vars(), n_phi); - Bmat_nl_v.reinit(2, _system.n_vars(), n_phi); - Bmat_bend.reinit(n1, _system.n_vars(), n_phi); - Bmat_vk.reinit(n3, _system.n_vars(), n_phi); // only dw/dx and dw/dy - bool if_vk = (_property.strain_type() == MAST::NONLINEAR_STRAIN); - - MAST::BendingOperatorType - bending_model = _property.bending_model(_elem); - - std::unique_ptr bend; - - if (bending_model != MAST::NO_BENDING) - bend.reset(MAST::build_bending_operator_2D(bending_model, - *this, - fe->get_qpoints()).release()); - - std::unique_ptr > - mat_stiff_A = _property.stiffness_A_matrix(*this), - mat_stiff_B = _property.stiffness_B_matrix(*this), - mat_stiff_D = _property.stiffness_D_matrix(*this); - - for (unsigned int qp=0; qpinclude_transverse_shear_energy()) - bend->calculate_transverse_shear_residual(request_jacobian, - local_f, - local_jac); - + else // Other structural analysis + { + FEMOperatorMatrix + Bmat_lin, + Bmat_nl_x, + Bmat_nl_y, + Bmat_nl_u, + Bmat_nl_v, + Bmat_bend, + Bmat_vk; + + Bmat_lin.reinit(n1, _system.n_vars(), n_phi); // three stress-strain components + Bmat_nl_x.reinit(2, _system.n_vars(), n_phi); + Bmat_nl_y.reinit(2, _system.n_vars(), n_phi); + Bmat_nl_u.reinit(2, _system.n_vars(), n_phi); + Bmat_nl_v.reinit(2, _system.n_vars(), n_phi); + Bmat_bend.reinit(n1, _system.n_vars(), n_phi); + Bmat_vk.reinit(n3, _system.n_vars(), n_phi); // only dw/dx and dw/dy + + bool if_vk = (_property.strain_type() == MAST::NONLINEAR_STRAIN); + + MAST::BendingOperatorType + bending_model = _property.bending_model(_elem); + + std::unique_ptr bend; + + if (bending_model != MAST::NO_BENDING) + bend.reset(MAST::build_bending_operator_2D(bending_model, + *this, + fe->get_qpoints()).release()); + + std::unique_ptr > + mat_stiff_A = _property.stiffness_A_matrix(*this), + mat_stiff_B = _property.stiffness_B_matrix(*this), + mat_stiff_D = _property.stiffness_D_matrix(*this); + + for (unsigned int qp=0; qpinclude_transverse_shear_energy()) + bend->calculate_transverse_shear_residual(request_jacobian, + local_f, + local_jac); + } // now transform to the global coorodinate system transform_vector_to_global_system(local_f, vec3_n2); @@ -1214,7 +1259,8 @@ MAST::StructuralElement2D::internal_residual (bool request_jacobian, if (request_jacobian) { // for 2D elements - if (_elem.dim() == 2) { + if ((_elem.dim() == 2) and (not _property.get_warping_only())) + { // add small values to the diagonal of the theta_z dofs for (unsigned int i=0; i + +#include "base/parameter.h" +#include "base/constant_field_function.h" +#include "property_cards/cross_section_property_pilkey.h" +#include "base/warping_assembly.h" +#include "elasticity/warping_system_initialization.h" +#include "base/nonlinear_system.h" +#include "property_cards/isotropic_material_property_card.h" +#include "property_cards/solid_2d_section_element_property_card.h" +#include "elasticity/structural_nonlinear_assembly.h" + +#include "libmesh/petsc_nonlinear_solver.h" +#include "libmesh/petsc_linear_solver.h" +#include "libmesh/solver_configuration.h" +#include "libmesh/petsc_macro.h" +#include "libmesh/mesh_triangle_holes.h" + +// this class allows us to set the solver and preconditioner to be appropriate +// for linear elasticity. This is modeled after libMesh's +// systems_of_equations_ex6.C example sorce code. + +/** + * A class that is used by libMesh to set options on PETSc's linear solver. + * Modeled after the code in libMesh's systems_of_equations_ex6.C example + * source code. + */ +class PetscLinearSolverConfiguration : public libMesh::SolverConfiguration +{ +public: + + PetscLinearSolverConfiguration( + libMesh::PetscLinearSolver & petsc_linear_solver): + _petsc_linear_solver(petsc_linear_solver) + { + } + + virtual void configure_solver() + { + PetscErrorCode ierr = 0; + + /** + * Let's PETSc know that it is expecting a zero initial guess. This + * make sense since direct solvers don't utialize an intial guess. + */ + ierr = KSPSetInitialGuessNonzero(_petsc_linear_solver.ksp(), PETSC_FALSE); + CHKERRABORT(_petsc_linear_solver.comm().get(), ierr); + + /** + * Set the KSP type to PREONLY which indicates only the preconditoner + * will be applied, and no iterations performed afterwards. This + * results in a direct solver when the preconditioner is a complete + * factorization of the matrix. + */ + ierr = KSPSetType(_petsc_linear_solver.ksp(), KSPPREONLY); + CHKERRABORT(_petsc_linear_solver.comm().get(), ierr); + + /** + * Set the preconditioner to be a complete LU factorization + */ + ierr = PCSetType(_petsc_linear_solver.pc(), PCLU); + CHKERRABORT(_petsc_linear_solver.comm().get(), ierr); + + /** + * Have MUMPS perform the preconditioner factorization. + */ + ierr = PCFactorSetMatSolverType(_petsc_linear_solver.pc(), MATSOLVERMUMPS); + CHKERRABORT(_petsc_linear_solver.comm().get(), ierr); + + /** + * During factorization, to minimize fill-in (an increase in the number + * of nonzeros (nnz) in a sparse matrix versus the nnz in the + * unfactored matrix) which causes increased memory usage and higher + * computational cost, the matrix is reordered. If multiple matrices + * are to be factored and they have similar sparsity structures (such + * as when performing optimization and doing multiple FEA solves), the + * reordering that was computed on the first matrix will be reused on + * all subsequent matrices. This reduces computational cost by avoiding + * redundant calculation of the reordering permutations. + */ + ierr = PCFactorSetReuseOrdering(_petsc_linear_solver.pc(), PETSC_TRUE); + CHKERRABORT(_petsc_linear_solver.comm().get(), ierr); + } + + libMesh::PetscLinearSolver& _petsc_linear_solver; +}; + + +/** + * A class that is used by libMesh to set options on PETSc's nonlinear solver. + * Modeled after the code in libMesh's systems_of_equations_ex6.C example + * source code. + */ +class PetscNonlinearSolverConfiguration : public libMesh::SolverConfiguration +{ +public: + + PetscNonlinearSolverConfiguration(libMesh::PetscNonlinearSolver & petsc_nonlinear_solver): + _petsc_nonlinear_solver(petsc_nonlinear_solver) + { + } + + virtual void configure_solver() + { + PetscErrorCode ierr = 0; + + /** + * We can make the nonlinear solver act as a linear solver by specifing + * to do only one linear solver. This is useful in MAST where + * everything is modeled in a nonlinear system, and we want to force + * a linear solver if the system is truly linear. + */ + ierr = SNESSetType(_petsc_nonlinear_solver.snes(), SNESKSPONLY); + CHKERRABORT(_petsc_nonlinear_solver.comm().get(), ierr); + + /** + * We can set the linesearch used by the nonlinear solver. Here, we + * used a basic linesearch with a damping value of 1.0 which + * corresponds to the full Newton-Raphson method (when using a + * Newton-Raphson based nonlinear solver). + */ + SNESLineSearch linesearch; + ierr = SNESGetLineSearch(_petsc_nonlinear_solver.snes(), &linesearch); + CHKERRABORT(_petsc_nonlinear_solver.comm().get(), ierr); + + ierr = SNESLineSearchSetType(linesearch, SNESLINESEARCHBASIC); + CHKERRABORT(_petsc_nonlinear_solver.comm().get(), ierr); + + ierr = SNESLineSearchSetDamping(linesearch, 1.0); + CHKERRABORT(_petsc_nonlinear_solver.comm().get(), ierr); + + /** + * Recall that a nonlinear solver essentially linearizes a nonlinear + * system and does iterative linear solves until it converges to the + * nonlinear solution. Below, we configure the options for the linear + * solver called by the nonlinear solver. + */ + + KSP ksp; + SNESGetKSP(_petsc_nonlinear_solver.snes(), &ksp); + + ierr = KSPSetInitialGuessNonzero(ksp, PETSC_FALSE); + CHKERRABORT(_petsc_nonlinear_solver.comm().get(), ierr); + + ierr = KSPSetType(ksp, KSPPREONLY); + CHKERRABORT(_petsc_nonlinear_solver.comm().get(), ierr); + + PC pc; + KSPGetPC(ksp, &pc); + + ierr = PCSetType(pc, PCLU); + CHKERRABORT(_petsc_nonlinear_solver.comm().get(), ierr); + + ierr = PCFactorSetMatSolverType(pc, MATSOLVERMUMPS); + CHKERRABORT(_petsc_nonlinear_solver.comm().get(), ierr); + } + + libMesh::PetscNonlinearSolver& _petsc_nonlinear_solver; +}; + + +MAST::CrossSection::CrossSection( + const libMesh::LibMeshInit& init, + const uint target_n_elems, + MAST::Solid1DSectionElementPropertyCard& property, + const libMesh::ElemType element_type): + _init(init), _property(property), _target_n_elems(target_n_elems), + _element_type(element_type) +{ + _mesh.reset(new libMesh::ReplicatedMesh(_init.comm())); +} + + +Real MAST::CrossSection::get_area(const libMesh::Point& p, const Real t) +{ + _update_geometry(p, t); + return _A; +} + + +Real MAST::CrossSection::get_area_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t) +{ + _update_geometry(f, p, t); + _calculate_shoelace_geometric_properties_sensitivities(f, p, t); + return _dA; +} + + +RealVectorX MAST::CrossSection::get_second_area_moments(const libMesh::Point& p, const Real t) +{ + _update_geometry(p, t); + RealVectorX I(3); + I << _Ixx, _Iyy, _Ixy; + return I; +} + + +RealVectorX MAST::CrossSection::get_second_area_moments_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t) +{ + _update_geometry(f, p, t); + RealVectorX dI(3); + dI << _dIxx, _dIyy, _dIxy; + return dI; +} + + +Real MAST::CrossSection::get_first_area_moment_z(const libMesh::Point& p, const Real t) +{ + _update_geometry(p, t); + return _Qx; +} + + +Real MAST::CrossSection::get_first_area_moment_z_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t) +{ + _update_geometry(f, p, t); + return _dQx; +} + + +Real MAST::CrossSection::get_first_area_moment_y(const libMesh::Point& p, const Real t) +{ + _update_geometry(p, t); + return _Qy; +} + + +Real MAST::CrossSection::get_first_area_moment_y_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t) +{ + _update_geometry(f, p, t); + return _dQy; +} + + +Real MAST::CrossSection::get_second_polar_area_moment(const libMesh::Point& p, const Real t) +{ + _update_geometry(p, t); + Real Ip = _Ixx + _Iyy; + return Ip; +} + + +Real MAST::CrossSection::get_second_polar_area_moment_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t) +{ + _update_geometry(f, p, t); + Real dIp = _dIxx + _dIyy; + return dIp; +} + + +libMesh::Point MAST::CrossSection::get_centroid(const libMesh::Point& p, const Real t) +{ + _update_geometry(p, t); + return libMesh::Point(_Cx, _Cy, 0.); +} + + +libMesh::Point MAST::CrossSection::get_centroid_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t) +{ + _update_geometry(f, p, t); + return libMesh::Point(_dCx, _dCy, 0.); +} + + +RealVectorX MAST::CrossSection::get_second_area_moments_about_centroid(const libMesh::Point& p, const Real t) +{ + _update_geometry(p, t); + RealVectorX Ic(3); + Ic << _Ixxc, _Iyyc, _Ixyc; + return Ic; +} + + +RealVectorX MAST::CrossSection::get_radii_of_gyration(const libMesh::Point& p, const Real t) +{ + _update_geometry(p, t); + RealVectorX r(2); + r << _rx, _ry; + return r; +} + + +RealVectorX MAST::CrossSection::get_elastic_section_modulii(const libMesh::Point& p, const Real t) +{ + _update_geometry(p, t); + RealVectorX Z(4); + Z << _Z_xx_p, _Z_xx_n, _Z_yy_p, _Z_yy_n; + return Z; +} + + +Real MAST::CrossSection::get_torsion_constant(const libMesh::Point& p, const Real t) +{ + _update_warping_geometry(p, t); + return _wp.J; +} + +// TODO: Implement analytical derivative instead of finite difference +Real MAST::CrossSection::get_torsion_constant_derivative(MAST::FunctionBase& f, const libMesh::Point& p, const Real t) +{ + //Real delta = 1.0e-06; + //Real delta = 1.4901161193847656e-08; // np.spacing(1)**0.5 + const Real delta = 1.220703125e-04; // np.spacing(1)**0.25 + MAST::Parameter* param = dynamic_cast(&f); + (*param)() += delta; + _update_warping_geometry(p, t); + const Real Jh = _wp.J; + (*param)() -= 2.0*delta; + _update_warping_geometry(p, t); + const Real Jn = _wp.J; + (*param)() += delta; + return (Jh - Jn)/(2.0*delta); +} + + +libMesh::Point MAST::CrossSection::get_shear_center(const libMesh::Point& p, const Real t) +{ + _update_warping_geometry(p, t); + libMesh::Point shear_center(_wp.xs, _wp.ys, 0.); + return shear_center; +} + +// TODO: Implement analytical derivative instead of finite difference +libMesh::Point MAST::CrossSection::get_shear_center_derivative(MAST::FunctionBase& f, const libMesh::Point& p, const Real t) +{ + //Real delta = 1.0e-06; + const Real delta = 1.220703125e-04; // np.spacing(1)**0.25 + MAST::Parameter* param = dynamic_cast(&f); + (*param)() += delta; + _update_warping_geometry(p, t); + const Real xs_h = _wp.xs; + const Real ys_h = _wp.ys; + +// (*param)() += delta; +// _update_warping_geometry(p, t); +// const Real xs_2h = _wp.xs; +// const Real ys_2h = _wp.ys; +// (*param)() -= delta; + + (*param)() -= 2.0*delta; + _update_warping_geometry(p, t); + const Real xs_n = _wp.xs; + const Real ys_n = _wp.ys; + +// (*param)() -= delta; +// _update_warping_geometry(p, t); +// const Real xs_2n = _wp.xs; +// const Real ys_2n = _wp.ys; +// (*param)() + =delta; + + (*param)() += delta; + + //return libMesh::Point((xs_h - xs_n)/(2.0*delta), (ys_h - ys_n)/(2.0*delta), 0.); + Real dxs = (xs_h - xs_n)/(2.0*delta); + Real dys = (ys_h - ys_n)/(2.0*delta); +// Real dxs = (xs_2n - 8.*xs_n + 8.*xs_h - xs_2h)/(12.*delta); +// Real dys = (ys_2n - 8.*ys_n + 8.*ys_h - ys_2h)/(12.*delta); + return libMesh::Point(dxs, dys, 0.); +} + + +RealVectorX MAST::CrossSection::get_shear_coefficients(const libMesh::Point& p, const Real t) +{ + _update_warping_geometry(p, t); + RealVectorX kappa(3); + kappa << _wp.kappa_x, _wp.kappa_y, _wp.kappa_xy; + return kappa; +} + +// TODO: Implement analytical derivative instead of finite difference +RealVectorX MAST::CrossSection::get_shear_coefficients_derivative(MAST::FunctionBase& f, const libMesh::Point& p, const Real t) +{ + //Real delta = 1.0e-06; + const Real delta = 1.220703125e-04; // np.spacing(1)**0.25 + MAST::Parameter* param = dynamic_cast(&f); + + (*param)() += delta; + _update_warping_geometry(p, t); + Real kappa_x_h = _wp.kappa_x; + Real kappa_y_h = _wp.kappa_y; + Real kappa_xy_h = _wp.kappa_xy; + + (*param)() -= 2.0*delta; + _update_warping_geometry(p, t); + Real kappa_x_n = _wp.kappa_x; + Real kappa_y_n = _wp.kappa_y; + Real kappa_xy_n = _wp.kappa_xy; + + (*param)() += delta; + + Real dkappa_x = (kappa_x_h - kappa_x_n) / (2.0*delta); + Real dkappa_y = (kappa_y_h - kappa_y_n) / (2.0*delta); + Real dkappa_xy = (kappa_xy_h - kappa_xy_n) / (2.0*delta); + + RealVectorX dkappa(3); + dkappa << dkappa_x, dkappa_y, dkappa_xy; + + return dkappa; +} + + +Real MAST::CrossSection::get_warping_constant(const libMesh::Point& p, const Real t) +{ + _update_warping_geometry(p, t); + return _wp.gamma; +} + +// TODO: Implement analytical derivative instead of finite difference +Real MAST::CrossSection::get_warping_constant_derivative(MAST::FunctionBase& f, const libMesh::Point& p, const Real t) +{ + //Real delta = 1.0e-06; + const Real delta = 1.220703125e-04; // np.spacing(1)**0.25 + MAST::Parameter* param = dynamic_cast(&f); + + (*param)() += delta; + _update_warping_geometry(p, t); + Real gammah = _wp.gamma; + (*param)() -= 2.0*delta; + _update_warping_geometry(p, t); + Real gamman = _wp.gamma; + (*param)() += delta; + return (gammah - gamman)/(2.0*delta); +} + + +void MAST::CrossSection::_update_geometry(const libMesh::Point& p, const Real t) +{ + // Get the points defining the outter geometry from the mesh + std::vector geometry_points = _property.get_geom_points(p, t); + std::vector> hole_list = _property.get_holes_points(p, t); + + // Check if the geometry is the same as the last time it was calculated + if ((geometry_points == _geometry_points) and (hole_list == _hole_list)) + { + // Geometry did not change, no need to redo calculations. + //libMesh::out << "Geometry the same. SKIPPING update." << std::endl; + } + else + { + // Geometry did change, need to re-run calculations + _geometry_points = geometry_points; + _hole_list = hole_list; + _calculate_shoelace_geometric_properties(); + _build_model(p, t); + //libMesh::out << "Geometry is different. UPDATING." << std::endl; + } +} + + +void MAST::CrossSection::_update_warping_geometry(const libMesh::Point& p, const Real t) +{ + // Get the points defining the outter geometry from the mesh + std::vector geometry_points = _property.get_geom_points(p, t); + std::vector> hole_list = _property.get_holes_points(p, t); + + + // Check if the geometry is the same as the last time it was calculated + if ((geometry_points == _geometry_points) and (hole_list == _hole_list) and (_warping_calculated)) + { + // Geometry did not change, no need to redo calculations. + libMesh::out << "Geometry the same. SKIPPING warping update." << std::endl; + } + else + { + libMesh::out << "Geometry is different. UPDATING warping." << std::endl; + // Geometry did change, need to re-run calculations + _warping_calculated = false; + _geometry_points = geometry_points; + _hole_list = hole_list; + _calculate_shoelace_geometric_properties(); + _build_model(p, t); + _solve_warping(); + _wp = _assembly->calculate_warping_properties(*_F_warp, *_Omega, *_Psi, + *_Phi, _A, _Ixxc, _Iyyc, _Ixyc, + _Cx, _Cy); + _warping_calculated = true; + libMesh::out << "Done updating warping." << std::endl; + } +} + + +void MAST::CrossSection::_update_geometry(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t) +{ + // Get the points defining the outter geometry from the mesh + std::vector geometry_points = _property.get_geom_points(p, t); + std::vector> hole_list = _property.get_holes_points(p, t); + std::string sensitivity_parameter = f.name(); + + // Check if the geometry is the same as the last time it was calculated + if ((geometry_points == _geometry_points) and (hole_list == _hole_list) and (sensitivity_parameter == _sensitivity_parameter)) + { + // Geometry did not change, no need to redo calculations. + //libMesh::out << "Geometry the same. SKIPPING update." << std::endl; + } + else + { + // Geometry did change, need to re-run calculations + _geometry_points = geometry_points; + _hole_list = hole_list; + _sensitivity_parameter = sensitivity_parameter; + _calculate_shoelace_geometric_properties_sensitivities(f, p, t); + _build_model(p, t); + //libMesh::out << "Geometry is different. UPDATING." << std::endl; + } +} + + +void MAST::CrossSection::calculate_shoelace_geometric_properties() +{ + _calculate_shoelace_geometric_properties(); + + libMesh::out << "\nShoelace Geometric Properties" << std::endl; + libMesh::out << "xc = " << _Cx << std::endl; + libMesh::out << "yc = " << _Cy << std::endl; + libMesh::out << "A = " << _A << std::endl; + libMesh::out << "Ay = " << _Qy << std::endl; + libMesh::out << "Az = " << _Qx << std::endl; + libMesh::out << "Iyy = " << _Iyy << std::endl; + libMesh::out << "Izz = " << _Ixx << std::endl; + libMesh::out << "Iyz = " << _Ixy << std::endl; + libMesh::out << "Ip = " << (_Ixx+_Iyy) << std::endl; +} + + +void MAST::CrossSection::_calculate_shoelace_geometric_properties() +{ + // Shoelace formula + Real xi, yi, xi1, yi1, yin1, Ibase; + + Real A = 0.0; + Real Cx = 0.0; + Real Cy = 0.0; + Real Ixx = 0.0; + Real Iyy = 0.0; + Real Ixy = 0.0; + Real y_max = -1e16; + Real y_min = 1e16; + Real x_max = -1e16; + Real x_min = 1e16; + + // Loop through points describing outer geometry boundary + const uint n = _geometry_points.size(); + for (uint i=0; i geometry_point_sensitivity = _property.get_geom_points_derivative(f, p, t); + + // Loop through points describing outer geometry boundary + const uint n = _geometry_points.size(); + for (uint i=0; i> hole_derivatives_list = _property.get_holes_points_derivative(f, p, t); + + // Loop through holes in the geometry + for (uint j=0; j<_hole_list.size(); j++) + { + const std::vector hole_points = _hole_list[j]; + const std::vector hole_point_derivative = hole_derivatives_list[j]; + // Loop through points describing the hole + const uint n = hole_points.size(); + for (uint i=0; iadd_system("warping")); + + // Create a finite element type for the system. Here, we use first order Lagrangian-type finite elements. + _fetype.reset(new libMesh::FEType(_mesh->elem_ptr(0)->default_order(), libMesh::LAGRANGE)); + + _warping_system.reset(new MAST::WarpingSystemInitialization(*_system, _system->name(), *_fetype)); + + _discipline.reset(new MAST::PhysicsDisciplineBase(*_equation_systems)); + + _equation_systems->init(); + + _parameters["th"].reset(new MAST::Parameter("th", 1.0)); + _parameters["zero"].reset(new MAST::Parameter("zero", 0.0)); + + // Create field functions to dsitribute these constant parameters throughout the model + _field_functions["h"].reset(new MAST::ConstantFieldFunction("h", *_parameters["th"])); + _field_functions["off"].reset(new MAST::ConstantFieldFunction("off", *_parameters["zero"])); + + _section.reset(new MAST::Solid2DSectionElementPropertyCard); + + _section->add(*_field_functions["h"]); + _section->add(*_field_functions["off"]); + + // Set the materials for the section + _section->set_material(_property.get_material()); + _section->set_strain(MAST::LINEAR_STRAIN); + _section->set_bending_model(MAST::NO_BENDING); + _section->set_warping_only(true); + + // Set the section properties for subdoamin 0 in the discipline + _discipline->set_property_for_subdomain(0, *_section); + + _assembly.reset(new MAST::WarpingAssembly); + _assembly->set_force_jacobian_symmetry(true); + _assembly->set_discipline_and_system(*_discipline, *_warping_system); + + _elem_ops.reset(new MAST::StructuralNonlinearAssemblyElemOperations); + _elem_ops->set_discipline_and_system(*_discipline, *_warping_system); + + _nonlinear_system = &(_assembly->system()); + + // Get the geometric properties which can be explicitly calculated + _gp = _assembly->calculate_geometric_properties(); + + // Shift the mesh so that the global axis lies on the centroid. + libMesh::Point centroid(_gp.xc, _gp.yc, 0.0); + for (auto& node_ptr : _mesh->node_ptr_range()) + { + node_ptr->subtract(centroid); + } + + // Zero the solution before solving + _nonlinear_system->solution->zero(); +} + + +void MAST::CrossSection::_solve_warping() +{ + // Get the warping, shear_x, and shear_y loads + _F_warp = _nonlinear_system->solution->zero_clone(); + _F_shearx = _nonlinear_system->solution->zero_clone(); + _F_sheary = _nonlinear_system->solution->zero_clone(); + _assembly->get_loads(*_F_warp, *_F_shearx, *_F_sheary, _gp.xc, _gp.yc, + _gp.Ixxc, _gp.Iyyc, _gp.Ixyc); + + // Configure the nonlinear solver + libMesh::PetscNonlinearSolver* petsc_nonlinear_solver = dynamic_cast*>(_nonlinear_system->nonlinear_solver.get()); + libmesh_assert(petsc_nonlinear_solver); + PetscNonlinearSolverConfiguration petsc_nonlinear_solver_config(*petsc_nonlinear_solver); + petsc_nonlinear_solver->set_solver_configuration(petsc_nonlinear_solver_config); + + // Solve the system for the warping function + _nonlinear_system->solve(*_elem_ops, *_assembly); + + /** + * Get the linear solver object + * See sensitivity_solve() method in libMesh's implicit_system.C source code + * for an example of getting the linear solver and using it to solve + * additional right hand sides. + */ + _nonlinear_system->assemble_before_solve = false; + libMesh::LinearSolver* linear_solver = _nonlinear_system->get_linear_solver(); + + /** + * Configure the Linear Solver Object + * See libMesh's systems_of_equations_ex6.C example sorce code as reference. + */ + libMesh::PetscLinearSolver* petsc_linear_solver = dynamic_cast*>(linear_solver); + libmesh_assert(petsc_linear_solver); + PetscLinearSolverConfiguration petsc_solver_config(*petsc_linear_solver); + petsc_linear_solver->set_solver_configuration(petsc_solver_config); + + _Omega = _nonlinear_system->solution->clone(); +// _Omega = _nonlinear_system->solution->zero_clone(); +// linear_solver->solve(*(_nonlinear_system->matrix), *_Omega, *_F_warp, 1e-15, 100000); + + // solve the linear system for the shear_x function + _Psi = _nonlinear_system->solution->zero_clone(); + linear_solver->solve(*(_nonlinear_system->matrix), *_Psi, *_F_shearx, 1e-15, 100000); + + + // solve the linear system for the shear_y function + _Phi = _nonlinear_system->solution->zero_clone(); + linear_solver->solve(*(_nonlinear_system->matrix), *_Phi, *_F_sheary, 1e-15, 100000); + + + _nonlinear_system->release_linear_solver(linear_solver); // To avoid memory leak +} diff --git a/src/property_cards/cross_section_property_pilkey.h b/src/property_cards/cross_section_property_pilkey.h new file mode 100644 index 00000000..5132d76e --- /dev/null +++ b/src/property_cards/cross_section_property_pilkey.h @@ -0,0 +1,164 @@ +#ifndef __mast__cross_section__ +#define __mast__cross_section__ + +// libMesh Includes +#include "libmesh/libmesh.h" +#include "libmesh/replicated_mesh.h" +#include "libmesh/mesh_generation.h" +#include "libmesh/point.h" +#include "libmesh/edge_edge2.h" +#include "libmesh/equation_systems.h" +#include "libmesh/exodusII_io.h" +#include "libmesh/mesh_triangle_interface.h" +#include "libmesh/mesh_generation.h" +#include "libmesh/linear_solver.h" + +// // MAST includes +#include "base/constant_field_function.h" +#include "property_cards/solid_1d_section_element_property_card.h" +#include "base/warping_assembly.h" +#include "elasticity/warping_system_initialization.h" +#include "elasticity/structural_nonlinear_assembly.h" +#include "base/parameter.h" +#include "base/constant_field_function.h" +#include "property_cards/solid_2d_section_element_property_card.h" +#include "base/physics_discipline_base.h" + + + +namespace MAST +{ + +class CrossSection +{ + public: + CrossSection(const libMesh::LibMeshInit& init, + const uint target_n_elems, + MAST::Solid1DSectionElementPropertyCard& property, + const libMesh::ElemType element_type=libMesh::TRI6); + + /*! + * virtual destructor + */ + virtual ~CrossSection() { } + + void calculate_shoelace_geometric_properties(); + void calculate_geometric_properties(); + void calculate_warping_properties(); + + Real get_area(const libMesh::Point& p, const Real t); + Real get_area_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t); + + libMesh::Point get_centroid(const libMesh::Point& p, const Real t); + libMesh::Point get_centroid_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t); + + Real get_first_area_moment_z(const libMesh::Point& p, const Real t); + Real get_first_area_moment_z_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t); + + Real get_first_area_moment_y(const libMesh::Point& p, const Real t); + Real get_first_area_moment_y_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t); + + RealVectorX get_second_area_moments(const libMesh::Point& p, const Real t); + RealVectorX get_second_area_moments_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t); + + Real get_second_polar_area_moment(const libMesh::Point& p, const Real t); + Real get_second_polar_area_moment_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t); + + Real get_torsion_constant(const libMesh::Point& p, const Real t); + Real get_torsion_constant_derivative(MAST::FunctionBase& f, const libMesh::Point& p, const Real t); + + libMesh::Point get_shear_center(const libMesh::Point& p, const Real t); + libMesh::Point get_shear_center_derivative(MAST::FunctionBase& f, const libMesh::Point& p, const Real t); + + RealVectorX get_shear_coefficients(const libMesh::Point& p, const Real t); + RealVectorX get_shear_coefficients_derivative(MAST::FunctionBase& f, const libMesh::Point& p, const Real t); + + Real get_warping_constant(const libMesh::Point& p, const Real t); + Real get_warping_constant_derivative(MAST::FunctionBase& f, const libMesh::Point& p, const Real t); + + RealVectorX get_second_area_moments_about_centroid(const libMesh::Point& p, const Real t); + RealVectorX get_radii_of_gyration(const libMesh::Point& p, const Real t); + RealVectorX get_elastic_section_modulii(const libMesh::Point& p, const Real t); + + + protected: + + /*! + * METHODS + */ + + void _calculate_shoelace_geometric_properties(); + + void _calculate_shoelace_geometric_properties_sensitivities(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t); + + bool _shoelace_calculated = false; + + void _configure_linear_solver(); + + void _mesh_cross_section(const libMesh::Point& p, const Real t); + + void _build_model(const libMesh::Point& p, const Real t); + + void _solve_warping(); + + void _update_geometry(const libMesh::Point& p, const Real t); + + void _update_geometry(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t); + + void _update_warping_geometry(const libMesh::Point& p, const Real t); + + + /*! + * VARIABLES + */ + const libMesh::LibMeshInit& _init; + const uint _target_n_elems; + const libMesh::ElemType _element_type; + + std::unique_ptr _mesh; + std::unique_ptr _equation_systems; + std::unique_ptr _fetype; + MAST::NonlinearSystem* _system; + std::unique_ptr _discipline; + std::unique_ptr _warping_system; + std::unique_ptr _assembly; + std::unique_ptr _elem_ops; + MAST::NonlinearSystem* _nonlinear_system; + + // Define geometric properties as MAST Parmeters + std::map> _parameters; + std::map> _field_functions; + + // Create the section property card and attach all geometric property values. + std::unique_ptr _section; + + MAST::Solid1DSectionElementPropertyCard& _property; + + Real _A, _Cx, _Cy, _Qx, _Qy, _Ixx, _Iyy, _Ixy, _rx, _ry, _Ixxc, _Iyyc, + _Ixyc, _Z_xx_p, _Z_xx_n, _Z_yy_p, _Z_yy_n; + + Real _dA, _dCx, _dCy, _dQx, _dQy, _dIxx, _dIyy, _dIxy, _drx, _dry, + _dIxxc, _dIyyc, _dIxyc, _dZ_xx_p, _dZ_xx_n, _dZ_yy_p, _dZ_yy_n; + + std::unique_ptr> _F_warp; + std::unique_ptr> _F_shearx; + std::unique_ptr> _F_sheary; + + std::unique_ptr> _Omega; + std::unique_ptr> _Psi; + std::unique_ptr> _Phi; + + std::vector _geometry_points; + std::vector> _hole_list; + std::string _sensitivity_parameter; + // std::vector _stress_points; + + bool _warping_calculated = false; + + geometric_properties _gp; + warping_properties _wp; +}; + +} + +#endif // __mast__cross_section__ diff --git a/src/property_cards/solid_1d_1parameter_section_element_property_card.cpp b/src/property_cards/solid_1d_1parameter_section_element_property_card.cpp new file mode 100644 index 00000000..cbdfbf65 --- /dev/null +++ b/src/property_cards/solid_1d_1parameter_section_element_property_card.cpp @@ -0,0 +1,285 @@ +/* + * MAST: Multidisciplinary-design Adaptation and Sensitivity Toolkit + * Copyright (C) 2013-2019 Manav Bhatia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +// MAST includes +#include "property_cards/solid_1d_1parameter_section_element_property_card.h" +//#include "property_cards/material_property_card_base.h" +//#include "base/field_function_base.h" +//#include "base/elem_base.h" + + +MAST::Solid1D1ParameterSectionProperty::Area::Area( + const std::function func, + const std::function dfunc, + const MAST::FieldFunction& DIM1): + MAST::FieldFunction("Area"), + _func(func), _dfunc(dfunc), _DIM1(DIM1) + { + _functions.insert(&DIM1); + } + +void MAST::Solid1D1ParameterSectionProperty::Area::operator() + (const libMesh::Point& p, const Real t, Real& m) const { + Real DIM1; + _DIM1(p, t, DIM1); + _func(DIM1, m); + } + +void MAST::Solid1D1ParameterSectionProperty::Area::derivative( + const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, + Real& m) const { + Real DIM1, dDIM1; + _DIM1(p, t, DIM1); _DIM1.derivative( f, p, t, dDIM1); + _dfunc(DIM1, dDIM1, m); + } + + +MAST::Solid1D1ParameterSectionProperty::TorsionalConstant:: +TorsionalConstant(const std::function func, + const std::function dfunc, + const MAST::FieldFunction& DIM1): + MAST::FieldFunction("TorsionalConstant"), + _func(func), _dfunc(dfunc), _DIM1(DIM1){ + _functions.insert(&DIM1); +} + + +void MAST::Solid1D1ParameterSectionProperty::TorsionalConstant:: +operator() (const libMesh::Point& p, const Real t, Real& m) const { + Real DIM1; + _DIM1(p, t, DIM1); + _func(DIM1, m); +} + + +void MAST::Solid1D1ParameterSectionProperty::TorsionalConstant:: +derivative (MAST::FunctionBase& f, const libMesh::Point& p, const Real t, +Real& m) { + Real DIM1, dDIM1; + _DIM1(p, t, DIM1); _DIM1.derivative( f, p, t, dDIM1); + _dfunc(DIM1, dDIM1, m); +} + + + +MAST::Solid1D1ParameterSectionProperty::PolarInertia:: +PolarInertia(const std::function func, + const std::function dfunc, + const std::function Afunc, + const std::function dAfunc, + const MAST::FieldFunction& DIM1, + const MAST::FieldFunction& hy_offset, + const MAST::FieldFunction& hz_offset): + MAST::FieldFunction("PolarInertia"), + _func(func), + _dfunc(dfunc), + _Afunc(Afunc), + _dAfunc(dAfunc), + _DIM1(DIM1), + _hy_offset(hy_offset), + _hz_offset(hz_offset) { + _functions.insert(&DIM1); + _functions.insert(&hy_offset); + _functions.insert(&hz_offset); + } + +void MAST::Solid1D1ParameterSectionProperty::PolarInertia:: +operator() (const libMesh::Point& p, + const Real t, + Real& m) const { + Real DIM1, offy, offz, A; + _DIM1(p, t, DIM1); + _hy_offset(p, t, offy); + _hz_offset(p, t, offz); + + _Afunc(DIM1, A); + + _func(DIM1, m); + m += A*pow(offy,2) + A*pow(offz,2); // Account for offsets + } + + +void MAST::Solid1D1ParameterSectionProperty::PolarInertia:: +derivative ( const MAST::FunctionBase& f, + const libMesh::Point& p, + const Real t, + Real& m) const { + Real DIM1, dDIM1, offy, offz, doffy, doffz, A, dA; + _DIM1 (p, t, DIM1); _DIM1.derivative( f, p, t, dDIM1); + _hy_offset (p, t, offy); _hy_offset.derivative( f, p, t, doffy); + _hz_offset (p, t, offz); _hz_offset.derivative( f, p, t, doffz); + + + _Afunc(DIM1, A); + _dAfunc(DIM1, dDIM1, dA); + + _dfunc(DIM1, dDIM1, m); + m += dA*pow(offy,2) + 2.*A*offy*doffy + dA*pow(offz,2) + 2.*A*offz*doffz; + } + + +MAST::Solid1D1ParameterSectionProperty::AreaYMoment:: +AreaYMoment(const std::function Afunc, + const std::function dAfunc, + const MAST::FieldFunction& DIM1, + const MAST::FieldFunction& hz_offset): + MAST::FieldFunction("AreaYMoment"), + _Afunc(Afunc), + _dAfunc(dAfunc), + _DIM1(DIM1), + _hz_offset(hz_offset) { + _functions.insert(&DIM1); + _functions.insert(&hz_offset); + } + +void MAST::Solid1D1ParameterSectionProperty::AreaYMoment:: +operator() (const libMesh::Point& p, + const Real t, + Real& m) const { + Real DIM1, off, A; + _DIM1(p, t, DIM1); + _hz_offset(p, t, off); + + _Afunc(DIM1, A); + m = A*off; + } + +void MAST::Solid1D1ParameterSectionProperty::AreaYMoment:: +derivative ( const MAST::FunctionBase& f, + const libMesh::Point& p, + const Real t, + Real& m) const { + Real DIM1, off, dDIM1, doff, A, dA; + _DIM1 (p, t, DIM1); _DIM1.derivative( f, p, t, dDIM1); + _hz_offset (p, t, off); _hz_offset.derivative( f, p, t, doff); + + _Afunc(DIM1, A); + _dAfunc(DIM1, dDIM1, dA); + + m = dA*off + A*doff; + } + + +MAST::Solid1D1ParameterSectionProperty::AreaZMoment:: +AreaZMoment(const std::function Afunc, + const std::function dAfunc, + const MAST::FieldFunction& DIM1, + const MAST::FieldFunction& hy_offset): +MAST::FieldFunction("AreaZMoment"), +_Afunc(Afunc), +_dAfunc(dAfunc), +_DIM1(DIM1), +_hy_offset(hy_offset) { + _functions.insert(&DIM1); + _functions.insert(&hy_offset); +} + +void MAST::Solid1D1ParameterSectionProperty::AreaZMoment:: +operator() (const libMesh::Point& p, + const Real t, + Real& m) const { + Real DIM1, off, A; + _DIM1(p, t, DIM1); + _hy_offset(p, t, off); + + _Afunc(DIM1, A); + m = A*off; + } + +void MAST::Solid1D1ParameterSectionProperty::AreaZMoment:: +derivative ( const MAST::FunctionBase& f, + const libMesh::Point& p, + const Real t, + Real& m) const { + Real DIM1, off, dDIM1, doff, A, dA; + _DIM1(p, t, DIM1); _DIM1.derivative( f, p, t, dDIM1); + _hy_offset(p, t, off); _hy_offset.derivative( f, p, t, doff); + + _Afunc(DIM1, A); + _dAfunc(DIM1, dDIM1, dA); + + m = dA*off + A*doff; + } + +MAST::Solid1D1ParameterSectionProperty::AreaInertiaMatrix:: +AreaInertiaMatrix(const std::function Izfunc, + const std::function dIzfunc, + const std::function Iyfunc, + const std::function dIyfunc, + const std::function Afunc, + const std::function dAfunc, + const MAST::FieldFunction& DIM1, + const MAST::FieldFunction& hy_offset, + const MAST::FieldFunction& hz_offset): + MAST::FieldFunction("AreaInertiaMatrix"), + _Izfunc(Izfunc), + _dIzfunc(dIzfunc), + _Iyfunc(Iyfunc), + _dIyfunc(dIyfunc), + _Afunc(Afunc), + _dAfunc(dAfunc), + _DIM1(DIM1), + _hy_offset(hy_offset), + _hz_offset(hz_offset) { + _functions.insert(&DIM1); + _functions.insert(&hy_offset); + _functions.insert(&hz_offset); + } + +void MAST::Solid1D1ParameterSectionProperty::AreaInertiaMatrix:: +operator() (const libMesh::Point& p, + const Real t, + RealMatrixX& m) const { + Real DIM1, offy, offz, A; + m = RealMatrixX::Zero(2,2); + _DIM1(p, t, DIM1); + _hy_offset(p, t, offy); + _hz_offset(p, t, offz); + + _Afunc(DIM1, A); + _Izfunc(DIM1, m(0,0)); + _Iyfunc(DIM1, m(1,1)); + + m(0,0) += A*pow(offy,2) ; // Account for offset + m(0,1) = A*offy*offz; + m(1,0) = m(0,1); + m(1,1) += A*pow(offz,2) ; // Account for offset + } + +void MAST::Solid1D1ParameterSectionProperty::AreaInertiaMatrix:: +derivative ( const MAST::FunctionBase& f, + const libMesh::Point& p, + const Real t, + RealMatrixX& m) const { + Real DIM1, offy, offz, A, dDIM1, doffy, doffz, dA; + m = RealMatrixX::Zero(2,2); + _DIM1(p, t, DIM1); _DIM1.derivative( f, p, t, dDIM1); + _hy_offset(p, t, offy); _hy_offset.derivative( f, p, t, doffy); + _hz_offset(p, t, offz); _hz_offset.derivative( f, p, t, doffz); + + _Afunc(DIM1, A); + _dAfunc(DIM1, dDIM1, dA); + _dIzfunc(DIM1, dDIM1, m(0,0)); + _dIyfunc(DIM1, dDIM1, m(1,1)); + + m(0,0) += dA*pow(offy,2) + A*2.*offy*doffy; + m(0,1) = dA*offy*offz + A*doffy*offz + A*offy*doffz; + m(1,0) = m(0,1); + m(1,1) += dA*pow(offz,2) + A*2.*offz*doffz; + } diff --git a/src/property_cards/solid_1d_1parameter_section_element_property_card.h b/src/property_cards/solid_1d_1parameter_section_element_property_card.h new file mode 100644 index 00000000..844c1d1f --- /dev/null +++ b/src/property_cards/solid_1d_1parameter_section_element_property_card.h @@ -0,0 +1,229 @@ +/* + * MAST: Multidisciplinary-design Adaptation and Sensitivity Toolkit + * Copyright (C) 2013-2019 Manav Bhatia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __mast__solid_1d_1parameter_section_element_property_card__ +#define __mast__solid_1d_1parameter_section_element_property_card__ + + +// MAST includes +#include "property_cards/solid_1d_section_element_property_card.h" +#include "property_cards/solid_1d_nparameter_section_element_property_card.h" +#include "base/field_function_base.h" + + +namespace MAST { + namespace Solid1D1ParameterSectionProperty { + + class Area: public MAST::FieldFunction { + public: + Area(const std::function func, + const std::function dfunc, + const MAST::FieldFunction& DIM1); + + virtual ~Area() { } + + virtual void operator() (const libMesh::Point& p, + const Real t, + Real& m) const; + + virtual void derivative (const MAST::FunctionBase& f, + const libMesh::Point& p, + const Real t, + Real& m) const; + + protected: + const std::function _func; + const std::function _dfunc; + const MAST::FieldFunction &_DIM1; + }; + + + class TorsionalConstant: public MAST::FieldFunction { + public: + TorsionalConstant(const std::function func, + const std::function dfunc, + const MAST::FieldFunction& DIM1); + + virtual ~TorsionalConstant() { } + + virtual void operator() (const libMesh::Point& p, + const Real t, + Real& m) const; + + virtual void derivative (MAST::FunctionBase& f, + const libMesh::Point& p, + const Real t, + Real& m); + + protected: + + const std::function _func; + const std::function _dfunc; + const MAST::FieldFunction &_DIM1; + }; + + + class PolarInertia: public MAST::FieldFunction { + public: + PolarInertia(const std::function func, + const std::function dfunc, + const std::function Afunc, + const std::function dAfunc, + const MAST::FieldFunction& DIM1, + const MAST::FieldFunction& hy_offset, + const MAST::FieldFunction& hz_offset); + + virtual ~PolarInertia() { } + + virtual void operator() (const libMesh::Point& p, + const Real t, + Real& m) const; + + virtual void derivative ( const MAST::FunctionBase& f, + const libMesh::Point& p, + const Real t, + Real& m) const; + + protected: + const std::function _func, _Afunc; + const std::function _dfunc, _dAfunc; + const MAST::FieldFunction &_DIM1, &_hy_offset, &_hz_offset; + }; + + + /*! + * calculates the area moment about the Y-axis due to an offset + * along the Z-axis + */ + class AreaYMoment: public MAST::FieldFunction { + public: + AreaYMoment(const std::function Afunc, + const std::function dAfunc, + const MAST::FieldFunction& DIM1, + const MAST::FieldFunction& hz_offset); + + + virtual ~AreaYMoment() { } + + virtual void operator() (const libMesh::Point& p, + const Real t, + Real& m) const; + + + virtual void derivative (const MAST::FunctionBase& f, + const libMesh::Point& p, + const Real t, + Real& m) const; + + protected: + const std::function _Afunc; + const std::function _dAfunc; + const MAST::FieldFunction &_DIM1, &_hz_offset; + }; + + + /*! + * calculates the area moment about the Z-axis due to an offset + * along the Y-axis + */ + class AreaZMoment: public MAST::FieldFunction { + public: + AreaZMoment(const std::function Afunc, + const std::function dAfunc, + const MAST::FieldFunction& DIM1, + const MAST::FieldFunction& hy_offset); + + virtual ~AreaZMoment() { } + + virtual void operator() (const libMesh::Point& p, + const Real t, + Real& m) const; + + + virtual void derivative (const MAST::FunctionBase& f, + const libMesh::Point& p, + const Real t, + Real& m) const; + + protected: + const std::function _Afunc; + const std::function _dAfunc; + const MAST::FieldFunction &_DIM1, &_hy_offset; + }; + + + /*! + * calculates the 2x2 matrix of area inertia for the section with + * individual entries as + * + * 0 x 0 = int_omega (y+yoff)^2 dy dz + * 0 x 1 = int_omega (y+yoff) (z+zoff) dy dz + * 1 x 0 = int_omega (y+yoff) (z+zoff) dy dz + * 1 x 1 = int_omega (z+zoff)^2 dy dz + */ + class AreaInertiaMatrix: public MAST::FieldFunction { + public: + AreaInertiaMatrix(const std::function Izfunc, + const std::function dIzfunc, + const std::function Iyfunc, + const std::function dIyfunc, + const std::function Afunc, + const std::function dAfunc, + const MAST::FieldFunction& DIM1, + const MAST::FieldFunction& hy_offset, + const MAST::FieldFunction& hz_offset); + + virtual ~AreaInertiaMatrix() { } + + virtual void operator() (const libMesh::Point& p, + const Real t, + RealMatrixX& m) const; + + + virtual void derivative (const MAST::FunctionBase& f, + const libMesh::Point& p, + const Real t, + RealMatrixX& m) const; + + protected: + const std::function _Izfunc, _Iyfunc, _Afunc; + const std::function _dIzfunc, _dIyfunc, _dAfunc; + const MAST::FieldFunction &_DIM1, &_hy_offset, &_hz_offset; + }; + } +} + + +namespace MAST { + + class Solid1D1ParameterSectionElementPropertyCard : public MAST::Solid1DSectionElementPropertyCard + { + public: + Solid1D1ParameterSectionElementPropertyCard(): + MAST::Solid1DSectionElementPropertyCard() {} + + /*! + * virtual destructor + */ + virtual ~Solid1D1ParameterSectionElementPropertyCard() { } + }; +} + + +#endif // __mast__solid_1d_1parameter_section_element_property_card__ diff --git a/src/property_cards/solid_1d_nparameter_section_element_property_card.cpp b/src/property_cards/solid_1d_nparameter_section_element_property_card.cpp new file mode 100644 index 00000000..757c68c0 --- /dev/null +++ b/src/property_cards/solid_1d_nparameter_section_element_property_card.cpp @@ -0,0 +1,215 @@ +/* + * MAST: Multidisciplinary-design Adaptation and Sensitivity Toolkit + * Copyright (C) 2013-2019 Manav Bhatia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +// MAST includes +#include "property_cards/solid_1d_nparameter_section_element_property_card.h" + +MAST::Solid1DnParameterSectionProperty::Area:: +Area(MAST::CrossSection& cross_section): +MAST::FieldFunction("Area"), +_cross_section(cross_section) +{ +} + +void MAST::Solid1DnParameterSectionProperty::Area:: +operator() (const libMesh::Point& p, const Real t, Real& m) const +{ + m = _cross_section.get_area(p, t); +} + +void MAST::Solid1DnParameterSectionProperty::Area:: +derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, + Real& m) const +{ + m = _cross_section.get_area_derivative(f, p, t); +} + + +MAST::Solid1DnParameterSectionProperty::AreaYMoment:: +AreaYMoment(MAST::CrossSection& cross_section): +MAST::FieldFunction("AreaYMoment"), +_cross_section(cross_section) +{ +} + +void MAST::Solid1DnParameterSectionProperty::AreaYMoment:: +operator() (const libMesh::Point& p, const Real t, Real& m) const +{ + m = _cross_section.get_first_area_moment_y(p, t); +} + +void MAST::Solid1DnParameterSectionProperty::AreaYMoment:: +derivative (const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, + Real& m) const +{ + m = _cross_section.get_first_area_moment_y_derivative(f, p, t); +} + + + +MAST::Solid1DnParameterSectionProperty::AreaZMoment:: +AreaZMoment(MAST::CrossSection& cross_section): +MAST::FieldFunction("AreaZMoment"), +_cross_section(cross_section) +{ +} + +void MAST::Solid1DnParameterSectionProperty::AreaZMoment:: +operator() (const libMesh::Point& p, const Real t, Real& m) const +{ + m = _cross_section.get_first_area_moment_z(p, t); +} + +void MAST::Solid1DnParameterSectionProperty::AreaZMoment:: +derivative (const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, + Real& m) const +{ + m = _cross_section.get_first_area_moment_z_derivative(f, p, t); +} + + + +MAST::Solid1DnParameterSectionProperty::AreaInertiaMatrix:: +AreaInertiaMatrix(MAST::CrossSection& cross_section): +MAST::FieldFunction("AreaInertiaMatrix"), +_cross_section(cross_section) +{ +} + +void MAST::Solid1DnParameterSectionProperty::AreaInertiaMatrix:: +operator() (const libMesh::Point& p, const Real t, RealMatrixX& m) const +{ + m = RealMatrixX::Zero(2,2); + + RealVectorX I = _cross_section.get_second_area_moments(p, t); + m(0,0) = I(0); + m(1,1) = I(1); + m(0,1) = m(1,0) = I(2); +} + +void MAST::Solid1DnParameterSectionProperty::AreaInertiaMatrix:: +derivative (const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, + RealMatrixX& m) const +{ + m = RealMatrixX::Zero(2,2); + + RealVectorX dI = _cross_section.get_second_area_moments_derivative(f, p, t); + + m(0,0) = dI(0); + m(1,1) = dI(1); + m(0,1) = m(1,0) = dI(2); +} + + +MAST::Solid1DnParameterSectionProperty::PolarInertia:: +PolarInertia(MAST::CrossSection& cross_section): +MAST::FieldFunction("PolarInertia"), +_cross_section(cross_section) +{ +} + +void MAST::Solid1DnParameterSectionProperty::PolarInertia:: +operator() (const libMesh::Point& p,const Real t, Real& m) const +{ + m = _cross_section.get_second_polar_area_moment(p, t); +} + + +void MAST::Solid1DnParameterSectionProperty::PolarInertia:: +derivative (const MAST::FunctionBase& f, const libMesh::Point& p, + const Real t, Real& m) const +{ + m = _cross_section.get_second_polar_area_moment_derivative(f, p, t); +} + + +MAST::Solid1DnParameterSectionProperty::TorsionalConstant:: +TorsionalConstant(MAST::CrossSection& cross_section): +MAST::FieldFunction("TorsionalConstant"), +_cross_section(cross_section) +{ +} + +void MAST::Solid1DnParameterSectionProperty::TorsionalConstant:: +operator() (const libMesh::Point& p, const Real t, Real& m) const +{ + m = _cross_section.get_torsion_constant(p, t); +} + +void MAST::Solid1DnParameterSectionProperty::TorsionalConstant:: +derivative (MAST::FunctionBase& f, const libMesh::Point& p, const Real t, +Real& m) +{ + m = _cross_section.get_torsion_constant_derivative(f, p, t); +} + + +MAST::Solid1DnParameterSectionProperty::WarpingConstant:: +WarpingConstant(MAST::CrossSection& cross_section): +MAST::FieldFunction("WarpingConstant"), +_cross_section(cross_section) +{ +} + + +void MAST::Solid1DnParameterSectionProperty::WarpingConstant:: +operator() (const libMesh::Point& p, const Real t, Real& m) const +{ + m = _cross_section.get_warping_constant(p, t); +} + + +void MAST::Solid1DnParameterSectionProperty::WarpingConstant:: +derivative (MAST::FunctionBase& f, const libMesh::Point& p, const Real t, +Real& m) +{ + m = _cross_section.get_warping_constant_derivative(f, p, t); +} + + +MAST::Solid1DnParameterSectionProperty::ShearCoefficientMatrix:: +ShearCoefficientMatrix(MAST::CrossSection& cross_section): +MAST::FieldFunction("ShearCoefficientMatrix"), +_cross_section(cross_section) +{ +} + +void MAST::Solid1DnParameterSectionProperty::ShearCoefficientMatrix:: +operator() (const libMesh::Point& p, const Real t, RealMatrixX& m) const +{ + m = RealMatrixX::Zero(2,2); + + RealVectorX kappa = _cross_section.get_shear_coefficients(p, t); + m(0,0) = kappa(0); + m(1,1) = kappa(1); + m(0,1) = m(1,0) = kappa(2); +} + +void MAST::Solid1DnParameterSectionProperty::ShearCoefficientMatrix:: +derivative (MAST::FunctionBase& f, const libMesh::Point& p, const Real t, + RealMatrixX& m) +{ + m = RealMatrixX::Zero(2,2); + + RealVectorX dkappa = _cross_section.get_shear_coefficients_derivative(f, p, t); + + m(0,0) = dkappa(0); + m(1,1) = dkappa(1); + m(0,1) = m(1,0) = dkappa(2); +} diff --git a/src/property_cards/solid_1d_nparameter_section_element_property_card.h b/src/property_cards/solid_1d_nparameter_section_element_property_card.h new file mode 100644 index 00000000..1a48caf7 --- /dev/null +++ b/src/property_cards/solid_1d_nparameter_section_element_property_card.h @@ -0,0 +1,237 @@ +/* + * MAST: Multidisciplinary-design Adaptation and Sensitivity Toolkit + * Copyright (C) 2013-2019 Manav Bhatia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#ifndef __mast__solid_1d_nparameter_section_element_property_card__ +#define __mast__solid_1d_nparameter_section_element_property_card__ + + +// MAST includes +#include "property_cards/solid_1d_section_element_property_card.h" +#include "base/field_function_base.h" +#include "property_cards/cross_section_property_pilkey.h" + + +namespace MAST { + namespace Solid1DnParameterSectionProperty { + + class Area: public MAST::FieldFunction + { + public: + Area(MAST::CrossSection& cross_section); + + virtual ~Area() { } + + virtual void operator() (const libMesh::Point& p, + const Real t, + Real& m) const; + + virtual void derivative (const MAST::FunctionBase& f, + const libMesh::Point& p, + const Real t, + Real& m) const; + + protected: + MAST::CrossSection& _cross_section; + }; + + + /*! + * calculates the area moment about the Y-axis due to an offset + * along the Z-axis + */ + class AreaYMoment: public MAST::FieldFunction + { + public: + AreaYMoment(MAST::CrossSection& cross_section); + + + virtual ~AreaYMoment() { } + + virtual void operator() (const libMesh::Point& p, + const Real t, + Real& m) const; + + + virtual void derivative (const MAST::FunctionBase& f, + const libMesh::Point& p, + const Real t, + Real& m) const; + + protected: + MAST::CrossSection& _cross_section; + }; + + + /*! + * calculates the area moment about the Z-axis due to an offset + * along the Y-axis + */ + class AreaZMoment: public MAST::FieldFunction + { + public: + AreaZMoment(MAST::CrossSection& cross_section); + + virtual ~AreaZMoment() { } + + virtual void operator() (const libMesh::Point& p, + const Real t, + Real& m) const; + + + virtual void derivative (const MAST::FunctionBase& f, + const libMesh::Point& p, + const Real t, + Real& m) const; + + protected: + MAST::CrossSection& _cross_section; + }; + + + /*! + * calculates the 2x2 matrix of area inertia for the section + */ + class AreaInertiaMatrix: public MAST::FieldFunction + { + public: + AreaInertiaMatrix(MAST::CrossSection& cross_section); + + virtual ~AreaInertiaMatrix() { } + + virtual void operator() (const libMesh::Point& p, + const Real t, + RealMatrixX& m) const; + + + virtual void derivative (const MAST::FunctionBase& f, + const libMesh::Point& p, + const Real t, + RealMatrixX& m) const; + + protected: + MAST::CrossSection& _cross_section; + }; + + + class PolarInertia: public MAST::FieldFunction + { + public: + PolarInertia(MAST::CrossSection& cross_section); + + virtual ~PolarInertia() { } + + virtual void operator() (const libMesh::Point& p, + const Real t, + Real& m) const; + + virtual void derivative (const MAST::FunctionBase& f, + const libMesh::Point& p, + const Real t, + Real& m) const; + + protected: + MAST::CrossSection& _cross_section; + }; + + + class TorsionalConstant: public MAST::FieldFunction + { + public: + TorsionalConstant(MAST::CrossSection& cross_section); + + virtual ~TorsionalConstant() { } + + virtual void operator() (const libMesh::Point& p, + const Real t, + Real& m) const; + + virtual void derivative (MAST::FunctionBase& f, + const libMesh::Point& p, + const Real t, + Real& m); + + protected: + MAST::CrossSection& _cross_section; + }; + + + class WarpingConstant: public MAST::FieldFunction + { + public: + WarpingConstant(MAST::CrossSection& cross_section); + + virtual ~WarpingConstant() { } + + virtual void operator() (const libMesh::Point& p, + const Real t, + Real& m) const; + + virtual void derivative (MAST::FunctionBase& f, + const libMesh::Point& p, + const Real t, + Real& m); + + protected: + MAST::CrossSection& _cross_section; + }; + + + class ShearCoefficientMatrix: public MAST::FieldFunction + { + public: + ShearCoefficientMatrix(MAST::CrossSection& cross_section); + + virtual ~ShearCoefficientMatrix() { } + + virtual void operator() (const libMesh::Point& p, + const Real t, + RealMatrixX& m) const; + + + virtual void derivative (MAST::FunctionBase& f, + const libMesh::Point& p, + const Real t, + RealMatrixX& m); + + protected: + MAST::CrossSection& _cross_section; + }; + + } +} + + +namespace MAST { + + class Solid1DnParameterSectionElementPropertyCard : public MAST::Solid1DSectionElementPropertyCard + { + public: + Solid1DnParameterSectionElementPropertyCard(): + MAST::Solid1DSectionElementPropertyCard() {} + + /*! + * virtual destructor + */ + virtual ~Solid1DnParameterSectionElementPropertyCard() { } + }; +} + + +#endif // __mast__solid_1d_nparameter_section_element_property_card__ diff --git a/src/property_cards/solid_1d_rod_section_element_property_card.cpp b/src/property_cards/solid_1d_rod_section_element_property_card.cpp new file mode 100644 index 00000000..f3eca5a7 --- /dev/null +++ b/src/property_cards/solid_1d_rod_section_element_property_card.cpp @@ -0,0 +1,345 @@ +/* + * MAST: Multidisciplinary-design Adaptation and Sensitivity Toolkit + * Copyright (C) 2013-2019 Manav Bhatia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +// C++ includes +#include + +// MAST includes +#include "property_cards/solid_1d_rod_section_element_property_card.h" + + +#define PI 3.1415926535897932 + + +void MAST::Solid1DRodSectionProperty::calcA(Real& DIM1, Real& A){ + A = PI*DIM1*DIM1; +} + +void MAST::Solid1DRodSectionProperty::calcdA(Real& DIM1, Real& dDIM1, Real& dA){ + dA = 2.*PI*DIM1*dDIM1; +} + +void MAST::Solid1DRodSectionProperty::calcIz(Real& DIM1, Real& Iz){ + Iz = PI*pow(DIM1,4.)/4.0; +} + +void MAST::Solid1DRodSectionProperty::calcdIz(Real& DIM1, Real& dDIM1, Real& dIz){ + dIz = PI*pow(DIM1,3.)*dDIM1; +} + +void MAST::Solid1DRodSectionProperty::calcIy(Real& DIM1, Real& Iy){ + Iy = PI*pow(DIM1,4.)/4.0; +} + +void MAST::Solid1DRodSectionProperty::calcdIy(Real& DIM1, Real& dDIM1, Real& dIy){ + dIy = PI*pow(DIM1,3.)*dDIM1; +} + +void MAST::Solid1DRodSectionProperty::calcIp(Real& DIM1, Real& Ip){ + Ip = PI*pow(DIM1, 4.)/2.0; +} + +void MAST::Solid1DRodSectionProperty::calcdIp(Real& DIM1, Real& dDIM1, Real& dIp){ + dIp = 2.*PI*pow(DIM1, 3.)*dDIM1; +} + +void MAST::Solid1DRodSectionProperty::calcJ(Real& DIM1, Real& J){ + J = PI*pow(DIM1, 4.)/2.0; +} + +void MAST::Solid1DRodSectionProperty::calcdJ(Real& DIM1, Real& dDIM1, Real& dJ){ + dJ = 2.*PI*pow(DIM1, 3.)*dDIM1; +} + + +MAST::Solid1DRodSectionProperty::WarpingConstant:: +WarpingConstant(): +MAST::FieldFunction("WarpingConstant") +{ +} + +void MAST::Solid1DRodSectionProperty::WarpingConstant:: +operator() (const libMesh::Point& p, const Real t, Real& m) const +{ + m = 0.0; +} + + +void MAST::Solid1DRodSectionProperty::WarpingConstant:: +derivative (const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, +Real& m) const +{ + m = 0.0; +} + + +void MAST::Solid1DRodSectionProperty::WarpingConstant:: +derivative (MAST::FunctionBase& f, const libMesh::Point& p, const Real t, +Real& m) +{ + m = 0.0; +} + +const std::vector +MAST::Solid1DRodSectionElementPropertyCard::get_geom_points(const libMesh::Point& p, const Real t, const uint n) const +{ + const MAST::FieldFunction + &DIM1 = this->get >("DIM1"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real DIM1v, offset_y, offset_z; + DIM1(p, t, DIM1v); + hy_off(p, t, offset_y); hz_off(p, t, offset_z); + + libMesh::Point offset(offset_z, offset_y); + std::vector geom_points(n); + for (uint i=0; i +MAST::Solid1DRodSectionElementPropertyCard::get_geom_points_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, const uint n) const +{ + const MAST::FieldFunction + &DIM1 = this->get >("DIM1"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real DIM1v, offset_y, offset_z; + Real dDIM1v, doffset_y, doffset_z; + DIM1(p, t, DIM1v); DIM1.derivative(f, p, t, dDIM1v); + hy_off(p, t, offset_y); hy_off.derivative(f, p, t, doffset_y); + hz_off(p, t, offset_z); hz_off.derivative(f, p, t, doffset_z); + + libMesh::Point doffset(doffset_z, doffset_y); + std::vector dgeom_points(n); + for (uint i=0; i + &DIM1 = this->get >("DIM1"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real DIM1v, offset_y, offset_z; + DIM1(p, t, DIM1v); + hy_off(p, t, offset_y); hz_off(p, t, offset_z); + + return libMesh::Point(offset_z, offset_y, 0.); +} + + +const libMesh::Point +MAST::Solid1DRodSectionElementPropertyCard::get_shear_center_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t) const +{ + const MAST::FieldFunction + &DIM1 = this->get >("DIM1"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real DIM1v, offset_y, offset_z; + Real dDIM1v, doffset_y, doffset_z; + DIM1(p, t, DIM1v); DIM1.derivative(f, p, t, dDIM1v); + hy_off(p, t, offset_y); hy_off.derivative(f, p, t, doffset_y); + hz_off(p, t, offset_z); hz_off.derivative(f, p, t, doffset_z); + + return libMesh::Point(doffset_z, doffset_y, 0.); +} + + +const libMesh::Point +MAST::Solid1DRodSectionElementPropertyCard::get_centroid(const libMesh::Point& p, const Real t) const +{ + const MAST::FieldFunction + &DIM1 = this->get >("DIM1"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real DIM1v, offset_y, offset_z; + DIM1(p, t, DIM1v); + hy_off(p, t, offset_y); hz_off(p, t, offset_z); + + return libMesh::Point(offset_z, offset_y, 0.); +} + + +const libMesh::Point +MAST::Solid1DRodSectionElementPropertyCard::get_centroid_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t) const +{ + const MAST::FieldFunction + &DIM1 = this->get >("DIM1"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real DIM1v, offset_y, offset_z; + Real dDIM1v, doffset_y, doffset_z; + DIM1(p, t, DIM1v); DIM1.derivative(f, p, t, dDIM1v); + hy_off(p, t, offset_y); hy_off.derivative(f, p, t, doffset_y); + hz_off(p, t, offset_z); hz_off.derivative(f, p, t, doffset_z); + + return libMesh::Point(doffset_z, doffset_y, 0.); +} + + +const std::vector +MAST::Solid1DRodSectionElementPropertyCard::get_stress_points(const libMesh::Point& p, const Real t, const libMesh::Point ps) const +{ + const MAST::FieldFunction + &DIM1 = this->get >("DIM1"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real DIM1v, offset_y, offset_z; + DIM1(p, t, DIM1v); + hy_off(p, t, offset_y); hz_off(p, t, offset_z); + + libMesh::Point offset(offset_z, offset_y); + + return {libMesh::Point(0., DIM1v, 0.) + offset - ps, + libMesh::Point(DIM1v, 0., 0.) + offset - ps, + libMesh::Point(0. -DIM1v, 0.) + offset - ps, + libMesh::Point(-DIM1v, 0., 0.) + offset - ps + }; +} + + +const std::vector +MAST::Solid1DRodSectionElementPropertyCard::get_stress_points_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, const libMesh::Point dps) const +{ + const MAST::FieldFunction + &DIM1 = this->get >("DIM1"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real DIM1v, offset_y, offset_z; + Real dDIM1v, doffset_y, doffset_z; + DIM1(p, t, DIM1v); DIM1.derivative(f, p, t, dDIM1v); + hy_off(p, t, offset_y); hy_off.derivative(f, p, t, doffset_y); + hz_off(p, t, offset_z); hz_off.derivative(f, p, t, doffset_z); + + libMesh::Point offset(offset_z, offset_y); + + libMesh::Point doffset(doffset_z, doffset_y); + + return {libMesh::Point(0., dDIM1v, 0.) + doffset - dps, + libMesh::Point(dDIM1v, 0., 0.) + doffset - dps, + libMesh::Point(0. -dDIM1v, 0.) + doffset - dps, + libMesh::Point(-dDIM1v, 0., 0.) + doffset - dps + }; +} + + +void MAST::Solid1DRodSectionElementPropertyCard::init(const libMesh::LibMeshInit& init) { + + libmesh_assert(!_initialized); + + MAST::FieldFunction + &DIM1 = this->get >("DIM1"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + // Check that dimensions are physically correct + Real DIM1v; DIM1(DIM1v); + if (DIM1v<=0){ + libmesh_error_msg("DIM1<=0"); + } + + // Create a cross section model of this section + cross_section.reset(new MAST::CrossSection(init, 3500, *this, libMesh::TRI6)); + + _A.reset(new MAST::Solid1D1ParameterSectionProperty::Area(MAST::Solid1DRodSectionProperty::calcA, + MAST::Solid1DRodSectionProperty::calcdA, + DIM1)); + + _Ay.reset(new MAST::Solid1D1ParameterSectionProperty::AreaYMoment( + MAST::Solid1DRodSectionProperty::calcA, + MAST::Solid1DRodSectionProperty::calcdA, + DIM1, + hz_off)); + + _Az.reset(new MAST::Solid1D1ParameterSectionProperty::AreaZMoment( + MAST::Solid1DRodSectionProperty::calcA, + MAST::Solid1DRodSectionProperty::calcdA, + DIM1, + hy_off)); + + _J.reset(new MAST::Solid1D1ParameterSectionProperty::TorsionalConstant( + MAST::Solid1DRodSectionProperty::calcJ, + MAST::Solid1DRodSectionProperty::calcdJ, + DIM1)); + + _Ip.reset(new MAST::Solid1D1ParameterSectionProperty::PolarInertia( + MAST::Solid1DRodSectionProperty::calcIp, + MAST::Solid1DRodSectionProperty::calcdIp, + MAST::Solid1DRodSectionProperty::calcA, + MAST::Solid1DRodSectionProperty::calcdA, + DIM1, + hy_off, + hz_off)); + + _AI.reset(new MAST::Solid1D1ParameterSectionProperty::AreaInertiaMatrix( + MAST::Solid1DRodSectionProperty::calcIz, + MAST::Solid1DRodSectionProperty::calcdIz, + MAST::Solid1DRodSectionProperty::calcIy, + MAST::Solid1DRodSectionProperty::calcdIy, + MAST::Solid1DRodSectionProperty::calcA, + MAST::Solid1DRodSectionProperty::calcdA, + DIM1, + hy_off, + hz_off)); + + _Gamma.reset(new MAST::Solid1DRodSectionProperty::WarpingConstant()); + + _Kappa.reset(new MAST::Solid1DnParameterSectionProperty::ShearCoefficientMatrix(*cross_section)); + + _initialized = true; +} + + +void MAST::Solid1DRodSectionElementPropertyCard::create_cross_section( + const libMesh::LibMeshInit& init, const uint n_target_elems, + const libMesh::ElemType element_type) +{ + cross_section.reset(new MAST::CrossSection(init, n_target_elems, + *this, element_type)); +} + + +void MAST::Solid1DRodSectionElementPropertyCard::calculate_properties_pilkey() +{ + cross_section->calculate_geometric_properties(); + cross_section->calculate_warping_properties(); +} diff --git a/src/property_cards/solid_1d_rod_section_element_property_card.h b/src/property_cards/solid_1d_rod_section_element_property_card.h new file mode 100644 index 00000000..ae048c4a --- /dev/null +++ b/src/property_cards/solid_1d_rod_section_element_property_card.h @@ -0,0 +1,139 @@ +/* + * MAST: Multidisciplinary-design Adaptation and Sensitivity Toolkit + * Copyright (C) 2013-2019 Manav Bhatia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * +// * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __mast__solid_1d_rod_section_element_property_card__ +#define __mast__solid_1d_rod_section_element_property_card__ + + +// MAST includes +#include "property_cards/solid_1d_1parameter_section_element_property_card.h" + + +namespace MAST +{ + namespace Solid1DRodSectionProperty + { + void calcA(Real& DIM1, Real& A); + + void calcdA(Real& DIM1, Real& dDIM1, Real& dA); + + void calcIz(Real& DIM1, Real& Iz); + + void calcdIz(Real& DIM1, Real& dDIM1, Real& dIz); + + void calcIy(Real& DIM1, Real& Iy); + + void calcdIy(Real& DIM1, Real& dDIM1, Real& dIy); + + void calcIp(Real& DIM1, Real& Ip); + + void calcdIp(Real& DIM1, Real& dDIM1, Real& dIp); + + void calcJ(Real& DIM1, Real& J); + + void calcdJ(Real& DIM1, Real& dDIM1, Real& dJ); + + class WarpingConstant: public MAST::FieldFunction + { + public: + WarpingConstant(); + + virtual ~WarpingConstant() { } + + virtual void operator() (const libMesh::Point& p, + const Real t, + Real& m) const; + + virtual void derivative (const MAST::FunctionBase& f, + const libMesh::Point& p, + const Real t, + Real& m) const; + + /*! + * Added to be compatible with other sections where the derivative + * function is not constant due to using finite differences to + * approximate the sensitivity. + */ + virtual void derivative (MAST::FunctionBase& f, + const libMesh::Point& p, + const Real t, + Real& m) ; + }; + } +} + +namespace MAST { + + class Solid1DRodSectionElementPropertyCard : public MAST::Solid1DnParameterSectionElementPropertyCard + { + public: + Solid1DRodSectionElementPropertyCard(): + MAST::Solid1DnParameterSectionElementPropertyCard() {} + + /*! + * virtual destructor + */ + virtual ~Solid1DRodSectionElementPropertyCard() { } + + virtual void init(const libMesh::LibMeshInit& init); + + virtual void create_cross_section( + const libMesh::LibMeshInit& init, + const uint n_target_elems=3500, + const libMesh::ElemType element_type=libMesh::TRI6); + + virtual void calculate_properties_pilkey(); + + virtual const std::vector get_geom_points(const libMesh::Point& p, const Real t, const uint n=201) const override; + + virtual const std::vector get_geom_points_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, const uint n=201) const override; + + virtual const libMesh::Point get_shear_center(const libMesh::Point& p, const Real t) const override; + + virtual const libMesh::Point get_shear_center_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t) const; + + virtual const libMesh::Point get_centroid(const libMesh::Point& p, const Real t) const override; + + virtual const libMesh::Point get_centroid_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t) const override; + + virtual const std::vector get_stress_points(const libMesh::Point& p, const Real t, const libMesh::Point ps) const override; + + virtual const std::vector get_stress_points_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, const libMesh::Point dps) const override; + + std::unique_ptr cross_section; + + const bool is_bisymmetric() const + { + return true; + } + + const bool is_symmetric_z() const + { + return true; + } + + const bool is_symmetric_y() const + { + return true; + } + }; +} + + +#endif // __mast__solid_1d_rod_section_element_property_card__ diff --git a/src/property_cards/solid_1d_section_element_property_card.cpp b/src/property_cards/solid_1d_section_element_property_card.cpp index ce1a83eb..89d2a737 100644 --- a/src/property_cards/solid_1d_section_element_property_card.cpp +++ b/src/property_cards/solid_1d_section_element_property_card.cpp @@ -105,7 +105,7 @@ namespace MAST { } - virtual void derivative ( const MAST::FunctionBase& f, + virtual void derivative (const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, Real& m) const { @@ -132,6 +132,38 @@ namespace MAST { 4.*pow(b,4)/pow(a,5)*da/12.))); } + /*! + * Added to be compatible with other sections where the derivative + * function is not constant due to using finite differences to + * approximate the sensitivity. + */ + virtual void derivative (MAST::FunctionBase& f, + const libMesh::Point& p, + const Real t, + Real& m) { + Real hy, hz, dhy, dhz, a, b, da, db; + _hy(p, t, hy); _hy.derivative( f, p, t, dhy); + _hz(p, t, hz); _hz.derivative( f, p, t, dhz); + + // shorter side is b, and longer side is a + if (hy > hz) { + a = hy; da = dhy; + b = hz; db = dhz; + } + else { + a = hz; da = dhz; + b = hy; db = dhy; + } + + m = + da*pow(b,3)*(1./3.-.21*b/a*(1.-pow(b/a,4)/12.)) + + a*3.*pow(b,2)*db*(1./3.-.21*b/a*(1.-pow(b/a,4)/12.)) + + a*pow(b,3)*(-.21*db/a*(1.-pow(b/a,4)/12.) + + (.21*b/pow(a,2)*da*(1.-pow(b/a,4)/12.)) + + (-.21*b/a*(-4.*pow(b,3)*db/pow(a,4)/12.+ + 4.*pow(b,4)/pow(a,5)*da/12.))); + } + protected: const MAST::FieldFunction& _hy, &_hz; @@ -397,6 +429,19 @@ namespace MAST { { m = 0.0; } + + /*! + * Added to be compatible with other sections where the derivative + * function is not constant due to using finite differences to + * approximate the sensitivity. + */ + virtual void derivative (MAST::FunctionBase& f, + const libMesh::Point& p, + const Real t, + Real& m) + { + m = 0.0; + } }; diff --git a/src/property_cards/solid_1d_section_element_property_card.h b/src/property_cards/solid_1d_section_element_property_card.h index 51c40447..1fddd9d9 100644 --- a/src/property_cards/solid_1d_section_element_property_card.h +++ b/src/property_cards/solid_1d_section_element_property_card.h @@ -141,13 +141,23 @@ namespace MAST { /*! - * returns a reference to the material + * returns a constnant reference to the material */ virtual const MAST::MaterialPropertyCardBase& get_material() const { libmesh_assert(_material); // make sure it has already been set return *_material; } + /*! + * returns a writable reference to the material + * currently only used for some finite difference sensitivities in + * Pilkey cross section calculations + */ + virtual MAST::MaterialPropertyCardBase& get_material() { + libmesh_assert(_material); // make sure it has already been set + return *_material; + } + /*! * @returns a constant reference to the section area function */ diff --git a/tests/property/CMakeLists.txt b/tests/property/CMakeLists.txt index 96faebe8..adbaa872 100644 --- a/tests/property/CMakeLists.txt +++ b/tests/property/CMakeLists.txt @@ -2,6 +2,7 @@ target_sources(mast_catch_tests PRIVATE ${CMAKE_CURRENT_LIST_DIR}/mast_solid_1d_section_element_property_card.cpp ${CMAKE_CURRENT_LIST_DIR}/mast_solid_1d_arbitrary_section_element_property_card.cpp + ${CMAKE_CURRENT_LIST_DIR}/mast_solid_1d_rod_section_element_property_card.cpp ${CMAKE_CURRENT_LIST_DIR}/mast_solid_2d_section_element_property_card.cpp ${CMAKE_CURRENT_LIST_DIR}/mast_3d_isotropic_element_property_card.cpp) @@ -343,44 +344,57 @@ set_tests_properties(Arbitrary_Element_Property_Card_1D_Base_mpi # ## ============================================================================ -# ## ============================================================================ -# # 1D ROD Cross Section -# add_test(NAME Rod_Element_Property_Card_1D_Base -# COMMAND mast_catch_tests "rod_element_property_card_constant_base_1d") -# set_tests_properties(Rod_Element_Property_Card_1D_Base -# PROPERTIES -# FIXTURES_REQUIRED Isotropic_Material_1D_Structural) -# -# add_test(NAME Rod_Element_Property_Card_1D_Base_Sensitivity -# COMMAND mast_catch_tests "rod_element_property_card_constant_base_sensitivity_1d") -# set_tests_properties(Rod_Element_Property_Card_1D_Base_Sensitivity -# PROPERTIES -# FIXTURES_REQUIRED Rod_Element_Property_Card_1D_Base) -# -# add_test(NAME Rod_Element_Property_Card_1D_Heat_Transfer -# COMMAND mast_catch_tests "rod_element_property_card_constant_heat_transfer_1d") -# set_tests_properties(Rod_Element_Property_Card_1D_Heat_Transfer -# PROPERTIES -# FIXTURES_REQUIRED Isotropic_Material_1D_Heat_Transfer) -# -# add_test(NAME Rod_Element_Property_Card_1D_Thermoelastic -# COMMAND mast_catch_tests "rod_element_property_card_constant_thermoelastic_1d") -# set_tests_properties(Rod_Element_Property_Card_1D_Thermoelastic -# PROPERTIES -# FIXTURES_REQUIRED Isotropic_Material_1D_Thermoelastic) -# -# add_test(NAME Rod_Element_Property_Card_1D_Structural -# COMMAND mast_catch_tests "rod_element_property_card_constant_structural_1d") -# set_tests_properties(Rod_Element_Property_Card_1D_Structural -# PROPERTIES -# FIXTURES_REQUIRED Isotropic_Material_1D_Structural) -# -# add_test(NAME Rod_Element_Property_Card_1D_Dynamic -# COMMAND mast_catch_tests "rod_element_property_card_constant_dynamic_1d") -# set_tests_properties(Rod_Element_Property_Card_1D_Dynamic -# PROPERTIES -# FIXTURES_REQUIRED Isotropic_Material_1D_Dynamic) -# ## ============================================================================ +## ============================================================================ +# 1D ROD Cross Section +add_test(NAME Rod_Element_Property_Card_1D_Base + COMMAND $ -w NoTests "rod_element_property_card_constant_base_1d") +set_tests_properties(Rod_Element_Property_Card_1D_Base + PROPERTIES + LABELS "SEQ" + FIXTURES_REQUIRED Isotropic_Material_1D_Structural) + +add_test(NAME Rod_Element_Property_Card_1D_Base_mpi + COMMAND ${MPIEXEC_EXECUTABLE} -np 2 $ -w NoTests "rod_element_property_card_constant_base_1d") +set_tests_properties(Rod_Element_Property_Card_1D_Base_mpi + PROPERTIES + LABELS "MPI" + FIXTURES_REQUIRED Isotropic_Material_1D_Structural_mpi) + +add_test(NAME Rod_Element_Property_Card_1D_Base_Sensitivity + COMMAND $ -w NoTests "rod_element_property_card_constant_base_sensitivity_1d") +set_tests_properties(Rod_Element_Property_Card_1D_Base_Sensitivity + PROPERTIES + LABELS "SEQ" + FIXTURES_REQUIRED Rod_Element_Property_Card_1D_Base) + +add_test(NAME Rod_Element_Property_Card_1D_Heat_Transfer + COMMAND $ -w NoTests "rod_element_property_card_constant_heat_transfer_1d") +set_tests_properties(Rod_Element_Property_Card_1D_Heat_Transfer + PROPERTIES + LABELS "SEQ" + FIXTURES_REQUIRED Isotropic_Material_1D_Heat_Transfer) + +add_test(NAME Rod_Element_Property_Card_1D_Thermoelastic + COMMAND $ -w NoTests "rod_element_property_card_constant_thermoelastic_1d") +set_tests_properties(Rod_Element_Property_Card_1D_Thermoelastic + PROPERTIES + LABELS "SEQ" + FIXTURES_REQUIRED Isotropic_Material_1D_Thermoelastic) + +add_test(NAME Rod_Element_Property_Card_1D_Structural + COMMAND $ -w NoTests "rod_element_property_card_constant_structural_1d") +set_tests_properties(Rod_Element_Property_Card_1D_Structural + PROPERTIES + LABELS "SEQ" + FIXTURES_REQUIRED Isotropic_Material_1D_Structural) + +add_test(NAME Rod_Element_Property_Card_1D_Dynamic + COMMAND $ -w NoTests "rod_element_property_card_constant_dynamic_1d") +set_tests_properties(Rod_Element_Property_Card_1D_Dynamic + PROPERTIES + LABELS "SEQ" + FIXTURES_REQUIRED Isotropic_Material_1D_Dynamic) +## ============================================================================ # ## ============================================================================ diff --git a/tests/property/mast_solid_1d_rod_section_element_property_card.cpp b/tests/property/mast_solid_1d_rod_section_element_property_card.cpp new file mode 100644 index 00000000..d95df88d --- /dev/null +++ b/tests/property/mast_solid_1d_rod_section_element_property_card.cpp @@ -0,0 +1,1546 @@ +// Catch2 includes +#include "catch.hpp" + +// libMesh includes +#include "libmesh/point.h" + +// MAST includes +#include "base/parameter.h" +#include "base/constant_field_function.h" +#include "property_cards/isotropic_material_property_card.h" +#include "property_cards/solid_1d_rod_section_element_property_card.h" + +// Custom includes +#include "test_helpers.h" + +extern libMesh::LibMeshInit* p_global_init; + +#define PI 3.1415926535897932 + +/** + * A BAR is defined as a solid rectangular cross section defined by two + * parameters. + */ +TEST_CASE("rod_element_property_card_constant_base_1d", + "[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + + // Define Material Properties as MAST Parameters + MAST::Parameter rho("rho_param", 1420.5); // Density + MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity + MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio + MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity + MAST::Parameter k("k_param", 237.0); // Thermal Conductivity + + const Real G = E() / (2. * (1. + nu())); + + // Define Section Properties as MAST Parameters + MAST::Parameter DIM1("DIM1", 3.234); // Section thickness in z-direction + MAST::Parameter offset_y("offy_param", 0.287); // Section offset in y-direction + MAST::Parameter offset_z("offz_param", -1.654); // Section offset in z-direction + + // Define Sensitivity Parameters + std::vector sens_params = {&DIM1}; + uint n_s = sens_params.size(); + + // Create field functions to dsitribute these constant parameters throughout the model + // Section Property Field Functions + MAST::ConstantFieldFunction DIM1_f("DIM1", DIM1); + MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); + MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); + // Material Property Field Functions + MAST::ConstantFieldFunction rho_f("rho", rho); + MAST::ConstantFieldFunction E_f("E", E); + MAST::ConstantFieldFunction nu_f("nu", nu); + MAST::ConstantFieldFunction cp_f("cp", cp); + MAST::ConstantFieldFunction k_f("k_th", k); + + // Initialize the material + MAST::IsotropicMaterialPropertyCard material; + + // Add the material property constant field functions to the material card + material.add(rho_f); + material.add(k_f); + material.add(cp_f); + material.add(E_f); + material.add(nu_f); + + // Initialize the section + MAST::Solid1DRodSectionElementPropertyCard section; + + // Add the section property constant field functions to the section card + section.add(DIM1_f); + + section.add(offsety_f); + section.add(offsetz_f); + + // Add the material card to the section card + section.set_material(material); + + // Specify a section orientation point and add it to the section. + RealVectorX orientation = RealVectorX::Zero(3); + orientation(1) = 1.0; + section.y_vector() = orientation; + + // Now initialize the section + section.init(*p_global_init); + + REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional + REQUIRE( section.depends_on(DIM1) ); + REQUIRE( section.depends_on(offset_y) ); + REQUIRE( section.depends_on(offset_z) ); + REQUIRE( section.depends_on(k) ); + REQUIRE( section.depends_on(cp) ); + REQUIRE( section.depends_on(rho) ); + + REQUIRE( section.if_isotropic() ); + + // True values + const Real r = DIM1(); + const Real area_true = PI*r*r; + const Real torsion_constant_true = PI*pow(r, 4.0)/2.0; + const Real first_area_moment_z_true = area_true * offset_y(); + const Real first_area_moment_y_true = area_true * offset_z(); + const Real Izzc_true = PI*pow(r, 4.0)/4.0; + const Real Iyyc_true = PI*pow(r, 4.0)/4.0; + const Real Izyc_true = 0.0; + const Real Ipc_true = PI*pow(r, 4.0)/2.0; + const Real second_area_moment_zz_true = Izzc_true + area_true * pow(offset_y(), 2.); + const Real second_area_moment_yy_true = Iyyc_true + area_true * pow(offset_z(), 2.); + const Real second_area_moment_zy_true = Izyc_true + area_true * offset_y() * offset_z(); + const Real second_area_moment_polar_true = second_area_moment_zz_true + second_area_moment_yy_true; + const Real warping_constant_true = 0.0; + const Real kappa_z_true = 8.4967018479575718e-01; + const Real kappa_y_true = 8.4967018474199052e-01; + const Real xs_true = offset_z(); + const Real ys_true = offset_y(); + const Real xc_true = offset_z(); + const Real yc_true = offset_y(); + const libMesh::Point shear_center_true(xs_true, ys_true, 0.); + const libMesh::Point centroid_true(xc_true, yc_true, 0.); + + const libMesh::Point point(4.3, -3.5, -6.7); + const Real time = 8.22; + + Real area; + const MAST::FieldFunction& Area = section.A(); + Area(point, time, area); + REQUIRE( area == Approx(area_true) ); + + Real first_area_moment_y; + const MAST::FieldFunction& Ay = section.Ay(); + Ay(point, time, first_area_moment_y); + CHECK( first_area_moment_y == Approx(first_area_moment_y_true) ); + + Real first_area_moment_z; + const MAST::FieldFunction& Az = section.Az(); + Az(point, time, first_area_moment_z); + CHECK( first_area_moment_z == Approx(first_area_moment_z_true) ); + + RealMatrixX I; + const MAST::FieldFunction& Inertias = section.I(); + Inertias(point, time, I); + REQUIRE( I(0,1) == I(1,0) ); + Real Iyy = I(1,1); + Real Izz = I(0,0); + Real Izy = I(0,1); + REQUIRE( Izz == Approx(second_area_moment_zz_true) ); + REQUIRE( Iyy == Approx(second_area_moment_yy_true) ); + REQUIRE( Izy == Approx(second_area_moment_zy_true) ); + + Real Ip; + const MAST::FieldFunction& PolarInertia = section.Ip(); + PolarInertia(point, time, Ip); + REQUIRE( Ip == Approx(second_area_moment_polar_true) ); + + Real torsion_constant; + const MAST::FieldFunction& TorsionConstant = section.J(); + TorsionConstant(point, time, torsion_constant); + REQUIRE( torsion_constant == Approx(torsion_constant_true)); + + Real warping_constant; + const MAST::FieldFunction& WarpingConstant = section.Gam(); + WarpingConstant(point, time, warping_constant); + REQUIRE( warping_constant == Approx(warping_constant_true) ); + + RealMatrixX shear_coefficients; + const MAST::FieldFunction& ShearCoefficientMatrix = section.Kap(); + ShearCoefficientMatrix(point, time, shear_coefficients); + REQUIRE( shear_coefficients(0,0) == Approx(kappa_z_true) ); + REQUIRE( shear_coefficients(1,1) == Approx(kappa_y_true) ); + + libMesh::Point centroid = section.get_centroid(point, time); + REQUIRE( centroid(0) == Approx(centroid_true(0)) ); + REQUIRE( centroid(1) == Approx(centroid_true(1)) ); + + libMesh::Point shear_center = section.get_shear_center(point, time); + REQUIRE(shear_center(0) == Approx(xs_true)); + REQUIRE(shear_center(1) == Approx(ys_true)); + + REQUIRE_FALSE( section.if_diagonal_mass_matrix() ); + + section.set_diagonal_mass_matrix(true); + REQUIRE( section.if_diagonal_mass_matrix() ); +} + + +/*! + * These sensitivity checks are performed against a 4th order accurate + * central difference approximation with a perturbation of 1.22e-04. + */ +TEST_CASE("rod_element_property_card_constant_base_sensitivity_1d", + "[1D],[isotropic],[constant],[property],[sensitivity]") +{ + const uint dim = 1; + + // Define Material Properties as MAST Parameters + MAST::Parameter rho("rho_param", 1420.5); // Density + MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity + MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio + MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity + MAST::Parameter k("k_param", 237.0); // Thermal Conductivity + + const Real G = E() / (2. * (1. + nu())); + + // Define Section Properties as MAST Parameters + MAST::Parameter DIM1("DIM1", 3.234); // Section thickness in z-direction + MAST::Parameter offset_y("offy_param", 0.287); // Section offset in y-direction + MAST::Parameter offset_z("offz_param", -1.654); // Section offset in z-direction + + // Define Sensitivity Parameters + std::vector sens_params = {&DIM1}; + uint n_s = sens_params.size(); + + // Create field functions to dsitribute these constant parameters throughout the model + // Section Property Field Functions + MAST::ConstantFieldFunction DIM1_f("DIM1", DIM1); + MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); + MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); + // Material Property Field Functions + MAST::ConstantFieldFunction rho_f("rho", rho); + MAST::ConstantFieldFunction E_f("E", E); + MAST::ConstantFieldFunction nu_f("nu", nu); + MAST::ConstantFieldFunction cp_f("cp", cp); + MAST::ConstantFieldFunction k_f("k_th", k); + + // Initialize the material + MAST::IsotropicMaterialPropertyCard material; + + // Add the material property constant field functions to the material card + material.add(rho_f); + material.add(k_f); + material.add(cp_f); + material.add(E_f); + material.add(nu_f); + + // Initialize the section + MAST::Solid1DRodSectionElementPropertyCard section; + + // Add the section property constant field functions to the section card + section.add(DIM1_f); + section.add(offsety_f); + section.add(offsetz_f); + + // Add the material card to the section card + section.set_material(material); + + // Specify a section orientation point and add it to the section. + RealVectorX orientation = RealVectorX::Zero(3); + orientation(1) = 1.0; + section.y_vector() = orientation; + + // Now initialize the section + section.init(*p_global_init); + + REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional + REQUIRE( section.depends_on(DIM1) ); + REQUIRE( section.depends_on(offset_y) ); + REQUIRE( section.depends_on(offset_z) ); + REQUIRE( section.depends_on(k) ); + REQUIRE( section.depends_on(cp) ); + REQUIRE( section.depends_on(rho) ); + + REQUIRE( section.if_isotropic() ); + + // True values + const Real r = DIM1(); + const Real area_true = PI*r*r; + const Real torsion_constant_true = PI*pow(r, 4.0)/2.0; + const Real first_area_moment_z_true = area_true * offset_y(); + const Real first_area_moment_y_true = area_true * offset_z(); + const Real Izzc_true = PI*pow(r, 4.0)/4.0; + const Real Iyyc_true = PI*pow(r, 4.0)/4.0; + const Real Izyc_true = 0.0; + const Real Ipc_true = PI*pow(r, 4.0)/2.0; + const Real second_area_moment_zz_true = Izzc_true + area_true * pow(offset_y(), 2.); + const Real second_area_moment_yy_true = Iyyc_true + area_true * pow(offset_z(), 2.); + const Real second_area_moment_zy_true = Izyc_true + area_true * offset_y() * offset_z(); + const Real second_area_moment_polar_true = second_area_moment_zz_true + second_area_moment_yy_true; + const Real warping_constant_true = 0.0; + const Real kappa_z_true = 8.4967018479575718e-01; + const Real kappa_y_true = 8.4967018474199052e-01; + const Real xs_true = offset_z(); + const Real ys_true = offset_y(); + const Real xc_true = offset_z(); + const Real yc_true = offset_y(); + const libMesh::Point shear_center_true(xs_true, ys_true, 0.); + const libMesh::Point centroid_true(xc_true, yc_true, 0.); + + const libMesh::Point point(4.3, -3.5, -6.7); + const Real time = 8.22; + + Real dA_dDIM1, dA_dDIM2; + Real dCz_dDIM1, dCz_dDIM2; + Real dCy_dDIM1, dCy_dDIM2; + Real dQz_dDIM1, dQz_dDIM2; + Real dQy_dDIM1, dQy_dDIM2; + Real dIzz_dDIM1, dIzz_dDIM2; + Real dIyy_dDIM1, dIyy_dDIM2; + Real dIzy_dDIM1, dIzy_dDIM2; + Real dIp_dDIM1, dIp_dDIM2; + Real dIzzc_dDIM1, dIzzc_dDIM2; + Real dIyyc_dDIM1, dIyyc_dDIM2; + Real dIzyc_dDIM1, dIzyc_dDIM2; + Real dIpc_dDIM1, dIpc_dDIM2; + Real dJ_dDIM1, dJ_dDIM2; + Real dxs_dDIM1, dxs_dDIM2; + Real dys_dDIM1, dys_dDIM2; + Real dW_dDIM1, dW_dDIM2; + + Real f_h, f_2h, f_n, f_2n; + RealVectorX fv_h, fv_2h, fv_n, fv_2n; + RealMatrixX fm_h, fm_2h, fm_n, fm_2n; + + const Real delta = 1.220703125e-04; // (np.spacing(1))**(0.25) + + // Area Sensitivity Check + libMesh::out << "\tArea Sensitivity Check..." << std::endl; + const MAST::FieldFunction& Area = section.A(); + std::vector dA(n_s); + for (uint i=0; i dA_cd(n_s); + for (uint i=0; i dC(n_s); + for (uint i=0; i dC_cd(n_s); + for (uint i=0; i& Area_y = section.Ay(); + std::vector dAy(n_s); + for (uint i=0; i dAy_cd(n_s); + for (uint i=0; i& Area_z = section.Az(); + std::vector dAz(n_s); + for (uint i=0; i dAz_cd(n_s); + for (uint i=0; i& Inertia = section.I(); + std::vector dI(n_s); + for (uint i=0; i dI_cd(n_s); + for (uint i=0; i& PolarInertia = section.Ip(); + std::vector dIp(n_s); + for (uint i=0; i dIp_cd(n_s); + for (uint i=0; i dCs(n_s); +// for (uint i=0; i dCs_cd(n_s); +// for (uint i=0; iname() << " = " << dCs[i] << "\tdCs_cd = " << dCs_cd[i] << std::endl; +// REQUIRE(dCs[i](0) == Approx(dCs_cd[i](0)) ); +// REQUIRE(dCs[i](1) == Approx(dCs_cd[i](1)) ); +// } + + + // Torsion Constant Sensitivity Check + // NOTE: The field function below is not made constant because currently a finite difference is used to calculate sensitivity. + libMesh::out << "\tTorsion Constant Sensitivity Check..." << std::endl; + MAST::FieldFunction& TorsionConstant = section.J(); + std::vector dJ(n_s); + for (uint i=0; i dJ_cd(n_s); + for (uint i=0; i& Kappa = section.Kap(); +// std::vector dK(n_s); +// for (uint i=0; i dK_cd(n_s); +// for (uint i=0; i& WarpingConstant = section.Gam(); + std::vector dW(n_s); + for (uint i=0; i dW_cd(n_s); + for (uint i=0; iname() << " = " << dW[i] << "\tdW_cd = " << dW_cd[i] << std::endl; + REQUIRE(dW[i] == Approx(dW_cd[i]).epsilon(0.1) ); + // NOTE: 10% error margin due to 'exact' sensitivity being calculated using finite difference + } +} + + +TEST_CASE("rod_element_property_card_constant_heat_transfer_1d", + "[heat_transfer],[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + + // Define Material Properties as MAST Parameters + MAST::Parameter rho("rho_param", 1420.5); // Density + MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity + MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio + MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity + MAST::Parameter k("k_param", 237.0); // Thermal Conductivity + + const Real G = E() / (2. * (1. + nu())); + + // Define Section Properties as MAST Parameters + MAST::Parameter DIM1("DIM1", 3.234); // Section thickness in z-direction + MAST::Parameter offset_y("offy_param", 0.287); // Section offset in y-direction + MAST::Parameter offset_z("offz_param", -1.654); // Section offset in z-direction + + // Create field functions to dsitribute these constant parameters throughout the model + // Section Property Field Functions + MAST::ConstantFieldFunction DIM1_f("DIM1", DIM1); + MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); + MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); + // Material Property Field Functions + MAST::ConstantFieldFunction rho_f("rho", rho); + MAST::ConstantFieldFunction E_f("E", E); + MAST::ConstantFieldFunction nu_f("nu", nu); + MAST::ConstantFieldFunction cp_f("cp", cp); + MAST::ConstantFieldFunction k_f("k_th", k); + + // Initialize the material + MAST::IsotropicMaterialPropertyCard material; + + // Add the material property constant field functions to the material card + material.add(rho_f); + material.add(k_f); + material.add(cp_f); + material.add(E_f); + material.add(nu_f); + + // Initialize the section + MAST::Solid1DRodSectionElementPropertyCard section; + + // Add the section property constant field functions to the section card + section.add(DIM1_f); + section.add(offsety_f); + section.add(offsetz_f); + + // Add the material card to the section card + section.set_material(material); + + // Specify a section orientation point and add it to the section. + RealVectorX orientation = RealVectorX::Zero(3); + orientation(1) = 1.0; + section.y_vector() = orientation; + + // Now initialize the section + section.init(*p_global_init); + + REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional + REQUIRE( section.depends_on(DIM1) ); + REQUIRE( section.depends_on(offset_y) ); + REQUIRE( section.depends_on(offset_z) ); + REQUIRE( section.depends_on(k) ); + REQUIRE( section.depends_on(cp) ); + REQUIRE( section.depends_on(rho) ); + + REQUIRE( section.if_isotropic() ); + + // True values + const Real r = DIM1(); + const Real area_true = PI*r*r; + const Real torsion_constant_true = PI*pow(r, 4.0)/2.0; + const Real first_area_moment_z_true = area_true * offset_y(); + const Real first_area_moment_y_true = area_true * offset_z(); + const Real Izzc_true = PI*pow(r, 4.0)/4.0; + const Real Iyyc_true = PI*pow(r, 4.0)/4.0; + const Real Izyc_true = 0.0; + const Real Ipc_true = PI*pow(r, 4.0)/2.0; + const Real second_area_moment_zz_true = Izzc_true + area_true * pow(offset_y(), 2.); + const Real second_area_moment_yy_true = Iyyc_true + area_true * pow(offset_z(), 2.); + const Real second_area_moment_zy_true = Izyc_true + area_true * offset_y() * offset_z(); + const Real second_area_moment_polar_true = second_area_moment_zz_true + second_area_moment_yy_true; + const Real warping_constant_true = 0.0; + const Real kappa_z_true = 8.4967018479575718e-01; + const Real kappa_y_true = 8.4967018474199052e-01; + const Real xs_true = offset_z(); + const Real ys_true = offset_y(); + const Real xc_true = offset_z(); + const Real yc_true = offset_y(); + const libMesh::Point shear_center_true(xs_true, ys_true, 0.); + const libMesh::Point centroid_true(xc_true, yc_true, 0.); + + const libMesh::Point point(4.3, -3.5, -6.7); + const Real time = 8.22; + + Real area; + const MAST::FieldFunction& Area = section.A(); + Area(point, time, area); + REQUIRE( area == Approx(area_true) ); + + + SECTION("1D section thermal conductance matrix") + { + /** + * As of Dec. 17, 2019, inertia_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * inertia_matrix to be obtained without any input arguments. + */ + std::unique_ptr> conduct_mat = section.thermal_conductance_matrix(); + + const libMesh::Point point(2.3, 3.1, 5.2); + const Real time = 2.34; + RealMatrixX D_sec_conduc; + conduct_mat->operator()(point, time, D_sec_conduc); + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_conduc_true = RealMatrixX::Zero(1,1); + D_sec_conduc_true(0,0) = k() * area_true; + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_conduc); + std::vector truth = eigen_matrix_to_std_vector(D_sec_conduc_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } + + SECTION("1D section thermal capacitance matrix") + { + /** + * As of Dec. 17, 2019, inertia_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * inertia_matrix to be obtained without any input arguments. + */ + std::unique_ptr> capaci_mat = section.thermal_capacitance_matrix(); + + const libMesh::Point point(2.3, 3.1, 5.2); + const Real time = 2.34; + RealMatrixX D_sec_capac; + capaci_mat->operator()(point, time, D_sec_capac); + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_capac_true = RealMatrixX::Zero(1,1); + D_sec_capac_true(0,0) = rho() * cp() * area_true; + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_capac); + std::vector truth = eigen_matrix_to_std_vector(D_sec_capac_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } +} + + +TEST_CASE("rod_element_property_card_constant_thermoelastic_1d", + "[thermoelastic],[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + + // Define Material Properties as MAST Parameters + MAST::Parameter rho("rho_param", 1420.5); // Density + MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity + MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio + MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity + MAST::Parameter k("k_param", 237.0); // Thermal Conductivity + MAST::Parameter alpha("alpha_param", 5.73e-05); // Coeff. of Thermal Exp. + + const Real G = E() / (2. * (1. + nu())); + + // Define Section Properties as MAST Parameters + MAST::Parameter DIM1("DIM1", 3.234); // Section thickness in z-direction + MAST::Parameter offset_y("offy_param", 0.287); // Section offset in y-direction + MAST::Parameter offset_z("offz_param", -1.654); // Section offset in z-direction + + // Create field functions to dsitribute these constant parameters throughout the model + // Section Property Field Functions + MAST::ConstantFieldFunction DIM1_f("DIM1", DIM1); + MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); + MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); + // Material Property Field Functions + MAST::ConstantFieldFunction rho_f("rho", rho); + MAST::ConstantFieldFunction E_f("E", E); + MAST::ConstantFieldFunction nu_f("nu", nu); + MAST::ConstantFieldFunction cp_f("cp", cp); + MAST::ConstantFieldFunction k_f("k_th", k); + MAST::ConstantFieldFunction alpha_f("alpha_expansion", alpha); + + // Initialize the material + MAST::IsotropicMaterialPropertyCard material; + + // Add the material property constant field functions to the material card + material.add(rho_f); + material.add(k_f); + material.add(cp_f); + material.add(E_f); + material.add(nu_f); + material.add(alpha_f); + + // Initialize the section + MAST::Solid1DRodSectionElementPropertyCard section; + + // Add the section property constant field functions to the section card + section.add(DIM1_f); + section.add(offsety_f); + section.add(offsetz_f); + + // Add the material card to the section card + section.set_material(material); + + // Specify a section orientation point and add it to the section. + RealVectorX orientation = RealVectorX::Zero(3); + orientation(1) = 1.0; + section.y_vector() = orientation; + + // Now initialize the section + section.init(*p_global_init); + + REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional + REQUIRE( section.depends_on(DIM1) ); + REQUIRE( section.depends_on(offset_y) ); + REQUIRE( section.depends_on(offset_z) ); + REQUIRE( section.depends_on(k) ); + REQUIRE( section.depends_on(cp) ); + REQUIRE( section.depends_on(rho) ); + + REQUIRE( section.if_isotropic() ); + + // True values + const Real r = DIM1(); + const Real area_true = PI*r*r; + const Real torsion_constant_true = PI*pow(r, 4.0)/2.0; + const Real first_area_moment_z_true = area_true * offset_y(); + const Real first_area_moment_y_true = area_true * offset_z(); + const Real Izzc_true = PI*pow(r, 4.0)/4.0; + const Real Iyyc_true = PI*pow(r, 4.0)/4.0; + const Real Izyc_true = 0.0; + const Real Ipc_true = PI*pow(r, 4.0)/2.0; + const Real second_area_moment_zz_true = Izzc_true + area_true * pow(offset_y(), 2.); + const Real second_area_moment_yy_true = Iyyc_true + area_true * pow(offset_z(), 2.); + const Real second_area_moment_zy_true = Izyc_true + area_true * offset_y() * offset_z(); + const Real second_area_moment_polar_true = second_area_moment_zz_true + second_area_moment_yy_true; + const Real warping_constant_true = 0.0; + const Real kappa_z_true = 8.4967018479575718e-01; + const Real kappa_y_true = 8.4967018474199052e-01; + const Real xs_true = offset_z(); + const Real ys_true = offset_y(); + const Real xc_true = offset_z(); + const Real yc_true = offset_y(); + const libMesh::Point shear_center_true(xs_true, ys_true, 0.); + const libMesh::Point centroid_true(xc_true, yc_true, 0.); + + const libMesh::Point point(4.3, -3.5, -6.7); + const Real time = 8.22; + + SECTION("1D thermal expansion A matrix") + { + /** + * As of Dec. 17, 2019, thermal_expansion_A_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * thermal_expansion_A_matrix to be obtained without any input arguments. + */ + + Real area; + const MAST::FieldFunction& Area = section.A(); + Area(point, time, area); + CHECK( area == Approx(area_true) ); + + std::unique_ptr> texp_A_mat = section.thermal_expansion_A_matrix(); + + const libMesh::Point point(2.3, 3.1, 5.2); + const Real time = 2.34; + RealMatrixX D_sec_texpA; + texp_A_mat->operator()(point, time, D_sec_texpA); + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_texpA_true = RealMatrixX::Zero(2,1); + D_sec_texpA_true(0,0) = E() * alpha() * area_true; + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_texpA); + std::vector truth = eigen_matrix_to_std_vector(D_sec_texpA_true); + + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } + + SECTION("1D thermal expansion B matrix") + { + /** + * As of Dec. 17, 2019, thermal_expansion_B_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * thermal_expansion_B_matrix to be obtained without any input arguments. + */ + + Real first_area_moment_y; + const MAST::FieldFunction& Ay = section.Ay(); + Ay(point, time, first_area_moment_y); + CHECK( first_area_moment_y == Approx(first_area_moment_y_true) ); + + Real first_area_moment_z; + const MAST::FieldFunction& Az = section.Az(); + Az(point, time, first_area_moment_z); + CHECK( first_area_moment_z == Approx(first_area_moment_z_true) ); + + std::unique_ptr> texp_B_mat = section.thermal_expansion_B_matrix(); + + const libMesh::Point point(2.3, 3.1, 5.2); + const Real time = 2.34; + RealMatrixX D_sec_texpB; + texp_B_mat->operator()(point, time, D_sec_texpB); + + libMesh::out << "texp_B_mat =\n" << D_sec_texpB << std::endl; + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_texpB_true = RealMatrixX::Zero(2,1); + D_sec_texpB_true(0,0) = E() * alpha() * first_area_moment_z_true; + D_sec_texpB_true(1,0) = E() * alpha() * first_area_moment_y_true; + + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_texpB); + std::vector truth = eigen_matrix_to_std_vector(D_sec_texpB_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } +} + + +TEST_CASE("rod_element_property_card_constant_dynamic_1d", + "[dynamic],[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + + // Define Material Properties as MAST Parameters + MAST::Parameter rho("rho_param", 1420.5); // Density + MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity + MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio + MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity + MAST::Parameter k("k_param", 237.0); // Thermal Conductivity + + const Real G = E() / (2. * (1. + nu())); + + // Define Section Properties as MAST Parameters + MAST::Parameter DIM1("DIM1", 3.234); // Section thickness in z-direction + MAST::Parameter offset_y("offy_param", 0.287); // Section offset in y-direction + MAST::Parameter offset_z("offz_param", -1.654); // Section offset in z-direction + + // Create field functions to dsitribute these constant parameters throughout the model + // Section Property Field Functions + MAST::ConstantFieldFunction DIM1_f("DIM1", DIM1); + MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); + MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); + // Material Property Field Functions + MAST::ConstantFieldFunction rho_f("rho", rho); + MAST::ConstantFieldFunction E_f("E", E); + MAST::ConstantFieldFunction nu_f("nu", nu); + MAST::ConstantFieldFunction cp_f("cp", cp); + MAST::ConstantFieldFunction k_f("k_th", k); + + // Initialize the material + MAST::IsotropicMaterialPropertyCard material; + + // Add the material property constant field functions to the material card + material.add(rho_f); + material.add(k_f); + material.add(cp_f); + material.add(E_f); + material.add(nu_f); + + // Initialize the section + MAST::Solid1DRodSectionElementPropertyCard section; + + // Add the section property constant field functions to the section card + section.add(DIM1_f); + section.add(offsety_f); + section.add(offsetz_f); + + // Add the material card to the section card + section.set_material(material); + + // Specify a section orientation point and add it to the section. + RealVectorX orientation = RealVectorX::Zero(3); + orientation(1) = 1.0; + section.y_vector() = orientation; + + // Now initialize the section + section.init(*p_global_init); + + REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional + REQUIRE( section.depends_on(DIM1) ); + REQUIRE( section.depends_on(offset_y) ); + REQUIRE( section.depends_on(offset_z) ); + REQUIRE( section.depends_on(k) ); + REQUIRE( section.depends_on(cp) ); + REQUIRE( section.depends_on(rho) ); + + REQUIRE( section.if_isotropic() ); + + // True values + const Real r = DIM1(); + const Real area_true = PI*r*r; + const Real torsion_constant_true = PI*pow(r, 4.0)/2.0; + const Real first_area_moment_z_true = area_true * offset_y(); + const Real first_area_moment_y_true = area_true * offset_z(); + const Real Izzc_true = PI*pow(r, 4.0)/4.0; + const Real Iyyc_true = PI*pow(r, 4.0)/4.0; + const Real Izyc_true = 0.0; + const Real Ipc_true = PI*pow(r, 4.0)/2.0; + const Real second_area_moment_zz_true = Izzc_true + area_true * pow(offset_y(), 2.); + const Real second_area_moment_yy_true = Iyyc_true + area_true * pow(offset_z(), 2.); + const Real second_area_moment_zy_true = Izyc_true + area_true * offset_y() * offset_z(); + const Real second_area_moment_polar_true = second_area_moment_zz_true + second_area_moment_yy_true; + const Real warping_constant_true = 0.0; + const Real kappa_z_true = 8.4967018479575718e-01; + const Real kappa_y_true = 8.4967018474199052e-01; + const Real xs_true = offset_z(); + const Real ys_true = offset_y(); + const Real xc_true = offset_z(); + const Real yc_true = offset_y(); + const libMesh::Point shear_center_true(xs_true, ys_true, 0.); + const libMesh::Point centroid_true(xc_true, yc_true, 0.); + + const libMesh::Point point(4.3, -3.5, -6.7); + const Real time = 8.22; + + SECTION("1D section inertia matrix") + { + /** + * As of Dec. 17, 2019, inertia_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * inertia_matrix to be obtained without any input arguments. + */ + std::unique_ptr> inertia_mat = section.inertia_matrix(); + + const libMesh::Point point(2.3, 3.1, 5.2); + const Real time = 2.34; + RealMatrixX D_sec_iner; + inertia_mat->operator()(point, time, D_sec_iner); + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_iner_true = RealMatrixX::Zero(6,6); + + + Real area; + const MAST::FieldFunction& Area = section.A(); + Area(point, time, area); + REQUIRE( area == Approx(area_true) ); + D_sec_iner_true(0,0) = D_sec_iner_true(1,1) = D_sec_iner_true(2,2) = area_true; + + Real Ip; + const MAST::FieldFunction& PolarInertia = section.Ip(); + PolarInertia(point, time, Ip); + CHECK( Ip == Approx(second_area_moment_polar_true) ); + D_sec_iner_true(3,3) = second_area_moment_polar_true; + + Real first_area_moment_y; + const MAST::FieldFunction& Ay = section.Ay(); + Ay(point, time, first_area_moment_y); + CHECK( first_area_moment_y == Approx(first_area_moment_y_true) ); + D_sec_iner_true(0,4) = D_sec_iner_true(4,0) = first_area_moment_y_true; + + Real first_area_moment_z; + const MAST::FieldFunction& Az = section.Az(); + Az(point, time, first_area_moment_z); + CHECK( first_area_moment_z == Approx(first_area_moment_z_true) ); + D_sec_iner_true(0,5) = D_sec_iner_true(5,0) = first_area_moment_z_true; + + RealMatrixX I; + const MAST::FieldFunction& Inertias = section.I(); + Inertias(point, time, I); + REQUIRE( I(0,1) == I(1,0) ); + Real Iyy = I(1,1); + Real Izz = I(0,0); + Real Izy = I(0,1); + REQUIRE( Izz == Approx(second_area_moment_zz_true) ); + REQUIRE( Iyy == Approx(second_area_moment_yy_true) ); + REQUIRE( Izy == Approx(second_area_moment_zy_true) ); + + D_sec_iner_true(4,4) = Iyy; // TODO: Should this be Izz? + D_sec_iner_true(4,5) = Izy; + D_sec_iner_true(5,4) = Izy; + D_sec_iner_true(5,5) = Izz; // TODO: Should this be Iyy?? + + D_sec_iner_true *= rho(); + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_iner); + std::vector truth = eigen_matrix_to_std_vector(D_sec_iner_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } +} + + +TEST_CASE("rod_element_property_card_constant_structural_1d", + "[structural],[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + + // Define Material Properties as MAST Parameters + MAST::Parameter rho("rho_param", 1420.5); // Density + MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity + MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio + MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity + MAST::Parameter k("k_param", 237.0); // Thermal Conductivity + + const Real G = E() / (2. * (1. + nu())); + + // Define Section Properties as MAST Parameters + MAST::Parameter DIM1("DIM1", 3.234); // Section thickness in z-direction + MAST::Parameter offset_y("offy_param", 0.287); // Section offset in y-direction + MAST::Parameter offset_z("offz_param", -1.654); // Section offset in z-direction + + // Create field functions to dsitribute these constant parameters throughout the model + // Section Property Field Functions + MAST::ConstantFieldFunction DIM1_f("DIM1", DIM1); + MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); + MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); + // Material Property Field Functions + MAST::ConstantFieldFunction rho_f("rho", rho); + MAST::ConstantFieldFunction E_f("E", E); + MAST::ConstantFieldFunction nu_f("nu", nu); + MAST::ConstantFieldFunction cp_f("cp", cp); + MAST::ConstantFieldFunction k_f("k_th", k); + + // Initialize the material + MAST::IsotropicMaterialPropertyCard material; + + // Add the material property constant field functions to the material card + material.add(rho_f); + material.add(k_f); + material.add(cp_f); + material.add(E_f); + material.add(nu_f); + + // Initialize the section + MAST::Solid1DRodSectionElementPropertyCard section; + + // Add the section property constant field functions to the section card + section.add(DIM1_f); + section.add(offsety_f); + section.add(offsetz_f); + + // Add the material card to the section card + section.set_material(material); + + // Specify a section orientation point and add it to the section. + RealVectorX orientation = RealVectorX::Zero(3); + orientation(1) = 1.0; + section.y_vector() = orientation; + + // Now initialize the section + section.init(*p_global_init); + + REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional + REQUIRE( section.depends_on(DIM1) ); + REQUIRE( section.depends_on(offset_y) ); + REQUIRE( section.depends_on(offset_z) ); + REQUIRE( section.depends_on(k) ); + REQUIRE( section.depends_on(cp) ); + REQUIRE( section.depends_on(rho) ); + + REQUIRE( section.if_isotropic() ); + + // True values + const Real r = DIM1(); + const Real area_true = PI*r*r; + const Real torsion_constant_true = PI*pow(r, 4.0)/2.0; + const Real first_area_moment_z_true = area_true * offset_y(); + const Real first_area_moment_y_true = area_true * offset_z(); + const Real Izzc_true = PI*pow(r, 4.0)/4.0; + const Real Iyyc_true = PI*pow(r, 4.0)/4.0; + const Real Izyc_true = 0.0; + const Real Ipc_true = PI*pow(r, 4.0)/2.0; + const Real second_area_moment_zz_true = Izzc_true + area_true * pow(offset_y(), 2.); + const Real second_area_moment_yy_true = Iyyc_true + area_true * pow(offset_z(), 2.); + const Real second_area_moment_zy_true = Izyc_true + area_true * offset_y() * offset_z(); + const Real second_area_moment_polar_true = second_area_moment_zz_true + second_area_moment_yy_true; + const Real warping_constant_true = 0.0; + const Real kappa_z_true = 8.4967018479575718e-01; + const Real kappa_y_true = 8.4967018474199052e-01; + const Real xs_true = offset_z(); + const Real ys_true = offset_y(); + const Real xc_true = offset_z(); + const Real yc_true = offset_y(); + const libMesh::Point shear_center_true(xs_true, ys_true, 0.); + const libMesh::Point centroid_true(xc_true, yc_true, 0.); + + const libMesh::Point point(4.3, -3.5, -6.7); + const Real time = 8.22; + + SECTION("set_get_bending_model") + { + // NOTE: MAST::DKT and MAST::MINDLIN are not valid options for 1D sections, even though their input is accepted. + section.set_bending_model(MAST::BERNOULLI); + section.set_bending_model(MAST::DEFAULT_BENDING); + section.set_bending_model(MAST::NO_BENDING); + section.set_bending_model(MAST::TIMOSHENKO); + + // TODO: Implement element creation for testing of getting bending_model and checking default + //REQUIRE( section.bending_model() + } + +// SECTION("quadrature_order") +// { +// section.set_bending_model(MAST::MINDLIN); +// REQUIRE( section.extra_quadrature_order(elem) == 0 ); +// +// section.set_bending_model(MAST::DKT); +// REQUIRE( section.extra_quadrature_order(elem) == 2 ); +// } + + SECTION("1D extension stiffness matrix") + { + /** + * As of Dec. 17, 2019, stiffness_A_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * stiffness_A_matrix to be obtained without any input arguments. + */ + Real area; + const MAST::FieldFunction& Area = section.A(); + Area(point, time, area); + REQUIRE( area == Approx(area_true) ); + + Real torsion_constant; + const MAST::FieldFunction& TorsionConstant = section.J(); + TorsionConstant(point, time, torsion_constant); + REQUIRE( torsion_constant == Approx(torsion_constant_true).epsilon(0.05) ); + + std::unique_ptr> extension_stiffness_mat = section.stiffness_A_matrix(); + + const libMesh::Point point(2.3, 3.1, 5.2); + const Real time = 2.34; + RealMatrixX D_sec_ext; + extension_stiffness_mat->operator()(point, time, D_sec_ext); + + libMesh::out << "D_sec_ext\n" << D_sec_ext << std::endl; + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_ext_true = RealMatrixX::Zero(2,2); + D_sec_ext_true(0,0) = E() * area_true; + D_sec_ext_true(1,1) = G * torsion_constant_true; + + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_ext); + std::vector truth = eigen_matrix_to_std_vector(D_sec_ext_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth).epsilon(0.05) ); + } + + + SECTION("1D bending section stiffness matrix") + { + /** + * As of Dec. 17, 2019, stiffness_D_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * stiffness_D_matrix to be obtained without any input arguments. + */ + RealMatrixX I; + const MAST::FieldFunction& Inertias = section.I(); + Inertias(point, time, I); + REQUIRE( I(0,1) == I(1,0) ); + Real Izz = I(0,0); + Real Iyy = I(1,1); + Real Izy = I(0,1); + REQUIRE( Izz == Approx(second_area_moment_zz_true) ); + REQUIRE( Iyy == Approx(second_area_moment_yy_true) ); + REQUIRE( Izy == Approx(second_area_moment_zy_true) ); + + std::unique_ptr> bending_stiffness_mat = section.stiffness_D_matrix(); + + const libMesh::Point point(2.3, 3.1, 5.2); + const Real time = 2.34; + RealMatrixX D_sec_bnd; + bending_stiffness_mat->operator()(point, time, D_sec_bnd); + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_bnd_true = RealMatrixX::Zero(2,2); + D_sec_bnd_true(0,0) = E() * second_area_moment_zz_true; + D_sec_bnd_true(1,1) = E() * second_area_moment_yy_true; + D_sec_bnd_true(0,1) = E() * second_area_moment_zy_true; + D_sec_bnd_true(1,0) = E() * second_area_moment_zy_true; + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_bnd); + std::vector truth = eigen_matrix_to_std_vector(D_sec_bnd_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } + + SECTION("1D extension-bending section stiffness matrix") + { + /** + * As of Dec. 17, 2019, stiffness_B_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * stiffness_B_matrix to be obtained without any input arguments. + */ + Real first_area_moment_y; + const MAST::FieldFunction& Ay = section.Ay(); + Ay(point, time, first_area_moment_y); + CHECK( first_area_moment_y == Approx(first_area_moment_y_true) ); + + Real first_area_moment_z; + const MAST::FieldFunction& Az = section.Az(); + Az(point, time, first_area_moment_z); + CHECK( first_area_moment_z == Approx(first_area_moment_z_true) ); + + std::unique_ptr> bndext_stiffness_mat = section.stiffness_B_matrix(); + + const libMesh::Point point(2.3, 3.1, 5.2); + const Real time = 2.34; + RealMatrixX D_sec_bndext; + bndext_stiffness_mat->operator()(point, time, D_sec_bndext); + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_bndext_true = RealMatrixX::Zero(2,2); + D_sec_bndext_true(0,0) = E() * first_area_moment_z_true; + D_sec_bndext_true(0,1) = E() * first_area_moment_y_true; + // TODO: Add checks for torsion bending coupling when added to MAST. + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_bndext); + std::vector truth = eigen_matrix_to_std_vector(D_sec_bndext_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } + + SECTION("1D transverse shear section stiffness matrix") + { + /** + * As of Dec. 17, 2019, transverse_shear_stiffness_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * transverse_shear_stiffness_matrix to be obtained without any input arguments. + */ + Real area; + const MAST::FieldFunction& Area = section.A(); + Area(point, time, area); + REQUIRE( area == Approx(area_true) ); + + std::unique_ptr> trans_shear_stiffness_mat = section.transverse_shear_stiffness_matrix(); + + const libMesh::Point point(2.3, 3.1, 5.2); + const Real time = 2.34; + RealMatrixX D_sec_shr; + trans_shear_stiffness_mat->operator()(point, time, D_sec_shr); + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_shr_true = RealMatrixX::Zero(2,2); + D_sec_shr_true(0,0) = G*area_true*kappa_z_true; + D_sec_shr_true(1,1) = G*area_true*kappa_y_true; + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_shr); + std::vector truth = eigen_matrix_to_std_vector(D_sec_shr_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } + + +// SECTION("1D spring section stiffness matrix") +// { +// /** +// * As of Dec. 17, 2019, spring_stiffness_matrix requires the input of an +// * MAST::ElementBase object, but does not actually use it. To get +// * around requiring the creation of such an object (and therefore +// * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, +// * and MAST::GeomElem objects as well). +// * +// * To remedy this, an additional method was added to MAST which allows +// * transverse_shear_stiffness_matrix to be obtained without any input arguments. +// */ +// std::unique_ptr> spring_stiffness_mat = section.stiffness_S_matrix(); +// +// const libMesh::Point point(2.3, 3.1, 5.2); +// const Real time = 2.34; +// RealMatrixX D_sec_spring; +// spring_stiffness_mat->operator()(point, time, D_sec_spring); +// +// Hard-coded value of the section's extension stiffness +// NOTE: Should be all zero's for non-bushing sections +// RealMatrixX D_sec_spring_true = RealMatrixX::Zero(4,6); +// +// Convert the test and truth Eigen::Matrix objects to std::vector +// since Catch2 has built in methods to compare vectors +// std::vector test = eigen_matrix_to_std_vector(D_sec_spring); +// std::vector truth = eigen_matrix_to_std_vector(D_sec_spring_true); +// +// Floating point approximations are diffcult to compare since the +// values typically aren't exactly equal due to numerical error. +// Therefore, we use the Approx comparison instead of Equals +// CHECK_THAT( test, Catch::Approx(truth) ); +// } +} diff --git a/tests/property/mast_solid_1d_section_element_property_card.cpp b/tests/property/mast_solid_1d_section_element_property_card.cpp index 98ff085b..588eeab2 100644 --- a/tests/property/mast_solid_1d_section_element_property_card.cpp +++ b/tests/property/mast_solid_1d_section_element_property_card.cpp @@ -327,6 +327,7 @@ TEST_CASE("solid_element_property_card_constant_base_sensitivity_1d", const Real delta = 1.220703125e-04; // (np.spacing(1))**(0.25) // Area Sensitivity Check + libMesh::out << "\tArea sensitivity check..." << std::endl; const MAST::FieldFunction& Area = section.A(); std::vector dA(n_s); for (uint i=0; iname() << " = " << dA[i] << "\tdA_cd = " << dA_cd[i] << std::endl; REQUIRE(dA[i] == Approx(dA_cd[i])); } // // Centroid Sensitivity Check +// libMesh::out << "\tCentroid sensitivity check..." << std::endl; // std::vector dC(n_s); // for (uint i=0; iname() << " = " << dC[i] << "\tdC_cd = " << dC_cd[i] << std::endl; // REQUIRE(dC[i](0) == Approx(dC_cd[i](0)).margin(1.49e-08) ); // REQUIRE(dC[i](1) == Approx(dC_cd[i](1)).margin(1.49e-08) ); // } + // First Area Moments Sensitivity Check + libMesh::out << "\tArea Moment Y sensitivity check..." << std::endl; const MAST::FieldFunction& Area_y = section.Ay(); std::vector dAy(n_s); for (uint i=0; iname() << " = " << dAy[i] << "\tdAy_cd = " << dAy_cd[i] << std::endl; REQUIRE(dAy[i] == Approx(dAy_cd[i])); } - + libMesh::out << "\tArea Moment Z sensitivity check..." << std::endl; const MAST::FieldFunction& Area_z = section.Az(); std::vector dAz(n_s); for (uint i=0; iname() << " = " << dAz[i] << "\tdAz_cd = " << dAz_cd[i] << std::endl; REQUIRE(dAz[i] == Approx(dAz_cd[i])); } // Second Area Moments Sensitivity Check + libMesh::out << "\tSecond Area Moments sensitivity check..." << std::endl; const MAST::FieldFunction& Inertia = section.I(); std::vector dI(n_s); for (uint i=0; iname() << " =\n" << dI[i] << "\ndI_cd = \n" << dI_cd[i] << std::endl; - + Real dIzz = dI[i](0,0); Real dIyy = dI[i](1,1); Real dIyz = dI[i](1,0); @@ -501,6 +500,7 @@ TEST_CASE("solid_element_property_card_constant_base_sensitivity_1d", // Second Area Polar Moment Sensitivity Check + libMesh::out << "\tArea Polar Moment sensitivity check..." << std::endl; const MAST::FieldFunction& PolarInertia = section.Ip(); std::vector dIp(n_s); for (uint i=0; iname() << " = " << dIp[i] << "\tdIp_cd = " << dIp_cd[i] << std::endl; REQUIRE(dIp[i] == Approx(dIp_cd[i])); } // // Shear Center Sensitivity Check +// libMesh::out << "\tShear center sensitivity check..." << std::endl; // std::vector dCs(n_s); // for (uint i=0; iname() << " = " << dCs[i] << "\tdCs_cd = " << dCs_cd[i] << std::endl; // REQUIRE(dCs[i](0) == Approx(dCs_cd[i](0)) ); // REQUIRE(dCs[i](1) == Approx(dCs_cd[i](1)) ); // } @@ -566,6 +565,7 @@ TEST_CASE("solid_element_property_card_constant_base_sensitivity_1d", // Torsion Constant Sensitivity Check // NOTE: The field function below is not made constant because currently a finite difference is used to calculate sensitivity. + libMesh::out << "\tTorsion Constant sensitivity check..." << std::endl; MAST::FieldFunction& TorsionConstant = section.J(); std::vector dJ(n_s); for (uint i=0; iname() << " = " << dJ[i] << "\tdJ_cd = " << dJ_cd[i] << std::endl; REQUIRE(dJ[i] == Approx(dJ_cd[i]).epsilon(0.1) ); // NOTE: 10% error margin due to 'exact' sensitivity being calculated using finite difference } // // Shear Coefficient Sensitivity Check +// libMesh::out << "\tShear Coefficient sensitivity check..." << std::endl; // // NOTE: The field function below is not made constant because currently a finite difference is used to calculate sensitivity. // MAST::FieldFunction& Kappa = section.Kap(); // std::vector dK(n_s); @@ -649,6 +649,7 @@ TEST_CASE("solid_element_property_card_constant_base_sensitivity_1d", // Warping Constant Sensitivity Check // NOTE: The field function below is not made constant because currently a finite difference is used to calculate sensitivity. + libMesh::out << "\tWarping Constant sensitivity check..." << std::endl; MAST::FieldFunction& WarpingConstant = section.Gam(); std::vector dW(n_s); for (uint i=0; iname() << " = " << dW[i] << "\tdW_cd = " << dW_cd[i] << std::endl; REQUIRE(dW[i] == Approx(dW_cd[i]).epsilon(0.1) ); // NOTE: 10% error margin due to 'exact' sensitivity being calculated using finite difference } From 6b2613b74f0d9fea2d927bd961147ff9bf13e8e6 Mon Sep 17 00:00:00 2001 From: David John Neiferd <13425967+JohnDN90@users.noreply.github.com> Date: Fri, 21 Feb 2020 15:28:31 -0500 Subject: [PATCH 07/27] Added BAR section property card and tests. Added missing MPI tests for ROD section. --- src/property_cards/CMakeLists.txt | 2 + ...d_1d_bar_section_element_property_card.cpp | 320 ++++ ...lid_1d_bar_section_element_property_card.h | 119 ++ tests/property/CMakeLists.txt | 160 +- ...d_1d_bar_section_element_property_card.cpp | 1519 +++++++++++++++++ 5 files changed, 2082 insertions(+), 38 deletions(-) create mode 100644 src/property_cards/solid_1d_bar_section_element_property_card.cpp create mode 100644 src/property_cards/solid_1d_bar_section_element_property_card.h create mode 100644 tests/property/mast_solid_1d_bar_section_element_property_card.cpp diff --git a/src/property_cards/CMakeLists.txt b/src/property_cards/CMakeLists.txt index 0f9c6730..bce21ed8 100644 --- a/src/property_cards/CMakeLists.txt +++ b/src/property_cards/CMakeLists.txt @@ -26,6 +26,8 @@ target_sources(mast ${CMAKE_CURRENT_LIST_DIR}/solid_1d_nparameter_section_element_property_card.h ${CMAKE_CURRENT_LIST_DIR}/solid_1d_1parameter_section_element_property_card.cpp ${CMAKE_CURRENT_LIST_DIR}/solid_1d_1parameter_section_element_property_card.h + ${CMAKE_CURRENT_LIST_DIR}/solid_1d_bar_section_element_property_card.cpp + ${CMAKE_CURRENT_LIST_DIR}/solid_1d_bar_section_element_property_card.h ${CMAKE_CURRENT_LIST_DIR}/solid_1d_rod_section_element_property_card.cpp ${CMAKE_CURRENT_LIST_DIR}/solid_1d_rod_section_element_property_card.h ${CMAKE_CURRENT_LIST_DIR}/solid_2d_section_element_property_card.cpp diff --git a/src/property_cards/solid_1d_bar_section_element_property_card.cpp b/src/property_cards/solid_1d_bar_section_element_property_card.cpp new file mode 100644 index 00000000..a8077dd7 --- /dev/null +++ b/src/property_cards/solid_1d_bar_section_element_property_card.cpp @@ -0,0 +1,320 @@ +/* + * MAST: Multidisciplinary-design Adaptation and Sensitivity Toolkit + * Copyright (C) 2013-2019 Manav Bhatia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +// MAST includes +#include "property_cards/solid_1d_nparameter_section_element_property_card.h" +#include "property_cards/solid_1d_bar_section_element_property_card.h" + + +// Rectangle (BAR in Siemens NX Nastran and Astros 21.2) +void MAST::Solid1DBarSectionProperty::calcA(Real& DIM1, Real& DIM2, Real& A){ + A = DIM1*DIM2; +} + +void MAST::Solid1DBarSectionProperty::calcdA(Real& DIM1, Real& DIM2, Real& dDIM1, Real& dDIM2, Real& dA){ + dA = DIM1*dDIM2+DIM2*dDIM1; +} + +void MAST::Solid1DBarSectionProperty::calcIz(Real& DIM1, Real& DIM2, Real& Iz){ + Iz = (DIM1*(DIM2*DIM2*DIM2))/1.2E+1; +} + +void MAST::Solid1DBarSectionProperty::calcdIz(Real& DIM1, Real& DIM2, Real& dDIM1, Real& dDIM2, Real& dIz){ + dIz = ((DIM2*DIM2*DIM2)*dDIM1)/1.2E+1+(DIM1*(DIM2*DIM2)*dDIM2)/4.0; +} + +void MAST::Solid1DBarSectionProperty::calcIy(Real& DIM1, Real& DIM2, Real& Iy){ + Iy = ((DIM1*DIM1*DIM1)*DIM2)/1.2E+1; +} + +void MAST::Solid1DBarSectionProperty::calcdIy(Real& DIM1, Real& DIM2, Real& dDIM1, Real& dDIM2, Real& dIy){ + dIy = ((DIM1*DIM1*DIM1)*dDIM2)/1.2E+1+((DIM1*DIM1)*DIM2*dDIM1)/4.0; +} + +void MAST::Solid1DBarSectionProperty::calcIp(Real& DIM1, Real& DIM2, Real& Ip){ + Ip = (DIM1*DIM2*(DIM1*DIM1+DIM2*DIM2))/1.2E+1; +} + +void MAST::Solid1DBarSectionProperty::calcdIp(Real& DIM1, Real& DIM2, Real& dDIM1, Real& dDIM2, Real& dIp){ + dIp = (DIM1*dDIM2*(DIM1*DIM1+(DIM2*DIM2)*3.0))/1.2E+1+(DIM2*dDIM1*((DIM1*DIM1)*3.0+DIM2*DIM2))/1.2E+1; +} + +void MAST::Solid1DBarSectionProperty::calcJ1(Real& DIM1, Real& DIM2, Real& J1){ + J1 = (1.0/(DIM1*DIM1*DIM1*DIM1)*(DIM2*DIM2*DIM2)*((DIM1*DIM1*DIM1*DIM1)*DIM2*-2.52E+2+(DIM1*DIM1*DIM1*DIM1*DIM1)*4.0E+2+(DIM2*DIM2*DIM2*DIM2*DIM2)*2.1E+1))/1.2E+3; +} + +void MAST::Solid1DBarSectionProperty::calcdJ1(Real& DIM1, Real& DIM2, Real& dDIM1, Real& dDIM2, Real& dJ1){ + dJ1 = (1.0/(DIM1*DIM1*DIM1*DIM1*DIM1)*(DIM2*DIM2*DIM2)*dDIM1*((DIM1*DIM1*DIM1*DIM1*DIM1)*1.0E+2-(DIM2*DIM2*DIM2*DIM2*DIM2)*2.1E+1))/3.0E+2+(1.0/(DIM1*DIM1*DIM1*DIM1)*(DIM2*DIM2)*dDIM2*((DIM1*DIM1*DIM1*DIM1)*DIM2*-4.2E+1+(DIM1*DIM1*DIM1*DIM1*DIM1)*5.0E+1+(DIM2*DIM2*DIM2*DIM2*DIM2)*7.0))/5.0E+1; +} + +void MAST::Solid1DBarSectionProperty::calcJ2(Real& DIM1, Real& DIM2, Real& J2){ + J2 = ((DIM1*DIM1*DIM1)*1.0/(DIM2*DIM2*DIM2*DIM2)*(DIM1*(DIM2*DIM2*DIM2*DIM2)*-2.52E+2+(DIM1*DIM1*DIM1*DIM1*DIM1)*2.1E+1+(DIM2*DIM2*DIM2*DIM2*DIM2)*4.0E+2))/1.2E+3; +} + +void MAST::Solid1DBarSectionProperty::calcdJ2(Real& DIM1, Real& DIM2, Real& dDIM1, Real& dDIM2, Real& dJ2){ + dJ2 = (DIM1*DIM1*DIM1)*1.0/(DIM2*DIM2*DIM2*DIM2*DIM2)*dDIM2*((DIM1*DIM1*DIM1*DIM1*DIM1)*2.1E+1-(DIM2*DIM2*DIM2*DIM2*DIM2)*1.0E+2)*(-1.0/3.0E+2)+((DIM1*DIM1)*1.0/(DIM2*DIM2*DIM2*DIM2)*dDIM1*(DIM1*(DIM2*DIM2*DIM2*DIM2)*-4.2E+1+(DIM1*DIM1*DIM1*DIM1*DIM1)*7.0+(DIM2*DIM2*DIM2*DIM2*DIM2)*5.0E+1))/5.0E+1; +} + +void MAST::Solid1DBarSectionProperty::calcJ(Real& DIM1, Real& DIM2, Real& J){ + if (DIM1>DIM2) + { + MAST::Solid1DBarSectionProperty::calcJ1(DIM1, DIM2, J); + } + else + { + MAST::Solid1DBarSectionProperty::calcJ2(DIM1, DIM2, J); + } +} + + +void MAST::Solid1DBarSectionProperty::calcdJ(Real& DIM1, Real& DIM2, Real& dDIM1, Real& dDIM2, Real& dJ){ + if (DIM1>DIM2) + { + MAST::Solid1DBarSectionProperty::calcdJ1(DIM1, DIM2, dDIM1, dDIM2, dJ); + } + else + { + MAST::Solid1DBarSectionProperty::calcdJ2(DIM1, DIM2, dDIM1, dDIM2, dJ); + } +} + + +const std::vector +MAST::Solid1DBarSectionElementPropertyCard::get_geom_points(const libMesh::Point& p, const Real t, const uint n) const +{ + const MAST::FieldFunction + &DIM1 = this->get >("DIM1"), + &DIM2 = this->get >("DIM2"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real DIM1v, DIM2v, offset_y, offset_z; + DIM1(p, t, DIM1v); DIM2(p, t, DIM2v); + hy_off(p, t, offset_y); hz_off(p, t, offset_z); + + libMesh::Point offset(offset_z, offset_y); + + std::vector points = { + libMesh::Point(-0.5*DIM1v, -0.5*DIM2v) + offset, + libMesh::Point( 0.5*DIM1v, -0.5*DIM2v) + offset, + libMesh::Point( 0.5*DIM1v, 0.5*DIM2v) + offset, + libMesh::Point(-0.5*DIM1v, 0.5*DIM2v) + offset + }; + + return points; +} + + +const std::vector +MAST::Solid1DBarSectionElementPropertyCard::get_geom_points_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, const uint n) const +{ + const MAST::FieldFunction + &DIM1 = this->get >("DIM1"), + &DIM2 = this->get >("DIM2"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real DIM1v, DIM2v, offset_y, offset_z; + DIM1(p, t, DIM1v); DIM2(p, t, DIM2v); + hy_off(p, t, offset_y); hz_off(p, t, offset_z); + + libMesh::Point offset(offset_z, offset_y); + + Real dDIM1v, dDIM2v, doffset_y, doffset_z; + DIM1.derivative(f, p, t, dDIM1v); + DIM2.derivative(f, p, t, dDIM2v); + hy_off.derivative(f, p, t, doffset_y); + hz_off.derivative(f, p, t, doffset_z); + + libMesh::Point doffset(doffset_z, doffset_y); + + std::vector points = { + libMesh::Point(-0.5*DIM1v, -0.5*DIM2v) + offset, + libMesh::Point(0.5*DIM1v, -0.5*DIM2v) + offset, + libMesh::Point(0.5*DIM1v, 0.5*DIM2v) + offset, + libMesh::Point(-0.5*DIM1v, 0.5*DIM2v) + offset + }; + + std::vector dpoints = { + libMesh::Point(-0.5*dDIM1v, -0.5*dDIM2v) + doffset, + libMesh::Point(0.5*dDIM1v, -0.5*dDIM2v) + doffset, + libMesh::Point(0.5*dDIM1v, 0.5*dDIM2v) + doffset, + libMesh::Point(-0.5*dDIM1v, 0.5*dDIM2v) + doffset + }; + + return dpoints; +} + + +const libMesh::Point +MAST::Solid1DBarSectionElementPropertyCard::get_centroid(const libMesh::Point& p, const Real t) const +{ + return cross_section->get_centroid(p, t); +} + + +const libMesh::Point +MAST::Solid1DBarSectionElementPropertyCard::get_shear_center(const libMesh::Point& p, const Real t) const +{ + return cross_section->get_shear_center(p, t); +} + + +const libMesh::Point +MAST::Solid1DBarSectionElementPropertyCard::get_centroid_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t) const +{ + return cross_section->get_centroid_derivative(f, p, t); +} + + +// const libMesh::Point +// MAST::Solid1DBarSectionElementPropertyCard::get_shear_center_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t) const +// { +// return cross_section->get_shear_center_derivative(f, p, t); +// } + + +const libMesh::Point +MAST::Solid1DBarSectionElementPropertyCard::get_shear_center_derivative(MAST::FunctionBase& f, const libMesh::Point& p, const Real t) +{ + return cross_section->get_shear_center_derivative(f, p, t); +} + + +const std::vector +MAST::Solid1DBarSectionElementPropertyCard::get_stress_points(const libMesh::Point& p, const Real t, const libMesh::Point ps) const +{ + // Ordered C, D, E, F as defined in MSC Nastran manual (See PBARL or PBEAML) + const MAST::FieldFunction + &DIM1 = this->get >("DIM1"), + &DIM2 = this->get >("DIM2"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real DIM1v, DIM2v, offset_y, offset_z; + DIM1(p, t, DIM1v); DIM2(p, t, DIM2v); + hy_off(p, t, offset_y); hz_off(p, t, offset_z); + + libMesh::Point offset(offset_z, offset_y); + + // Points Relative to Point ps + std::vector points = { + libMesh::Point(0.5*DIM1v, 0.5*DIM2v) + offset - ps, + libMesh::Point(0.5*DIM1v, -0.5*DIM2v) + offset - ps, + libMesh::Point(-0.5*DIM1v, -0.5*DIM2v) + offset - ps, + libMesh::Point(-0.5*DIM1v, 0.5*DIM2v) + offset - ps + }; + + return points; +}; + + +const std::vector +MAST::Solid1DBarSectionElementPropertyCard::get_stress_points_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, const libMesh::Point dps) const +{ + // Ordered C, D, E, F as defined in MSC Nastran manual (See PBARL or PBEAML) + const MAST::FieldFunction + &DIM1 = this->get >("DIM1"), + &DIM2 = this->get >("DIM2"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real DIM1v, DIM2v, offset_y, offset_z; + DIM1(p, t, DIM1v); DIM2(p, t, DIM2v); + hy_off(p, t, offset_y); hz_off(p, t, offset_z); + + libMesh::Point offset(offset_z, offset_y); + + Real dDIM1v, dDIM2v, doffset_y, doffset_z; + DIM1.derivative(f, p, t, dDIM1v); + DIM2.derivative(f, p, t, dDIM2v); + hy_off.derivative(f, p, t, doffset_y); + hz_off.derivative(f, p, t, doffset_z); + + libMesh::Point doffset(doffset_z, doffset_y); + + // Derivative of Stress Points Relative to ps + // FIXME: Need to account for changes in ps, i.e. when ps is centroid or shear center + std::vector points = { + libMesh::Point( 0.5*dDIM1v, 0.5*dDIM2v) + doffset - dps, + libMesh::Point( 0.5*dDIM1v, -0.5*dDIM2v) + doffset - dps, + libMesh::Point(-0.5*dDIM1v, -0.5*dDIM2v) + doffset - dps, + libMesh::Point(-0.5*dDIM1v, 0.5*dDIM2v) + doffset - dps + }; + + return points; +}; + + +void MAST::Solid1DBarSectionElementPropertyCard::init(const libMesh::LibMeshInit& init) { + + libmesh_assert(!_initialized); + + MAST::FieldFunction + &DIM1 = this->get >("DIM1"), + &DIM2 = this->get >("DIM2"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + // Check that dimensions are physically correct + Real DIM1v, DIM2v; + DIM1(DIM1v); DIM2(DIM2v); + if (DIM1v<=0){ + libmesh_error_msg("DIM1<=0"); + } + else if (DIM2v<=0){ + libmesh_error_msg("DIM2<=0"); + } + + // Create a cross section model of this section + cross_section.reset(new MAST::CrossSection(init, 3500, *this, libMesh::TRI6)); + + _A.reset(new MAST::Solid1DnParameterSectionProperty::Area(*cross_section)); + + _Ay.reset(new MAST::Solid1DnParameterSectionProperty::AreaYMoment(*cross_section)); + + _Az.reset(new MAST::Solid1DnParameterSectionProperty::AreaZMoment(*cross_section)); + + _AI.reset(new MAST::Solid1DnParameterSectionProperty::AreaInertiaMatrix(*cross_section)); + + _Ip.reset(new MAST::Solid1DnParameterSectionProperty::PolarInertia(*cross_section)); + + _J.reset(new MAST::Solid1DnParameterSectionProperty::TorsionalConstant(*cross_section)); + + _Kappa.reset(new MAST::Solid1DnParameterSectionProperty::ShearCoefficientMatrix(*cross_section)); + + _Gamma.reset(new MAST::Solid1DnParameterSectionProperty::WarpingConstant(*cross_section)); + + _initialized = true; +} + +void MAST::Solid1DBarSectionElementPropertyCard::create_cross_section( + const libMesh::LibMeshInit& init, const uint n_target_elems, + const libMesh::ElemType element_type) +{ + cross_section.reset(new MAST::CrossSection(init, n_target_elems, + *this, element_type)); +} + + +void MAST::Solid1DBarSectionElementPropertyCard::calculate_properties_pilkey() +{ + cross_section->calculate_geometric_properties(); + cross_section->calculate_warping_properties(); +} diff --git a/src/property_cards/solid_1d_bar_section_element_property_card.h b/src/property_cards/solid_1d_bar_section_element_property_card.h new file mode 100644 index 00000000..b58e673d --- /dev/null +++ b/src/property_cards/solid_1d_bar_section_element_property_card.h @@ -0,0 +1,119 @@ +/* + * MAST: Multidisciplinary-design Adaptation and Sensitivity Toolkit + * Copyright (C) 2013-2019 Manav Bhatia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * +// * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __mast__solid_1d_bar_section_element_property_card__ +#define __mast__solid_1d_bar_section_element_property_card__ + + +// MAST includes +#include "property_cards/solid_1d_nparameter_section_element_property_card.h" +#include "property_cards/cross_section_property_pilkey.h" + +// Annulus (TUBE in Siemens NX Nastran and Astros 21.2) +namespace MAST{ + namespace Solid1DBarSectionProperty{ + void calcA(Real& DIM1, Real& DIM2, Real& A); + + void calcdA(Real& DIM1, Real& DIM2, Real& dDIM1, Real& dDIM2, Real& dA); + + void calcIz(Real& DIM1, Real& DIM2, Real& Iz); + + void calcdIz(Real& DIM1, Real& DIM2, Real& dDIM1, Real& dDIM2, Real& dIz); + + void calcIy(Real& DIM1, Real& DIM2, Real& Iy); + + void calcdIy(Real& DIM1, Real& DIM2, Real& dDIM1, Real& dDIM2, Real& dIy); + + void calcIp(Real& DIM1, Real& DIM2, Real& Ip); + + void calcdIp(Real& DIM1, Real& DIM2, Real& dDIM1, Real& dDIM2, Real& dIp); + + void calcJ1(Real& DIM1, Real& DIM2, Real& J1); + + void calcdJ1(Real& DIM1, Real& DIM2, Real& dDIM1, Real& dDIM2, Real& dJ1); + + void calcJ2(Real& DIM1, Real& DIM2, Real& J2); + + void calcdJ2(Real& DIM1, Real& DIM2, Real& dDIM1, Real& dDIM2, Real& dJ2); + + void calcJ(Real& DIM1, Real& DIM2, Real& J); + + void calcdJ(Real& DIM1, Real& DIM2, Real& dDIM1, Real& dDIM2, Real& dJ); + } +} + +namespace MAST { + + class Solid1DBarSectionElementPropertyCard : public MAST::Solid1DnParameterSectionElementPropertyCard + { + public: + Solid1DBarSectionElementPropertyCard(): + MAST::Solid1DnParameterSectionElementPropertyCard() {} + + /*! + * virtual destructor + */ + virtual ~Solid1DBarSectionElementPropertyCard() { } + + virtual void init(const libMesh::LibMeshInit& init); + + virtual void create_cross_section( + const libMesh::LibMeshInit& init, + const uint n_target_elems=3500, + const libMesh::ElemType element_type=libMesh::TRI6); + + virtual void calculate_properties_pilkey(); + + virtual const std::vector get_geom_points(const libMesh::Point& p, const Real t, const uint n=201) const override; + + virtual const std::vector get_geom_points_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, const uint n=201) const override; + + virtual const libMesh::Point get_shear_center(const libMesh::Point& p, const Real t) const override; + + virtual const libMesh::Point get_shear_center_derivative(MAST::FunctionBase& f, const libMesh::Point& p, const Real t) override; + + virtual const libMesh::Point get_centroid(const libMesh::Point& p, const Real t) const override; + + virtual const libMesh::Point get_centroid_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t) const override; + + virtual const std::vector get_stress_points(const libMesh::Point& p, const Real t, const libMesh::Point ps) const override; + + virtual const std::vector get_stress_points_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, const libMesh::Point dps) const override; + + std::unique_ptr cross_section; + + const bool is_bisymmetric() const + { + return true; + } + + const bool is_symmetric_z() const + { + return true; + } + + const bool is_symmetric_y() const + { + return true; + } + }; +} + + +#endif // __mast__solid_1d_bar_section_element_property_card__ diff --git a/tests/property/CMakeLists.txt b/tests/property/CMakeLists.txt index adbaa872..48d482aa 100644 --- a/tests/property/CMakeLists.txt +++ b/tests/property/CMakeLists.txt @@ -3,6 +3,7 @@ target_sources(mast_catch_tests ${CMAKE_CURRENT_LIST_DIR}/mast_solid_1d_section_element_property_card.cpp ${CMAKE_CURRENT_LIST_DIR}/mast_solid_1d_arbitrary_section_element_property_card.cpp ${CMAKE_CURRENT_LIST_DIR}/mast_solid_1d_rod_section_element_property_card.cpp + ${CMAKE_CURRENT_LIST_DIR}/mast_solid_1d_bar_section_element_property_card.cpp ${CMAKE_CURRENT_LIST_DIR}/mast_solid_2d_section_element_property_card.cpp ${CMAKE_CURRENT_LIST_DIR}/mast_3d_isotropic_element_property_card.cpp) @@ -304,44 +305,92 @@ set_tests_properties(Arbitrary_Element_Property_Card_1D_Base_mpi ## ============================================================================ -# ## ============================================================================ -# # 1D BAR Cross Section -# add_test(NAME Bar_Element_Property_Card_1D_Base -# COMMAND mast_catch_tests "bar_element_property_card_constant_base_1d") -# set_tests_properties(Bar_Element_Property_Card_1D_Base -# PROPERTIES -# FIXTURES_REQUIRED Isotropic_Material_1D_Structural) -# -# add_test(NAME Bar_Element_Property_Card_1D_Base_Sensitivity -# COMMAND mast_catch_tests "bar_element_property_card_constant_base_sensitivity_1d") -# set_tests_properties(Bar_Element_Property_Card_1D_Base_Sensitivity -# PROPERTIES -# FIXTURES_REQUIRED Bar_Element_Property_Card_1D_Base) -# -# add_test(NAME Bar_Element_Property_Card_1D_Heat_Transfer -# COMMAND mast_catch_tests "bar_element_property_card_constant_heat_transfer_1d") -# set_tests_properties(Bar_Element_Property_Card_1D_Heat_Transfer -# PROPERTIES -# FIXTURES_REQUIRED Isotropic_Material_1D_Heat_Transfer) -# -# add_test(NAME Bar_Element_Property_Card_1D_Thermoelastic -# COMMAND mast_catch_tests "bar_element_property_card_constant_thermoelastic_1d") -# set_tests_properties(Bar_Element_Property_Card_1D_Thermoelastic -# PROPERTIES -# FIXTURES_REQUIRED Isotropic_Material_1D_Thermoelastic) -# -# add_test(NAME Bar_Element_Property_Card_1D_Structural -# COMMAND mast_catch_tests "bar_element_property_card_constant_structural_1d") -# set_tests_properties(Bar_Element_Property_Card_1D_Structural -# PROPERTIES -# FIXTURES_REQUIRED Isotropic_Material_1D_Structural) -# -# add_test(NAME Bar_Element_Property_Card_1D_Dynamic -# COMMAND mast_catch_tests "bar_element_property_card_constant_dynamic_1d") -# set_tests_properties(Bar_Element_Property_Card_1D_Dynamic -# PROPERTIES -# FIXTURES_REQUIRED Isotropic_Material_1D_Dynamic) -# ## ============================================================================ +## ============================================================================ +# 1D BAR Cross Section +add_test(NAME Bar_Element_Property_Card_1D_Base + COMMAND $ -w NoTests "bar_element_property_card_constant_base_1d") +set_tests_properties(Bar_Element_Property_Card_1D_Base + PROPERTIES + LABELS "SEQ" + FIXTURES_REQUIRED Isotropic_Material_1D_Structural) + +add_test(NAME Bar_Element_Property_Card_1D_Base_mpi + COMMAND ${MPIEXEC_EXECUTABLE} -np 2 $ -w NoTests "bar_element_property_card_constant_base_1d") +set_tests_properties(Bar_Element_Property_Card_1D_Base_mpi + PROPERTIES + LABELS "MPI" + FIXTURES_REQUIRED Isotropic_Material_1D_Structural_mpi) + +add_test(NAME Bar_Element_Property_Card_1D_Base_Sensitivity + COMMAND $ -w NoTests "bar_element_property_card_constant_base_sensitivity_1d") +set_tests_properties(Bar_Element_Property_Card_1D_Base_Sensitivity + PROPERTIES + LABELS "SEQ" + FIXTURES_REQUIRED Bar_Element_Property_Card_1D_Base) + +add_test(NAME Bar_Element_Property_Card_1D_Base_Sensitivity_mpi + COMMAND ${MPIEXEC_EXECUTABLE} -np 2 $ -w NoTests "bar_element_property_card_constant_base_sensitivity_1d") +set_tests_properties(Bar_Element_Property_Card_1D_Base_Sensitivity_mpi + PROPERTIES + LABELS "MPI" + FIXTURES_REQUIRED Bar_Element_Property_Card_1D_Base_mpi) + +add_test(NAME Bar_Element_Property_Card_1D_Heat_Transfer + COMMAND $ -w NoTests "bar_element_property_card_constant_heat_transfer_1d") +set_tests_properties(Bar_Element_Property_Card_1D_Heat_Transfer + PROPERTIES + LABELS "SEQ" + FIXTURES_REQUIRED Isotropic_Material_1D_Heat_Transfer) + +add_test(NAME Bar_Element_Property_Card_1D_Heat_Transfer_mpi + COMMAND ${MPIEXEC_EXECUTABLE} -np 2 $ -w NoTests "bar_element_property_card_constant_heat_transfer_1d") +set_tests_properties(Bar_Element_Property_Card_1D_Heat_Transfer_mpi + PROPERTIES + LABELS "MPI" + FIXTURES_REQUIRED Isotropic_Material_1D_Heat_Transfer_mpi) + +add_test(NAME Bar_Element_Property_Card_1D_Thermoelastic + COMMAND $ -w NoTests "bar_element_property_card_constant_thermoelastic_1d") +set_tests_properties(Bar_Element_Property_Card_1D_Thermoelastic + PROPERTIES + LABELS "SEQ" + FIXTURES_REQUIRED Isotropic_Material_1D_Thermoelastic) + +add_test(NAME Bar_Element_Property_Card_1D_Thermoelastic_mpi + COMMAND ${MPIEXEC_EXECUTABLE} -np 2 $ -w NoTests "bar_element_property_card_constant_thermoelastic_1d") +set_tests_properties(Bar_Element_Property_Card_1D_Thermoelastic_mpi + PROPERTIES + LABELS "MPI" + FIXTURES_REQUIRED Isotropic_Material_1D_Thermoelastic_mpi) + +add_test(NAME Bar_Element_Property_Card_1D_Structural + COMMAND $ -w NoTests "bar_element_property_card_constant_structural_1d") +set_tests_properties(Bar_Element_Property_Card_1D_Structural + PROPERTIES + LABELS "SEQ" + FIXTURES_REQUIRED Isotropic_Material_1D_Structural) + +add_test(NAME Bar_Element_Property_Card_1D_Structural_mpi + COMMAND ${MPIEXEC_EXECUTABLE} -np 2 $ -w NoTests "bar_element_property_card_constant_structural_1d") +set_tests_properties(Bar_Element_Property_Card_1D_Structural_mpi + PROPERTIES + LABELS "MPI" + FIXTURES_REQUIRED Isotropic_Material_1D_Structural_mpi) + +add_test(NAME Bar_Element_Property_Card_1D_Dynamic + COMMAND $ -w NoTests "bar_element_property_card_constant_dynamic_1d") +set_tests_properties(Bar_Element_Property_Card_1D_Dynamic + PROPERTIES + LABELS "SEQ" + FIXTURES_REQUIRED Isotropic_Material_1D_Dynamic) + +add_test(NAME Bar_Element_Property_Card_1D_Dynamic_mpi + COMMAND ${MPIEXEC_EXECUTABLE} -np 2 $ -w NoTests "bar_element_property_card_constant_dynamic_1d") +set_tests_properties(Bar_Element_Property_Card_1D_Dynamic_mpi + PROPERTIES + LABELS "MPI" + FIXTURES_REQUIRED Isotropic_Material_1D_Dynamic_mpi) +## ============================================================================ ## ============================================================================ @@ -367,6 +416,13 @@ set_tests_properties(Rod_Element_Property_Card_1D_Base_Sensitivity LABELS "SEQ" FIXTURES_REQUIRED Rod_Element_Property_Card_1D_Base) +add_test(NAME Rod_Element_Property_Card_1D_Base_Sensitivity_mpi + COMMAND ${MPIEXEC_EXECUTABLE} -np 2 $ -w NoTests "rod_element_property_card_constant_base_sensitivity_1d") +set_tests_properties(Rod_Element_Property_Card_1D_Base_Sensitivity_mpi + PROPERTIES + LABELS "MPI" + FIXTURES_REQUIRED Rod_Element_Property_Card_1D_Base_mpi) + add_test(NAME Rod_Element_Property_Card_1D_Heat_Transfer COMMAND $ -w NoTests "rod_element_property_card_constant_heat_transfer_1d") set_tests_properties(Rod_Element_Property_Card_1D_Heat_Transfer @@ -374,6 +430,13 @@ set_tests_properties(Rod_Element_Property_Card_1D_Heat_Transfer LABELS "SEQ" FIXTURES_REQUIRED Isotropic_Material_1D_Heat_Transfer) +add_test(NAME Rod_Element_Property_Card_1D_Heat_Transfer_mpi + COMMAND ${MPIEXEC_EXECUTABLE} -np 2 $ -w NoTests "rod_element_property_card_constant_heat_transfer_1d") +set_tests_properties(Rod_Element_Property_Card_1D_Heat_Transfer_mpi + PROPERTIES + LABELS "MPI" + FIXTURES_REQUIRED Isotropic_Material_1D_Heat_Transfer_mpi) + add_test(NAME Rod_Element_Property_Card_1D_Thermoelastic COMMAND $ -w NoTests "rod_element_property_card_constant_thermoelastic_1d") set_tests_properties(Rod_Element_Property_Card_1D_Thermoelastic @@ -381,6 +444,13 @@ set_tests_properties(Rod_Element_Property_Card_1D_Thermoelastic LABELS "SEQ" FIXTURES_REQUIRED Isotropic_Material_1D_Thermoelastic) +add_test(NAME Rod_Element_Property_Card_1D_Thermoelastic_mpi + COMMAND ${MPIEXEC_EXECUTABLE} -np 2 $ -w NoTests "rod_element_property_card_constant_thermoelastic_1d") +set_tests_properties(Rod_Element_Property_Card_1D_Thermoelastic_mpi + PROPERTIES + LABELS "MPI" + FIXTURES_REQUIRED Isotropic_Material_1D_Thermoelastic_mpi) + add_test(NAME Rod_Element_Property_Card_1D_Structural COMMAND $ -w NoTests "rod_element_property_card_constant_structural_1d") set_tests_properties(Rod_Element_Property_Card_1D_Structural @@ -388,12 +458,26 @@ set_tests_properties(Rod_Element_Property_Card_1D_Structural LABELS "SEQ" FIXTURES_REQUIRED Isotropic_Material_1D_Structural) +add_test(NAME Rod_Element_Property_Card_1D_Structural_mpi + COMMAND ${MPIEXEC_EXECUTABLE} -np 2 $ -w NoTests "rod_element_property_card_constant_structural_1d") +set_tests_properties(Rod_Element_Property_Card_1D_Structural_mpi + PROPERTIES + LABELS "MPI" + FIXTURES_REQUIRED Isotropic_Material_1D_Structural_mpi) + add_test(NAME Rod_Element_Property_Card_1D_Dynamic COMMAND $ -w NoTests "rod_element_property_card_constant_dynamic_1d") set_tests_properties(Rod_Element_Property_Card_1D_Dynamic PROPERTIES LABELS "SEQ" FIXTURES_REQUIRED Isotropic_Material_1D_Dynamic) + +add_test(NAME Rod_Element_Property_Card_1D_Dynamic_mpi + COMMAND ${MPIEXEC_EXECUTABLE} -np 2 $ -w NoTests "rod_element_property_card_constant_dynamic_1d") +set_tests_properties(Rod_Element_Property_Card_1D_Dynamic_mpi + PROPERTIES + LABELS "MPI" + FIXTURES_REQUIRED Isotropic_Material_1D_Dynamic_mpi) ## ============================================================================ diff --git a/tests/property/mast_solid_1d_bar_section_element_property_card.cpp b/tests/property/mast_solid_1d_bar_section_element_property_card.cpp new file mode 100644 index 00000000..aa3b68f8 --- /dev/null +++ b/tests/property/mast_solid_1d_bar_section_element_property_card.cpp @@ -0,0 +1,1519 @@ +// Catch2 includes +#include "catch.hpp" + +// libMesh includes +#include "libmesh/point.h" + +// MAST includes +#include "base/parameter.h" +#include "base/constant_field_function.h" +#include "property_cards/isotropic_material_property_card.h" +#include "property_cards/solid_1d_bar_section_element_property_card.h" + +// Custom includes +#include "test_helpers.h" + +extern libMesh::LibMeshInit* p_global_init; + + +/** + * A BAR is defined as a solid rectangular cross section defined by two + * parameters. + */ +TEST_CASE("bar_element_property_card_constant_base_1d", + "[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + + // Define Material Properties as MAST Parameters + MAST::Parameter rho("rho_param", 1420.5); // Density + MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity + MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio + MAST::Parameter kappa("kappa_param", 5.0/6.0); // Shear coefficient + MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity + MAST::Parameter k("k_param", 237.0); // Thermal Conductivity + + // Define Section Properties as MAST Parameters + MAST::Parameter thickness_y("DIM1", 3.0); // Section thickness in z-direction + MAST::Parameter thickness_z("DIM2", 0.75); // Section thickness in y-direction + MAST::Parameter offset_y("offy_param", 0.287); // Section offset in y-direction + MAST::Parameter offset_z("offz_param", 1.654); // Section offset in z-direction + + // Create field functions to dsitribute these constant parameters throughout the model + // Section Property Field Functions + MAST::ConstantFieldFunction DIM1_f("DIM1", thickness_y); + MAST::ConstantFieldFunction DIM2_f("DIM2", thickness_z); + MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); + MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); + // Material Property Field Functions + MAST::ConstantFieldFunction rho_f("rho", rho); + MAST::ConstantFieldFunction E_f("E", E); + MAST::ConstantFieldFunction nu_f("nu", nu); + MAST::ConstantFieldFunction kappa_f("kappa", kappa); + MAST::ConstantFieldFunction cp_f("cp", cp); + MAST::ConstantFieldFunction k_f("k_th", k); + + // Initialize the material + MAST::IsotropicMaterialPropertyCard material; + + // Add the material property constant field functions to the material card + material.add(rho_f); + material.add(k_f); + material.add(cp_f); + material.add(E_f); + material.add(nu_f); + material.add(kappa_f); + + // Initialize the section + MAST::Solid1DBarSectionElementPropertyCard section; + + // Add the section property constant field functions to the section card + section.add(DIM1_f); + section.add(DIM2_f); + section.add(offsety_f); + section.add(offsetz_f); + + // Add the material card to the section card + section.set_material(material); + + // Specify a section orientation point and add it to the section. + RealVectorX orientation = RealVectorX::Zero(3); + orientation(1) = 1.0; + section.y_vector() = orientation; + + // Now initialize the section + section.init(*p_global_init); + + REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional + REQUIRE( section.depends_on(thickness_y) ); + REQUIRE( section.depends_on(offset_y) ); + REQUIRE( section.depends_on(thickness_z) ); + REQUIRE( section.depends_on(offset_z) ); + REQUIRE( section.depends_on(k) ); + REQUIRE( section.depends_on(cp) ); + REQUIRE( section.depends_on(rho) ); + REQUIRE( section.if_isotropic() ); + + // True values calculated using the sectionproperties module in python BAR.py + const Real area_true = 2.2500000000000004e+00; + const Real torsion_constant_true = 3.5540414988249380e-01; + const Real first_area_moment_z_true = 6.4574999999999994e-01; + const Real first_area_moment_y_true = 3.7214999999999945e+00; + const Real second_area_moment_zz_true = 2.9079899999999986e-01; + const Real second_area_moment_yy_true = 7.8428609999999814e+00; + const Real second_area_moment_zy_true = 1.0680705000000006e+00; + const Real second_area_moment_polar_true = 8.1336599999999812e+00; + const Real Izzc_true = 1.0546874999999994e-01; + const Real Iyyc_true = 1.6875000000000009e+00; + const Real Izyc_true = 2.4424906541753444e-15; + const Real warping_constant_true = 6.1030611538894504e-02; + const Real kappa_z_true = 8.3330248143102326e-01; + const Real kappa_y_true = 5.5763491072129889e-01; + const Real xs_true = 1.6540000458463804e+00; + const Real ys_true = 2.8700000023051281e-01; + const Real xst_true = 1.6540000458463804e+00; + const Real yst_true = 2.8700000023051281e-01; + const libMesh::Point shear_center_true(xs_true, ys_true, 0.); + const libMesh::Point centroid_true(1.654, 0.287, 0.); + + // NOTE: The default 1D section is rectangular + const libMesh::Point point(4.3, -3.5, -6.7); + const Real time = 8.22; + + Real area; + const MAST::FieldFunction& Area = section.A(); + Area(point, time, area); + REQUIRE( area == Approx(area_true) ); + + Real first_area_moment_y; + const MAST::FieldFunction& Ay = section.Ay(); + Ay(point, time, first_area_moment_y); + CHECK( first_area_moment_y == Approx(first_area_moment_y_true) ); + + Real first_area_moment_z; + const MAST::FieldFunction& Az = section.Az(); + Az(point, time, first_area_moment_z); + CHECK( first_area_moment_z == Approx(first_area_moment_z_true) ); + + RealMatrixX I; + const MAST::FieldFunction& Inertias = section.I(); + Inertias(point, time, I); + REQUIRE( I(0,1) == I(1,0) ); + Real Iyy = I(1,1); + Real Izz = I(0,0); + Real Izy = I(0,1); + REQUIRE( Izz == Approx(second_area_moment_zz_true) ); + REQUIRE( Iyy == Approx(second_area_moment_yy_true) ); + REQUIRE( Izy == Approx(second_area_moment_zy_true) ); + + Real Ip; + const MAST::FieldFunction& PolarInertia = section.Ip(); + PolarInertia(point, time, Ip); + REQUIRE( Ip == Approx(second_area_moment_polar_true) ); + + const libMesh::Point p(0.5, 2.1, 1.6); + const Real t = 4.657; + RealVectorX Ic = section.cross_section->get_second_area_moments_about_centroid(p, t); + libMesh::out << "Izz = " << Ic(0) << std::endl; + libMesh::out << "Iyy = " << Ic(1) << std::endl; + REQUIRE( Ic(0) == Approx(Izzc_true) ); + REQUIRE( Ic(1) == Approx(Iyyc_true) ); + REQUIRE( Ic(2) == Approx(Izyc_true).margin(1e-09) ); + + Real torsion_constant; + const MAST::FieldFunction& TorsionConstant = section.J(); + TorsionConstant(point, time, torsion_constant); + REQUIRE( torsion_constant == Approx(torsion_constant_true)); + + Real warping_constant; + const MAST::FieldFunction& WarpingConstant = section.Gam(); + WarpingConstant(point, time, warping_constant); + REQUIRE( warping_constant == Approx(warping_constant_true) ); + + RealMatrixX shear_coefficients; + const MAST::FieldFunction& ShearCoefficientMatrix = section.Kap(); + ShearCoefficientMatrix(point, time, shear_coefficients); + REQUIRE( shear_coefficients(0,0) == Approx(kappa_z_true) ); + REQUIRE( shear_coefficients(1,1) == Approx(kappa_y_true) ); + + libMesh::Point centroid = section.cross_section->get_centroid(p, t); + REQUIRE( centroid(0) == Approx(centroid_true(0)) ); + REQUIRE( centroid(1) == Approx(centroid_true(1)) ); + + libMesh::Point shear_center = section.cross_section->get_shear_center(p, t); + REQUIRE(shear_center(0) == Approx(xs_true)); + REQUIRE(shear_center(1) == Approx(ys_true)); + + REQUIRE_FALSE( section.if_diagonal_mass_matrix() ); + + section.set_diagonal_mass_matrix(true); + REQUIRE( section.if_diagonal_mass_matrix() ); +} + + +/*! + * These sensitivity checks are performed against a 4th order accurate + * central difference approximation with a perturbation of 1.22e-04. + */ +TEST_CASE("bar_element_property_card_constant_base_sensitivity_1d", + "[1D],[isotropic],[constant],[property],[sensitivity]") +{ + const uint dim = 1; + + // Define Material Properties as MAST Parameters + MAST::Parameter rho("rho_param", 1420.5); // Density + MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity + MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio + MAST::Parameter kappa("kappa_param", 5.0/6.0); // Shear coefficient + MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity + MAST::Parameter k("k_param", 237.0); // Thermal Conductivity + + // Define Section Properties as MAST Parameters + MAST::Parameter DIM1("DIM1", 3.0); // Section thickness in z-direction + MAST::Parameter DIM2("DIM2", 0.75); // Section thickness in y-direction + MAST::Parameter offset_y("offy_param", 0.287); // Section offset in y-direction + MAST::Parameter offset_z("offz_param", 1.654); // Section offset in z-direction + + // Define Sensitivity Parameters + std::vector sens_params = {&DIM1, &DIM2}; + uint n_s = sens_params.size(); + + // Create field functions to dsitribute these constant parameters throughout the model + // Section Property Field Functions + MAST::ConstantFieldFunction DIM1_f("DIM1", DIM1); + MAST::ConstantFieldFunction DIM2_f("DIM2", DIM2); + MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); + MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); + // Material Property Field Functions + MAST::ConstantFieldFunction rho_f("rho", rho); + MAST::ConstantFieldFunction E_f("E", E); + MAST::ConstantFieldFunction nu_f("nu", nu); + MAST::ConstantFieldFunction kappa_f("kappa", kappa); + MAST::ConstantFieldFunction cp_f("cp", cp); + MAST::ConstantFieldFunction k_f("k_th", k); + + // Initialize the material + MAST::IsotropicMaterialPropertyCard material; + + // Add the material property constant field functions to the material card + material.add(rho_f); + material.add(k_f); + material.add(cp_f); + material.add(E_f); + material.add(nu_f); + material.add(kappa_f); + + // Initialize the section + MAST::Solid1DBarSectionElementPropertyCard section; + + // Add the section property constant field functions to the section card + section.add(DIM1_f); + section.add(DIM2_f); + section.add(offsety_f); + section.add(offsetz_f); + + // Add the material card to the section card + section.set_material(material); + + // Specify a section orientation point and add it to the section. + RealVectorX orientation = RealVectorX::Zero(3); + orientation(1) = 1.0; + section.y_vector() = orientation; + + // Now initialize the section + section.init(*p_global_init); + + REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional + REQUIRE( section.depends_on(DIM1) ); + REQUIRE( section.depends_on(offset_y) ); + REQUIRE( section.depends_on(DIM2) ); + REQUIRE( section.depends_on(offset_z) ); + REQUIRE( section.depends_on(k) ); + REQUIRE( section.depends_on(cp) ); + REQUIRE( section.depends_on(rho) ); + REQUIRE( section.if_isotropic() ); + + // True values calculated using the sectionproperties module in python BAR.py + const Real area_true = 2.2500000000000004e+00; + const Real torsion_constant_true = 3.5540414988249380e-01; + const Real first_area_moment_z_true = 6.4574999999999994e-01; + const Real first_area_moment_y_true = 3.7214999999999945e+00; + const Real second_area_moment_zz_true = 2.9079899999999986e-01; + const Real second_area_moment_yy_true = 7.8428609999999814e+00; + const Real second_area_moment_zy_true = 1.0680705000000006e+00; + const Real second_area_moment_polar_true = 8.1336599999999812e+00; + const Real Izzc_true = 1.0546874999999994e-01; + const Real Iyyc_true = 1.6875000000000009e+00; + const Real Izyc_true = 2.4424906541753444e-15; + const Real warping_constant_true = 6.1030611538894504e-02; + const Real kappa_z_true = 8.3330248143102326e-01; + const Real kappa_y_true = 5.5763491072129889e-01; + const Real xs_true = 1.6540000458463804e+00; + const Real ys_true = 2.8700000023051281e-01; + const Real xst_true = 1.6540000458463804e+00; + const Real yst_true = 2.8700000023051281e-01; + const libMesh::Point shear_center_true(xs_true, ys_true, 0.); + + const libMesh::Point centroid_true(1.654, 0.287); + Real stress_C_x, stress_C_y, stress_D_x, stress_D_y; + Real stress_E_x, stress_E_y, stress_F_x, stress_F_y; + + const libMesh::Point point(4.3, -3.5, -6.7); + const Real time = 8.22; + + Real dA_dDIM1, dA_dDIM2; + Real dCz_dDIM1, dCz_dDIM2; + Real dCy_dDIM1, dCy_dDIM2; + Real dQz_dDIM1, dQz_dDIM2; + Real dQy_dDIM1, dQy_dDIM2; + Real dIzz_dDIM1, dIzz_dDIM2; + Real dIyy_dDIM1, dIyy_dDIM2; + Real dIzy_dDIM1, dIzy_dDIM2; + Real dIp_dDIM1, dIp_dDIM2; + Real dIzzc_dDIM1, dIzzc_dDIM2; + Real dIyyc_dDIM1, dIyyc_dDIM2; + Real dIzyc_dDIM1, dIzyc_dDIM2; + Real dIpc_dDIM1, dIpc_dDIM2; + Real dJ_dDIM1, dJ_dDIM2; + Real dxs_dDIM1, dxs_dDIM2; + Real dys_dDIM1, dys_dDIM2; + Real dW_dDIM1, dW_dDIM2; + + Real f_h, f_2h, f_n, f_2n; + RealVectorX fv_h, fv_2h, fv_n, fv_2n; + RealMatrixX fm_h, fm_2h, fm_n, fm_2n; + + const Real delta = 1.220703125e-04; // (np.spacing(1))**(0.25) + + // Area Sensitivity Check + libMesh::out << "\tArea Sensitivity Check..." << std::endl; + const MAST::FieldFunction& Area = section.A(); + std::vector dA(n_s); + for (uint i=0; i dA_cd(n_s); + for (uint i=0; iname() << " = " << dA[i] << "\tdA_cd = " << dA_cd[i] << std::endl; + REQUIRE(dA[i] == Approx(dA_cd[i])); + } + + + // Centroid Sensitivity Check + libMesh::out << "\tCentroid Sensitivity Check..." << std::endl; + std::vector dC(n_s); + for (uint i=0; iget_centroid_derivative(*sens_params[i], point, time); + } + + libMesh::Point fp_h, fp_2h, fp_n, fp_2n; + std::vector dC_cd(n_s); + for (uint i=0; iget_centroid(point, time); + + (*sens_params[i])() += delta; + fp_2h = section.cross_section->get_centroid(point, time); + + (*sens_params[i])() -= 3.0*delta; + fp_n = section.cross_section->get_centroid(point, time); + + (*sens_params[i])() -= delta; + fp_2n = section.cross_section->get_centroid(point, time); + + (*sens_params[i])() += 2.0*delta; + + dC_cd[i] = (fp_2n - 8.*fp_n + 8*fp_h - fp_2h)/(12.*delta); + + libMesh::out << "dC_d" << sens_params[i]->name() << " = " << dC[i] << "\tdC_cd = " << dC_cd[i] << std::endl; + REQUIRE(dC[i](0) == Approx(dC_cd[i](0)).margin(1.49e-08) ); + REQUIRE(dC[i](1) == Approx(dC_cd[i](1)).margin(1.49e-08) ); + } + + // First Area Moments Sensitivity Check + libMesh::out << "\tFirst Area Moment Y Sensitivity Check..." << std::endl; + const MAST::FieldFunction& Area_y = section.Ay(); + std::vector dAy(n_s); + for (uint i=0; i dAy_cd(n_s); + for (uint i=0; iname() << " = " << dAy[i] << "\tdAy_cd = " << dAy_cd[i] << std::endl; + REQUIRE(dAy[i] == Approx(dAy_cd[i])); + } + + libMesh::out << "\tFirst Area Moment Z Sensitivity Check..." << std::endl; + const MAST::FieldFunction& Area_z = section.Az(); + std::vector dAz(n_s); + for (uint i=0; i dAz_cd(n_s); + for (uint i=0; iname() << " = " << dAz[i] << "\tdAz_cd = " << dAz_cd[i] << std::endl; + REQUIRE(dAz[i] == Approx(dAz_cd[i])); + } + + + // Second Area Moments Sensitivity Check + libMesh::out << "\tSecond Area Moments Sensitivity Check..." << std::endl; + const MAST::FieldFunction& Inertia = section.I(); + std::vector dI(n_s); + for (uint i=0; i dI_cd(n_s); + for (uint i=0; iname() << " =\n" << dI[i] << "\ndI_cd = \n" << dI_cd[i] << std::endl; + + Real dIzz = dI[i](0,0); + Real dIyy = dI[i](1,1); + Real dIyz = dI[i](1,0); + Real dIzy = dI[i](0,1); + + Real dIzz_cd = dI_cd[i](0,0); + Real dIyy_cd = dI_cd[i](1,1); + Real dIyz_cd = dI_cd[i](1,0); + Real dIzy_cd = dI_cd[i](0,1); + + REQUIRE(dIzz == Approx(dIzz_cd)); + REQUIRE(dIyy == Approx(dIyy_cd)); + REQUIRE(dIyz == Approx(dIyz_cd)); + REQUIRE(dIzy == Approx(dIzy_cd)); + REQUIRE(dIyz == dIzy); // symmetry check + } + + + // Second Area Polar Moment Sensitivity Check + libMesh::out << "\tSecond Area Polar Moment Sensitivity Check..." << std::endl; + const MAST::FieldFunction& PolarInertia = section.Ip(); + std::vector dIp(n_s); + for (uint i=0; i dIp_cd(n_s); + for (uint i=0; iname() << " = " << dIp[i] << "\tdIp_cd = " << dIp_cd[i] << std::endl; + REQUIRE(dIp[i] == Approx(dIp_cd[i])); + } + + +// // Shear Center Sensitivity Check +// libMesh::out << "\tShear Center Sensitivity Check..." << std::endl; +// std::vector dCs(n_s); +// for (uint i=0; iget_shear_center_derivative(*sens_params[i], point, time); +// } +// +// std::vector dCs_cd(n_s); +// for (uint i=0; iget_shear_center(point, time); +// +// (*sens_params[i])() += delta; +// fp_2h = section.cross_section->get_shear_center(point, time); +// +// (*sens_params[i])() -= 3.0*delta; +// fp_n = section.cross_section->get_shear_center(point, time); +// +// (*sens_params[i])() -= delta; +// fp_2n = section.cross_section->get_shear_center(point, time); +// +// (*sens_params[i])() += 2.0*delta; +// +// dCs_cd[i] = (fp_2n - 8.*fp_n + 8.*fp_h - fp_2h)/(12.*delta); +// +// libMesh::out << "dCs_d" << sens_params[i]->name() << " = " << dCs[i] << "\tdCs_cd = " << dCs_cd[i] << std::endl; +// REQUIRE(dCs[i](0) == Approx(dCs_cd[i](0)) ); +// REQUIRE(dCs[i](1) == Approx(dCs_cd[i](1)) ); +// } + + + // Torsion Constant Sensitivity Check + // NOTE: The field function below is not made constant because currently a finite difference is used to calculate sensitivity. + libMesh::out << "\tTorsion Constant Sensitivity Check..." << std::endl; + MAST::FieldFunction& TorsionConstant = section.J(); + std::vector dJ(n_s); + for (uint i=0; i dJ_cd(n_s); + for (uint i=0; iname() << " = " << dJ[i] << "\tdJ_cd = " << dJ_cd[i] << std::endl; + REQUIRE(dJ[i] == Approx(dJ_cd[i]).epsilon(0.1) ); + // NOTE: 10% error margin due to 'exact' sensitivity being calculated using finite difference + } + + + // Shear Coefficient Sensitivity Check + // NOTE: The field function below is not made constant because currently a finite difference is used to calculate sensitivity. + libMesh::out << "\tShear Coefficients Sensitivity Check..." << std::endl; + MAST::FieldFunction& Kappa = section.Kap(); + std::vector dK(n_s); + for (uint i=0; i dK_cd(n_s); + for (uint i=0; iname() << " =\n" << dK[i] << "\ndK_cd = \n" << dK_cd[i] << std::endl; + + Real dKzz = dK[i](0,0); + Real dKyy = dK[i](1,1); + Real dKyz = dK[i](1,0); + Real dKzy = dK[i](0,1); + + Real dKzz_cd = dK_cd[i](0,0); + Real dKyy_cd = dK_cd[i](1,1); + Real dKyz_cd = dK_cd[i](1,0); + Real dKzy_cd = dK_cd[i](0,1); + + REQUIRE(dKzz == Approx(dKzz_cd).epsilon(0.1)); + REQUIRE(dKyy == Approx(dKyy_cd).epsilon(0.1)); + //REQUIRE(dKyz == Approx(dKyz_cd).epsilon(0.1)); // Comparison can be hard when this is nearly infinite (~1e+13) + //REQUIRE(dKzy == Approx(dKzy_cd).epsilon(0.1)); // Comparison can be hard when this is nearly infinite (~1e+13) + // NOTE: 10% error margin due to 'exact' sensitivity being calculated using finite difference + REQUIRE(dKyz == dKzy); // symmetry check + } + + + // Warping Constant Sensitivity Check + // NOTE: The field function below is not made constant because currently a finite difference is used to calculate sensitivity. + libMesh::out << "\tWarping Constant Sensitivity Check..." << std::endl; + MAST::FieldFunction& WarpingConstant = section.Gam(); + std::vector dW(n_s); + for (uint i=0; i dW_cd(n_s); + for (uint i=0; iname() << " = " << dW[i] << "\tdW_cd = " << dW_cd[i] << std::endl; + REQUIRE(dW[i] == Approx(dW_cd[i]).epsilon(0.1) ); + // NOTE: 10% error margin due to 'exact' sensitivity being calculated using finite difference + } +} + + +TEST_CASE("bar_element_property_card_constant_heat_transfer_1d", + "[heat_transfer],[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + + // Define Material Properties as MAST Parameters + MAST::Parameter rho("rho_param", 1420.5); // Density + MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity + MAST::Parameter k("k_param", 237.0); // Thermal Conductivity + + // Define Section Properties as MAST Parameters + MAST::Parameter thickness_y("DIM1", 0.04); // Section thickness in z-direction + MAST::Parameter thickness_z("DIM2", 0.06); // Section thickness in y-direction + MAST::Parameter offset_y("offy_param", 0.035); // Section offset in y-direction + MAST::Parameter offset_z("offz_param", 0.026); // Section offset in z-direction + + // Create field functions to dsitribute these constant parameters throughout the model + // Section Property Field Functions + MAST::ConstantFieldFunction DIM1_f("DIM1", thickness_y); + MAST::ConstantFieldFunction DIM2_f("DIM2", thickness_z); + MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); + MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); + // Material Property Field Functions + MAST::ConstantFieldFunction rho_f("rho", rho); + MAST::ConstantFieldFunction cp_f("cp", cp); + MAST::ConstantFieldFunction k_f("k_th", k); + + // Initialize the material + MAST::IsotropicMaterialPropertyCard material; + + // Add the material property constant field functions to the material card + material.add(rho_f); + material.add(k_f); + material.add(cp_f); + + // Initialize the section + MAST::Solid1DBarSectionElementPropertyCard section; + + // Add the section property constant field functions to the section card + section.add(DIM1_f); + section.add(DIM2_f); + section.add(offsety_f); + section.add(offsetz_f); + + // Add the material card to the section card + section.set_material(material); + +// // Specify a section orientation point and add it to the section. +// RealVectorX orientation = RealVectorX::Zero(3); +// orientation(1) = 1.0; +// section.y_vector() = orientation; + + // Now initialize the section + section.init(*p_global_init); + + REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional + REQUIRE( section.depends_on(thickness_y) ); + REQUIRE( section.depends_on(offset_y) ); + REQUIRE( section.depends_on(thickness_z) ); + REQUIRE( section.depends_on(offset_z) ); + REQUIRE( section.depends_on(k) ); + REQUIRE( section.depends_on(cp) ); + REQUIRE( section.depends_on(rho) ); + REQUIRE( section.if_isotropic() ); + + // True values calculated using the sectionproperties module in python BAR.py + Real area_true = 2.3999999999999963e-03; + + // NOTE: The default 1D section is rectangular + const libMesh::Point point(4.3, -3.5, -6.7); + const Real time = 8.22; + + Real area; + const MAST::FieldFunction& Area = section.A(); + Area(point, time, area); + REQUIRE( area == Approx(area_true) ); + + + SECTION("1D section thermal conductance matrix") + { + /** + * As of Dec. 17, 2019, inertia_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * inertia_matrix to be obtained without any input arguments. + */ + std::unique_ptr> conduct_mat = section.thermal_conductance_matrix(); + + const libMesh::Point point(2.3, 3.1, 5.2); + const Real time = 2.34; + RealMatrixX D_sec_conduc; + conduct_mat->operator()(point, time, D_sec_conduc); + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_conduc_true = RealMatrixX::Zero(1,1); + D_sec_conduc_true(0,0) = 237.0*0.06*0.04; + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_conduc); + std::vector truth = eigen_matrix_to_std_vector(D_sec_conduc_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } + + SECTION("1D section thermal capacitance matrix") + { + /** + * As of Dec. 17, 2019, inertia_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * inertia_matrix to be obtained without any input arguments. + */ + std::unique_ptr> capaci_mat = section.thermal_capacitance_matrix(); + + const libMesh::Point point(2.3, 3.1, 5.2); + const Real time = 2.34; + RealMatrixX D_sec_capac; + capaci_mat->operator()(point, time, D_sec_capac); + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_capac_true = RealMatrixX::Zero(1,1); + D_sec_capac_true(0,0) = 908.0*1420.5*0.06*0.04; + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_capac); + std::vector truth = eigen_matrix_to_std_vector(D_sec_capac_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } +} + + +TEST_CASE("bar_element_property_card_constant_thermoelastic_1d", + "[thermoelastic],[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + + // Define Material Properties as MAST Parameters + MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity + MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio + MAST::Parameter alpha("alpha_param", 5.43e-05); // Coefficient of thermal expansion + + // Define Section Properties as MAST Parameters + MAST::Parameter thickness_y("DIM1", 0.04); // Section thickness in z-direction + MAST::Parameter thickness_z("DIM2", 0.06); // Section thickness in y-direction + MAST::Parameter offset_y("offy_param", 0.035); // Section offset in y-direction + MAST::Parameter offset_z("offz_param", 0.026); // Section offset in z-direction + + // Create field functions to dsitribute these constant parameters throughout the model + // Section Property Field Functions + MAST::ConstantFieldFunction DIM1_f("DIM1", thickness_y); + MAST::ConstantFieldFunction DIM2_f("DIM2", thickness_z); + MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); + MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); + // Material Property Field Functions + MAST::ConstantFieldFunction E_f("E", E); + MAST::ConstantFieldFunction nu_f("nu", nu); + MAST::ConstantFieldFunction alpha_f("alpha_expansion", alpha); + + // Initialize the material + MAST::IsotropicMaterialPropertyCard material; + + // Add the material property constant field functions to the material card + material.add(E_f); + material.add(nu_f); + material.add(alpha_f); + + // Initialize the section + MAST::Solid1DBarSectionElementPropertyCard section; + + // Add the section property constant field functions to the section card + section.add(DIM1_f); + section.add(DIM2_f); + section.add(offsety_f); + section.add(offsetz_f); + + // Add the material card to the section card + section.set_material(material); + + // Specify a section orientation point and add it to the section. + RealVectorX orientation = RealVectorX::Zero(3); + orientation(1) = 1.0; + section.y_vector() = orientation; + + // Now initialize the section + section.init(*p_global_init); + + REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional + REQUIRE( section.depends_on(thickness_y) ); + REQUIRE( section.depends_on(offset_y) ); + REQUIRE( section.depends_on(thickness_z) ); + REQUIRE( section.depends_on(offset_z) ); + REQUIRE( section.depends_on(E) ); + REQUIRE( section.depends_on(nu) ); + REQUIRE( section.depends_on(alpha) ); + REQUIRE( section.if_isotropic() ); + + // True values calculated using the sectionproperties module in python BAR.py + // NOTE: The default 1D section is rectangular + const libMesh::Point point(4.3, -3.5, -6.7); + const Real time = 8.22; + + Real area_true = 2.3999999999999963e-03; + Real first_area_moment_y_true = 6.2399999999999741e-05; + Real first_area_moment_z_true = 8.3999999999999887e-05; + + SECTION("1D thermal expansion A matrix") + { + /** + * As of Dec. 17, 2019, thermal_expansion_A_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * thermal_expansion_A_matrix to be obtained without any input arguments. + */ + + Real area; + const MAST::FieldFunction& Area = section.A(); + Area(point, time, area); + CHECK( area == Approx(area_true) ); + + std::unique_ptr> texp_A_mat = section.thermal_expansion_A_matrix(); + + const libMesh::Point point(2.3, 3.1, 5.2); + const Real time = 2.34; + RealMatrixX D_sec_texpA; + texp_A_mat->operator()(point, time, D_sec_texpA); + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_texpA_true = RealMatrixX::Zero(2,1); + D_sec_texpA_true(0,0) = 9383.04; + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_texpA); + std::vector truth = eigen_matrix_to_std_vector(D_sec_texpA_true); + + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } + + SECTION("1D thermal expansion B matrix") + { + /** + * As of Dec. 17, 2019, thermal_expansion_B_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * thermal_expansion_B_matrix to be obtained without any input arguments. + */ + + Real first_area_moment_y; + const MAST::FieldFunction& Ay = section.Ay(); + Ay(point, time, first_area_moment_y); + CHECK( first_area_moment_y == Approx(first_area_moment_y_true) ); + + Real first_area_moment_z; + const MAST::FieldFunction& Az = section.Az(); + Az(point, time, first_area_moment_z); + CHECK( first_area_moment_z == Approx(first_area_moment_z_true) ); + + std::unique_ptr> texp_B_mat = section.thermal_expansion_B_matrix(); + + const libMesh::Point point(2.3, 3.1, 5.2); + const Real time = 2.34; + RealMatrixX D_sec_texpB; + texp_B_mat->operator()(point, time, D_sec_texpB); + + libMesh::out << "texp_B_mat =\n" << D_sec_texpB << std::endl; + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_texpB_true = RealMatrixX::Zero(2,1); + D_sec_texpB_true(0,0) = 328.40639999999956; + D_sec_texpB_true(1,0) = 243.959039999999; + + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_texpB); + std::vector truth = eigen_matrix_to_std_vector(D_sec_texpB_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } +} + + +TEST_CASE("bar_element_property_card_constant_dynamic_1d", + "[dynamic],[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + + // Define Material Properties as MAST Parameters + MAST::Parameter rho("rho_param", 1420.5); // Density + MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity + MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio + MAST::Parameter kappa("kappa_param", 5.0/6.0); // Shear coefficient + MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity + MAST::Parameter k("k_param", 237.0); // Thermal Conductivity + + // Define Section Properties as MAST Parameters + MAST::Parameter thickness_y("DIM1", 3.0); // Section thickness in z-direction + MAST::Parameter thickness_z("DIM2", 0.75); // Section thickness in y-direction + MAST::Parameter offset_y("offy_param", 0.287); // Section offset in y-direction + MAST::Parameter offset_z("offz_param", 1.654); // Section offset in z-direction + + // Create field functions to dsitribute these constant parameters throughout the model + // Section Property Field Functions + MAST::ConstantFieldFunction DIM1_f("DIM1", thickness_y); + MAST::ConstantFieldFunction DIM2_f("DIM2", thickness_z); + MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); + MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); + // Material Property Field Functions + MAST::ConstantFieldFunction rho_f("rho", rho); + MAST::ConstantFieldFunction E_f("E", E); + MAST::ConstantFieldFunction nu_f("nu", nu); + MAST::ConstantFieldFunction kappa_f("kappa", kappa); + MAST::ConstantFieldFunction cp_f("cp", cp); + MAST::ConstantFieldFunction k_f("k_th", k); + + // Initialize the material + MAST::IsotropicMaterialPropertyCard material; + + // Add the material property constant field functions to the material card + material.add(rho_f); + material.add(k_f); + material.add(cp_f); + material.add(E_f); + material.add(nu_f); + material.add(kappa_f); + + // Initialize the section + MAST::Solid1DBarSectionElementPropertyCard section; + + // Add the section property constant field functions to the section card + section.add(DIM1_f); + section.add(DIM2_f); + section.add(offsety_f); + section.add(offsetz_f); + + // Add the material card to the section card + section.set_material(material); + + // Specify a section orientation point and add it to the section. + RealVectorX orientation = RealVectorX::Zero(3); + orientation(1) = 1.0; + section.y_vector() = orientation; + + // Now initialize the section + section.init(*p_global_init); + + REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional + REQUIRE( section.depends_on(thickness_y) ); + REQUIRE( section.depends_on(offset_y) ); + REQUIRE( section.depends_on(thickness_z) ); + REQUIRE( section.depends_on(offset_z) ); + REQUIRE( section.depends_on(k) ); + REQUIRE( section.depends_on(cp) ); + REQUIRE( section.depends_on(rho) ); + REQUIRE( section.if_isotropic() ); + + // True values calculated using the sectionproperties module in python BAR.py + const Real area_true = 2.2500000000000004e+00; + const Real torsion_constant_true = 3.5540414988249380e-01; + const Real first_area_moment_z_true = 6.4574999999999994e-01; + const Real first_area_moment_y_true = 3.7214999999999945e+00; + const Real second_area_moment_zz_true = 2.9079899999999986e-01; + const Real second_area_moment_yy_true = 7.8428609999999814e+00; + const Real second_area_moment_zy_true = 1.0680705000000006e+00; + const Real second_area_moment_polar_true = 8.1336599999999812e+00; + const Real Izzc_true = 1.0546874999999994e-01; + const Real Iyyc_true = 1.6875000000000009e+00; + const Real Izyc_true = 2.4424906541753444e-15; + const Real warping_constant_true = 6.1030611538894504e-02; + const Real kappa_z_true = 8.3330248143102326e-01; + const Real kappa_y_true = 5.5763491072129889e-01; + const Real xs_true = 1.6540000458463804e+00; + const Real ys_true = 2.8700000023051281e-01; + const Real xst_true = 1.6540000458463804e+00; + const Real yst_true = 2.8700000023051281e-01; + const libMesh::Point shear_center_true(xs_true, ys_true, 0.); + const libMesh::Point centroid_true(1.654, 0.287, 0.); + + // NOTE: The default 1D section is rectangular + const libMesh::Point point(4.3, -3.5, -6.7); + const Real time = 8.22; + + SECTION("1D section inertia matrix") + { + /** + * As of Dec. 17, 2019, inertia_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * inertia_matrix to be obtained without any input arguments. + */ + std::unique_ptr> inertia_mat = section.inertia_matrix(); + + const libMesh::Point point(2.3, 3.1, 5.2); + const Real time = 2.34; + RealMatrixX D_sec_iner; + inertia_mat->operator()(point, time, D_sec_iner); + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_iner_true = RealMatrixX::Zero(6,6); + + + Real area; + const MAST::FieldFunction& Area = section.A(); + Area(point, time, area); + REQUIRE( area == Approx(area_true) ); + D_sec_iner_true(0,0) = D_sec_iner_true(1,1) = D_sec_iner_true(2,2) = area_true; + + Real Ip; + const MAST::FieldFunction& PolarInertia = section.Ip(); + PolarInertia(point, time, Ip); + CHECK( Ip == Approx(second_area_moment_polar_true) ); + D_sec_iner_true(3,3) = second_area_moment_polar_true; + + Real first_area_moment_y; + const MAST::FieldFunction& Ay = section.Ay(); + Ay(point, time, first_area_moment_y); + CHECK( first_area_moment_y == Approx(first_area_moment_y_true) ); + D_sec_iner_true(0,4) = D_sec_iner_true(4,0) = first_area_moment_y_true; + + Real first_area_moment_z; + const MAST::FieldFunction& Az = section.Az(); + Az(point, time, first_area_moment_z); + CHECK( first_area_moment_z == Approx(first_area_moment_z_true) ); + D_sec_iner_true(0,5) = D_sec_iner_true(5,0) = first_area_moment_z_true; + + RealMatrixX I; + const MAST::FieldFunction& Inertias = section.I(); + Inertias(point, time, I); + REQUIRE( I(0,1) == I(1,0) ); + Real Iyy = I(1,1); + Real Izz = I(0,0); + Real Izy = I(0,1); + REQUIRE( Izz == Approx(second_area_moment_zz_true) ); + REQUIRE( Iyy == Approx(second_area_moment_yy_true) ); + REQUIRE( Izy == Approx(second_area_moment_zy_true) ); + + D_sec_iner_true(4,4) = Iyy; + D_sec_iner_true(4,5) = Izy; + D_sec_iner_true(5,4) = Izy; + D_sec_iner_true(5,5) = Izz; + + D_sec_iner_true *= rho(); + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_iner); + std::vector truth = eigen_matrix_to_std_vector(D_sec_iner_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } +} + + +TEST_CASE("bar_element_property_card_constant_structural_1d", + "[structural],[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + + // Define Material Properties as MAST Parameters + MAST::Parameter rho("rho_param", 1420.5); // Density + MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity + MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio + MAST::Parameter kappa("kappa_param", 5.0/6.0); // Shear coefficient + const Real G = E() / (2.0 * (1.0+nu())); + + // Define Section Properties as MAST Parameters + MAST::Parameter thickness_y("DIM1", 3.0); // Section thickness in z-direction + MAST::Parameter thickness_z("DIM2", 0.75); // Section thickness in y-direction + MAST::Parameter offset_y("offy_param", 0.287); // Section offset in y-direction + MAST::Parameter offset_z("offz_param", 1.654); // Section offset in z-direction + + // Create field functions to dsitribute these constant parameters throughout the model + // Section Property Field Functions + MAST::ConstantFieldFunction DIM1_f("DIM1", thickness_y); + MAST::ConstantFieldFunction DIM2_f("DIM2", thickness_z); + MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); + MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); + // Material Property Field Functions + MAST::ConstantFieldFunction rho_f("rho", rho); + MAST::ConstantFieldFunction E_f("E", E); + MAST::ConstantFieldFunction nu_f("nu", nu); + MAST::ConstantFieldFunction kappa_f("kappa", kappa); + + // Initialize the material + MAST::IsotropicMaterialPropertyCard material; + + // Add the material property constant field functions to the material card + material.add(rho_f); + material.add(E_f); + material.add(nu_f); + material.add(kappa_f); + + // Initialize the section + MAST::Solid1DBarSectionElementPropertyCard section; + + // Add the section property constant field functions to the section card + section.add(DIM1_f); + section.add(DIM2_f); + section.add(offsety_f); + section.add(offsetz_f); + + // Add the material card to the section card + section.set_material(material); + + // Specify a section orientation point and add it to the section. + RealVectorX orientation = RealVectorX::Zero(3); + orientation(1) = 1.0; + section.y_vector() = orientation; + + // Now initialize the section + section.init(*p_global_init); + + REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional + REQUIRE( section.depends_on(thickness_y) ); + REQUIRE( section.depends_on(offset_y) ); + REQUIRE( section.depends_on(thickness_z) ); + REQUIRE( section.depends_on(offset_z) ); + REQUIRE( section.depends_on(E) ); + REQUIRE( section.depends_on(nu) ); + REQUIRE( section.depends_on(kappa) ); + REQUIRE( section.depends_on(rho) ); + REQUIRE( section.if_isotropic() ); + + // True values calculated using the sectionproperties module in python BAR.py + const Real area_true = 2.2500000000000004e+00; + const Real torsion_constant_true = 3.5540414988249380e-01; + const Real first_area_moment_z_true = 6.4574999999999994e-01; + const Real first_area_moment_y_true = 3.7214999999999945e+00; + const Real second_area_moment_zz_true = 2.9079899999999986e-01; + const Real second_area_moment_yy_true = 7.8428609999999814e+00; + const Real second_area_moment_zy_true = 1.0680705000000006e+00; + const Real second_area_moment_polar_true = 8.1336599999999812e+00; + const Real Izzc_true = 1.0546874999999994e-01; + const Real Iyyc_true = 1.6875000000000009e+00; + const Real Izyc_true = 2.4424906541753444e-15; + const Real warping_constant_true = 6.1030611538894504e-02; + const Real kappa_z_true = 8.3330248143102326e-01; + const Real kappa_y_true = 5.5763491072129889e-01; + const Real xs_true = 1.6540000458463804e+00; + const Real ys_true = 2.8700000023051281e-01; + const Real xst_true = 1.6540000458463804e+00; + const Real yst_true = 2.8700000023051281e-01; + const libMesh::Point shear_center_true(xs_true, ys_true, 0.); + const libMesh::Point centroid_true(1.654, 0.287, 0.); + + // NOTE: The default 1D section is rectangular + const libMesh::Point point(4.3, -3.5, -6.7); + const Real time = 8.22; + + SECTION("set_get_bending_model") + { + // NOTE: MAST::DKT and MAST::MINDLIN are not valid options for 1D sections, even though their input is accepted. + section.set_bending_model(MAST::BERNOULLI); + section.set_bending_model(MAST::DEFAULT_BENDING); + section.set_bending_model(MAST::NO_BENDING); + section.set_bending_model(MAST::TIMOSHENKO); + + // TODO: Implement element creation for testing of getting bending_model and checking default + //REQUIRE( section.bending_model() + } + +// SECTION("quadrature_order") +// { +// section.set_bending_model(MAST::MINDLIN); +// REQUIRE( section.extra_quadrature_order(elem) == 0 ); +// +// section.set_bending_model(MAST::DKT); +// REQUIRE( section.extra_quadrature_order(elem) == 2 ); +// } + + SECTION("1D extension stiffness matrix") + { + /** + * As of Dec. 17, 2019, stiffness_A_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * stiffness_A_matrix to be obtained without any input arguments. + */ + Real area; + const MAST::FieldFunction& Area = section.A(); + Area(point, time, area); + REQUIRE( area == Approx(area_true) ); + + Real torsion_constant; + const MAST::FieldFunction& TorsionConstant = section.J(); + TorsionConstant(point, time, torsion_constant); + REQUIRE( torsion_constant == Approx(torsion_constant_true).epsilon(0.05) ); + + std::unique_ptr> extension_stiffness_mat = section.stiffness_A_matrix(); + + const libMesh::Point point(2.3, 3.1, 5.2); + const Real time = 2.34; + RealMatrixX D_sec_ext; + extension_stiffness_mat->operator()(point, time, D_sec_ext); + + libMesh::out << "D_sec_ext\n" << D_sec_ext << std::endl; + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_ext_true = RealMatrixX::Zero(2,2); + D_sec_ext_true(0,0) = E() * area_true; + D_sec_ext_true(1,1) = G * torsion_constant_true; + + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_ext); + std::vector truth = eigen_matrix_to_std_vector(D_sec_ext_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth).epsilon(0.05) ); + } + + + SECTION("1D bending section stiffness matrix") + { + /** + * As of Dec. 17, 2019, stiffness_D_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * stiffness_D_matrix to be obtained without any input arguments. + */ + RealMatrixX I; + const MAST::FieldFunction& Inertias = section.I(); + Inertias(point, time, I); + REQUIRE( I(0,1) == I(1,0) ); + Real Izz = I(0,0); + Real Iyy = I(1,1); + Real Izy = I(0,1); + REQUIRE( Izz == Approx(second_area_moment_zz_true) ); + REQUIRE( Iyy == Approx(second_area_moment_yy_true) ); + REQUIRE( Izy == Approx(second_area_moment_zy_true) ); + + std::unique_ptr> bending_stiffness_mat = section.stiffness_D_matrix(); + + const libMesh::Point point(2.3, 3.1, 5.2); + const Real time = 2.34; + RealMatrixX D_sec_bnd; + bending_stiffness_mat->operator()(point, time, D_sec_bnd); + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_bnd_true = RealMatrixX::Zero(2,2); + D_sec_bnd_true(0,0) = E() * second_area_moment_zz_true; + D_sec_bnd_true(1,1) = E() * second_area_moment_yy_true; + D_sec_bnd_true(0,1) = E() * second_area_moment_zy_true; + D_sec_bnd_true(1,0) = E() * second_area_moment_zy_true; + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_bnd); + std::vector truth = eigen_matrix_to_std_vector(D_sec_bnd_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } + + SECTION("1D extension-bending section stiffness matrix") + { + /** + * As of Dec. 17, 2019, stiffness_B_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * stiffness_B_matrix to be obtained without any input arguments. + */ + Real first_area_moment_y; + const MAST::FieldFunction& Ay = section.Ay(); + Ay(point, time, first_area_moment_y); + CHECK( first_area_moment_y == Approx(first_area_moment_y_true) ); + + Real first_area_moment_z; + const MAST::FieldFunction& Az = section.Az(); + Az(point, time, first_area_moment_z); + CHECK( first_area_moment_z == Approx(first_area_moment_z_true) ); + + std::unique_ptr> bndext_stiffness_mat = section.stiffness_B_matrix(); + + const libMesh::Point point(2.3, 3.1, 5.2); + const Real time = 2.34; + RealMatrixX D_sec_bndext; + bndext_stiffness_mat->operator()(point, time, D_sec_bndext); + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_bndext_true = RealMatrixX::Zero(2,2); + D_sec_bndext_true(0,0) = E() * first_area_moment_z_true; + D_sec_bndext_true(0,1) = E() * first_area_moment_y_true; + // TODO: Add checks for torsion bending coupling when added to MAST. + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_bndext); + std::vector truth = eigen_matrix_to_std_vector(D_sec_bndext_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } + + SECTION("1D transverse shear section stiffness matrix") + { + /** + * As of Dec. 17, 2019, transverse_shear_stiffness_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * transverse_shear_stiffness_matrix to be obtained without any input arguments. + */ + Real area; + const MAST::FieldFunction& Area = section.A(); + Area(point, time, area); + REQUIRE( area == Approx(area_true) ); + + std::unique_ptr> trans_shear_stiffness_mat = section.transverse_shear_stiffness_matrix(); + + const libMesh::Point point(2.3, 3.1, 5.2); + const Real time = 2.34; + RealMatrixX D_sec_shr; + trans_shear_stiffness_mat->operator()(point, time, D_sec_shr); + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_shr_true = RealMatrixX::Zero(2,2); + D_sec_shr_true(0,0) = G*area_true*kappa_z_true; + D_sec_shr_true(1,1) = G*area_true*kappa_y_true; + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_shr); + std::vector truth = eigen_matrix_to_std_vector(D_sec_shr_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } + + +// SECTION("1D spring section stiffness matrix") +// { +// /** +// * As of Dec. 17, 2019, spring_stiffness_matrix requires the input of an +// * MAST::ElementBase object, but does not actually use it. To get +// * around requiring the creation of such an object (and therefore +// * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, +// * and MAST::GeomElem objects as well). +// * +// * To remedy this, an additional method was added to MAST which allows +// * transverse_shear_stiffness_matrix to be obtained without any input arguments. +// */ +// std::unique_ptr> spring_stiffness_mat = section.stiffness_S_matrix(); +// +// const libMesh::Point point(2.3, 3.1, 5.2); +// const Real time = 2.34; +// RealMatrixX D_sec_spring; +// spring_stiffness_mat->operator()(point, time, D_sec_spring); +// +// // Hard-coded value of the section's extension stiffness +// // NOTE: Should be all zero's for non-bushing sections +// RealMatrixX D_sec_spring_true = RealMatrixX::Zero(4,6); +// +// // Convert the test and truth Eigen::Matrix objects to std::vector +// // since Catch2 has built in methods to compare vectors +// std::vector test = eigen_matrix_to_std_vector(D_sec_spring); +// std::vector truth = eigen_matrix_to_std_vector(D_sec_spring_true); +// +// // Floating point approximations are diffcult to compare since the +// // values typically aren't exactly equal due to numerical error. +// // Therefore, we use the Approx comparison instead of Equals +// CHECK_THAT( test, Catch::Approx(truth) ); +// } +} From f4624110767d26b7c07b3d77e69b8ae51e997ae6 Mon Sep 17 00:00:00 2001 From: David John Neiferd <13425967+JohnDN90@users.noreply.github.com> Date: Fri, 21 Feb 2020 16:24:54 -0500 Subject: [PATCH 08/27] Added TUBE section property card and tests. TODO: Still need to add MPI tests and sensitivity test. --- src/property_cards/CMakeLists.txt | 4 + ...arameter_section_element_property_card.cpp | 320 ++++++ ...2parameter_section_element_property_card.h | 265 +++++ ..._1d_tube_section_element_property_card.cpp | 409 +++++++ ...id_1d_tube_section_element_property_card.h | 117 ++ tests/property/CMakeLists.txt | 74 +- ..._1d_tube_section_element_property_card.cpp | 1020 +++++++++++++++++ 7 files changed, 2175 insertions(+), 34 deletions(-) create mode 100644 src/property_cards/solid_1d_2parameter_section_element_property_card.cpp create mode 100644 src/property_cards/solid_1d_2parameter_section_element_property_card.h create mode 100644 src/property_cards/solid_1d_tube_section_element_property_card.cpp create mode 100644 src/property_cards/solid_1d_tube_section_element_property_card.h create mode 100644 tests/property/mast_solid_1d_tube_section_element_property_card.cpp diff --git a/src/property_cards/CMakeLists.txt b/src/property_cards/CMakeLists.txt index bce21ed8..cfb4d3fe 100644 --- a/src/property_cards/CMakeLists.txt +++ b/src/property_cards/CMakeLists.txt @@ -26,10 +26,14 @@ target_sources(mast ${CMAKE_CURRENT_LIST_DIR}/solid_1d_nparameter_section_element_property_card.h ${CMAKE_CURRENT_LIST_DIR}/solid_1d_1parameter_section_element_property_card.cpp ${CMAKE_CURRENT_LIST_DIR}/solid_1d_1parameter_section_element_property_card.h + ${CMAKE_CURRENT_LIST_DIR}/solid_1d_2parameter_section_element_property_card.cpp + ${CMAKE_CURRENT_LIST_DIR}/solid_1d_2parameter_section_element_property_card.h ${CMAKE_CURRENT_LIST_DIR}/solid_1d_bar_section_element_property_card.cpp ${CMAKE_CURRENT_LIST_DIR}/solid_1d_bar_section_element_property_card.h ${CMAKE_CURRENT_LIST_DIR}/solid_1d_rod_section_element_property_card.cpp ${CMAKE_CURRENT_LIST_DIR}/solid_1d_rod_section_element_property_card.h + ${CMAKE_CURRENT_LIST_DIR}/solid_1d_tube_section_element_property_card.cpp + ${CMAKE_CURRENT_LIST_DIR}/solid_1d_tube_section_element_property_card.h ${CMAKE_CURRENT_LIST_DIR}/solid_2d_section_element_property_card.cpp ${CMAKE_CURRENT_LIST_DIR}/solid_2d_section_element_property_card.h ${CMAKE_CURRENT_LIST_DIR}/cross_section_property_pilkey.cpp diff --git a/src/property_cards/solid_1d_2parameter_section_element_property_card.cpp b/src/property_cards/solid_1d_2parameter_section_element_property_card.cpp new file mode 100644 index 00000000..0647f900 --- /dev/null +++ b/src/property_cards/solid_1d_2parameter_section_element_property_card.cpp @@ -0,0 +1,320 @@ +/* + * MAST: Multidisciplinary-design Adaptation and Sensitivity Toolkit + * Copyright (C) 2013-2019 Manav Bhatia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +// MAST includes +#include "property_cards/solid_1d_2parameter_section_element_property_card.h" + + +MAST::Solid1D2ParameterSectionProperty::Area:: +Area(const std::function func, + const std::function dfunc, + const MAST::FieldFunction& DIM1, + const MAST::FieldFunction& DIM2): +MAST::FieldFunction("Area"), +_func(func), _dfunc(dfunc), _DIM1(DIM1), _DIM2(DIM2){ + _functions.insert(&DIM1); + _functions.insert(&DIM2); +} + +void MAST::Solid1D2ParameterSectionProperty::Area:: +operator() (const libMesh::Point& p, const Real t, Real& m) const +{ + Real DIM1, DIM2; + _DIM1(p, t, DIM1); + _DIM2(p, t, DIM2); + _func(DIM1, DIM2, m); +} + +void MAST::Solid1D2ParameterSectionProperty::Area:: +derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, + Real& m) const +{ + Real DIM1, DIM2; + Real dDIM1, dDIM2; + _DIM1(p, t, DIM1); _DIM1.derivative( f, p, t, dDIM1); + _DIM2(p, t, DIM2); _DIM2.derivative( f, p, t, dDIM2); + _dfunc(DIM1, DIM2, dDIM1, dDIM2, m); +} + + +MAST::Solid1D2ParameterSectionProperty::TorsionalConstant:: +TorsionalConstant(const std::function func, + const std::function dfunc, + const MAST::FieldFunction& DIM1, + const MAST::FieldFunction& DIM2): +MAST::FieldFunction("TorsionalConstant"), +_func(func), _dfunc(dfunc), _DIM1(DIM1), _DIM2(DIM2) +{ + _functions.insert(&DIM1); + _functions.insert(&DIM2); +} + + +void MAST::Solid1D2ParameterSectionProperty::TorsionalConstant:: +operator() (const libMesh::Point& p, const Real t, Real& m) const +{ + Real DIM1, DIM2; + _DIM1(p, t, DIM1); + _DIM2(p, t, DIM2); + _func(DIM1, DIM2, m); +} + + +void MAST::Solid1D2ParameterSectionProperty::TorsionalConstant:: +derivative (const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, +Real& m) const +{ + Real DIM1, DIM2; + Real dDIM1, dDIM2; + _DIM1(p, t, DIM1); _DIM1.derivative( f, p, t, dDIM1); + _DIM2(p, t, DIM2); _DIM2.derivative( f, p, t, dDIM2); + _dfunc(DIM1, DIM2, dDIM1, dDIM2, m); +} + + + +MAST::Solid1D2ParameterSectionProperty::PolarInertia:: +PolarInertia(const std::function func, + const std::function dfunc, + const std::function Afunc, + const std::function dAfunc, + const MAST::FieldFunction& DIM1, + const MAST::FieldFunction& DIM2, + const MAST::FieldFunction& hy_offset, + const MAST::FieldFunction& hz_offset): +MAST::FieldFunction("PolarInertia"), +_func(func), +_dfunc(dfunc), +_Afunc(Afunc), +_dAfunc(dAfunc), +_DIM1(DIM1), _DIM2(DIM2), +_hy_offset(hy_offset), +_hz_offset(hz_offset) +{ + _functions.insert(&DIM1); + _functions.insert(&DIM2); + _functions.insert(&hy_offset); + _functions.insert(&hz_offset); +} + +void MAST::Solid1D2ParameterSectionProperty::PolarInertia:: +operator() (const libMesh::Point& p,const Real t, Real& m) const +{ + Real DIM1, DIM2, offy, offz, A; + _DIM1(p, t, DIM1); + _DIM2(p, t, DIM2); + _hy_offset(p, t, offy); + _hz_offset(p, t, offz); + + _Afunc(DIM1, DIM2, A); + + _func(DIM1, DIM2, m); + m += A*pow(offy,2) + A*pow(offz,2); // Account for offsets +} + + +void MAST::Solid1D2ParameterSectionProperty::PolarInertia:: +derivative (const MAST::FunctionBase& f, const libMesh::Point& p, + const Real t, Real& m) const +{ + Real DIM1, DIM2; + Real dDIM1, dDIM2; + Real offy, offz, doffy, doffz, A, dA; + _DIM1 (p, t, DIM1); _DIM1.derivative( f, p, t, dDIM1); + _DIM2(p, t, DIM2); _DIM2.derivative( f, p, t, dDIM2); + _hy_offset (p, t, offy); _hy_offset.derivative( f, p, t, doffy); + _hz_offset (p, t, offz); _hz_offset.derivative( f, p, t, doffz); + + + _Afunc(DIM1, DIM2, A); + _dAfunc(DIM1, DIM2, dDIM1, dDIM2, dA); + + _dfunc(DIM1, DIM2, dDIM1, dDIM2, m); + m += dA*pow(offy,2) + 2.*A*offy*doffy + dA*pow(offz,2) + 2.*A*offz*doffz; +} + + +MAST::Solid1D2ParameterSectionProperty::AreaYMoment:: +AreaYMoment(const std::function Afunc, + const std::function dAfunc, + const MAST::FieldFunction& DIM1, + const MAST::FieldFunction& DIM2, + const MAST::FieldFunction& hz_offset): +MAST::FieldFunction("AreaYMoment"), +_Afunc(Afunc), +_dAfunc(dAfunc), +_DIM1(DIM1), _DIM2(DIM2), +_hz_offset(hz_offset) +{ + _functions.insert(&DIM1); + _functions.insert(&DIM2); + _functions.insert(&hz_offset); +} + +void MAST::Solid1D2ParameterSectionProperty::AreaYMoment:: +operator() (const libMesh::Point& p, const Real t, Real& m) const +{ + Real DIM1, DIM2, off, A; + _DIM1(p, t, DIM1); + _DIM2(p, t, DIM2); + _hz_offset(p, t, off); + + _Afunc(DIM1, DIM2, A); + m = A*off; +} + +void MAST::Solid1D2ParameterSectionProperty::AreaYMoment:: +derivative (const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, + Real& m) const +{ + Real DIM1, DIM2; + Real dDIM1, dDIM2; + Real off, doff, A, dA; + _DIM1 (p, t, DIM1); _DIM1.derivative( f, p, t, dDIM1); + _DIM2(p, t, DIM2); _DIM2.derivative( f, p, t, dDIM2); + _hz_offset (p, t, off); _hz_offset.derivative( f, p, t, doff); + _Afunc(DIM1, DIM2, A); _dAfunc(DIM1, DIM2, dDIM1, dDIM2, dA); + + m = dA*off + A*doff; +} + + + +MAST::Solid1D2ParameterSectionProperty::AreaZMoment:: +AreaZMoment(const std::function Afunc, + const std::function dAfunc, + const MAST::FieldFunction& DIM1, + const MAST::FieldFunction& DIM2, + const MAST::FieldFunction& hy_offset): +MAST::FieldFunction("AreaZMoment"), +_Afunc(Afunc), +_dAfunc(dAfunc), +_DIM1(DIM1), _DIM2(DIM2), +_hy_offset(hy_offset) +{ + _functions.insert(&DIM1); + _functions.insert(&DIM2); + _functions.insert(&hy_offset); +} + +void MAST::Solid1D2ParameterSectionProperty::AreaZMoment:: +operator() (const libMesh::Point& p, const Real t, Real& m) const +{ + Real DIM1, DIM2, off, A; + _DIM1(p, t, DIM1); + _DIM2(p, t, DIM2); + _hy_offset(p, t, off); + + _Afunc(DIM1, DIM2, A); + m = A*off; +} + +void MAST::Solid1D2ParameterSectionProperty::AreaZMoment:: +derivative (const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, + Real& m) const +{ + Real DIM1, DIM2; + Real dDIM1, dDIM2; + Real off, doff, A, dA; + _DIM1(p, t, DIM1); _DIM1.derivative( f, p, t, dDIM1); + _DIM2(p, t, DIM2); _DIM2.derivative( f, p, t, dDIM2); + _hy_offset(p, t, off); _hy_offset.derivative( f, p, t, doff); + + _Afunc(DIM1, DIM2, A); + _dAfunc(DIM1, DIM2, dDIM1, dDIM2, dA); + + m = dA*off + A*doff; +} + +MAST::Solid1D2ParameterSectionProperty::AreaInertiaMatrix:: +AreaInertiaMatrix(const std::function Izfunc, + const std::function dIzfunc, + const std::function Iyfunc, + const std::function dIyfunc, + const std::function Afunc, + const std::function dAfunc, + const MAST::FieldFunction& DIM1, + const MAST::FieldFunction& DIM2, + const MAST::FieldFunction& hy_offset, + const MAST::FieldFunction& hz_offset): +MAST::FieldFunction("AreaInertiaMatrix"), +_Izfunc(Izfunc), +_dIzfunc(dIzfunc), +_Iyfunc(Iyfunc), +_dIyfunc(dIyfunc), +_Afunc(Afunc), +_dAfunc(dAfunc), +_DIM1(DIM1), _DIM2(DIM2), +_hy_offset(hy_offset), +_hz_offset(hz_offset) +{ + _functions.insert(&DIM1); + _functions.insert(&DIM2); + _functions.insert(&hy_offset); + _functions.insert(&hz_offset); +} + +void MAST::Solid1D2ParameterSectionProperty::AreaInertiaMatrix:: +operator() (const libMesh::Point& p, const Real t, RealMatrixX& m) const +{ + Real DIM1, DIM2, offy, offz, A; + m = RealMatrixX::Zero(2,2); + _DIM1(p, t, DIM1); + _DIM2(p, t, DIM2); + _hy_offset(p, t, offy); + _hz_offset(p, t, offz); + + _Afunc(DIM1, DIM2, A); + _Izfunc(DIM1, DIM2, m(0,0)); + _Iyfunc(DIM1, DIM2, m(1,1)); + + m(0,0) += A*pow(offy,2) ; // Account for offset + m(0,1) = A*offy*offz; + m(1,0) = m(0,1); + m(1,1) += A*pow(offz,2) ; // Account for offset +} + +void MAST::Solid1D2ParameterSectionProperty::AreaInertiaMatrix:: +derivative (const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, + RealMatrixX& m) const +{ + Real DIM1, DIM2; + Real dDIM1, dDIM2; + Real offy, offz, A, doffy, doffz, dA; + m = RealMatrixX::Zero(2,2); + _DIM1(p, t, DIM1); _DIM1.derivative( f, p, t, dDIM1); + _DIM2(p, t, DIM2); _DIM2.derivative( f, p, t, dDIM2); + _hy_offset(p, t, offy); _hy_offset.derivative( f, p, t, doffy); + _hz_offset(p, t, offz); _hz_offset.derivative( f, p, t, doffz); + + _Afunc(DIM1, DIM2, A); + _dAfunc(DIM1, DIM2, dDIM1, dDIM2, dA); + _dIzfunc(DIM1, DIM2, dDIM1, dDIM2, m(0,0)); + _dIyfunc(DIM1, DIM2, dDIM1, dDIM2, m(1,1)); + + m(0,0) += dA*pow(offy,2) + A*2.*offy*doffy; + m(0,1) = dA*offy*offz + A*doffy*offz + A*offy*doffz; + m(1,0) = m(0,1); + m(1,1) += dA*pow(offz,2) + A*2.*offz*doffz; +} diff --git a/src/property_cards/solid_1d_2parameter_section_element_property_card.h b/src/property_cards/solid_1d_2parameter_section_element_property_card.h new file mode 100644 index 00000000..8912c513 --- /dev/null +++ b/src/property_cards/solid_1d_2parameter_section_element_property_card.h @@ -0,0 +1,265 @@ +/* + * MAST: Multidisciplinary-design Adaptation and Sensitivity Toolkit + * Copyright (C) 2013-2019 Manav Bhatia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +/** + * Shapes Controlled by Two Parameters Include + * BAR (Rectangle) + * Ellipse + * TUBE (Hollow Circle) + * Square Box (Hollow Square) + */ + +#ifndef __mast__solid_1d_2parameter_section_element_property_card__ +#define __mast__solid_1d_2parameter_section_element_property_card__ + + +// MAST includes +#include "property_cards/solid_1d_section_element_property_card.h" +#include "base/field_function_base.h" +#include "property_cards/solid_1d_nparameter_section_element_property_card.h" + + +namespace MAST { + namespace Solid1D2ParameterSectionProperty { + + class Area: public MAST::FieldFunction { + public: + Area(const std::function func, + const std::function dfunc, + const MAST::FieldFunction& DIM1, + const MAST::FieldFunction& DIM2); + + virtual ~Area() { } + + virtual void operator() (const libMesh::Point& p, + const Real t, + Real& m) const; + + virtual void derivative (const MAST::FunctionBase& f, + const libMesh::Point& p, + const Real t, + Real& m) const; + + protected: + const std::function _func; + const std::function _dfunc; + const MAST::FieldFunction &_DIM1, &_DIM2; + }; + + + class TorsionalConstant: public MAST::FieldFunction { + public: + TorsionalConstant( + const std::function func, + const std::function dfunc, + const MAST::FieldFunction& DIM1, + const MAST::FieldFunction& DIM2); + + virtual ~TorsionalConstant() { } + + virtual void operator() (const libMesh::Point& p, + const Real t, + Real& m) const; + + virtual void derivative ( const MAST::FunctionBase& f, + const libMesh::Point& p, + const Real t, + Real& m) const; + + protected: + + const std::function _func; + const std::function _dfunc; + const MAST::FieldFunction &_DIM1, &_DIM2; + }; + + + class PolarInertia: public MAST::FieldFunction { + public: + PolarInertia(const std::function func, + const std::function dfunc, + const std::function Afunc, + const std::function dAfunc, + const MAST::FieldFunction& DIM1, + const MAST::FieldFunction& DIM2, + const MAST::FieldFunction& hy_offset, + const MAST::FieldFunction& hz_offset); + + virtual ~PolarInertia() { } + + virtual void operator() (const libMesh::Point& p, + const Real t, + Real& m) const; + + virtual void derivative ( const MAST::FunctionBase& f, + const libMesh::Point& p, + const Real t, + Real& m) const; + + protected: + const std::function _func, _Afunc; + const std::function _dfunc, _dAfunc; + const MAST::FieldFunction &_DIM1, &_DIM2, + &_hy_offset, &_hz_offset; + }; + + + /*! + * calculates the area moment about the Y-axis due to an offset + * along the Z-axis + */ + class AreaYMoment: public MAST::FieldFunction { + public: + AreaYMoment(const std::function Afunc, + const std::function dAfunc, + const MAST::FieldFunction& DIM1, + const MAST::FieldFunction& DIM2, + const MAST::FieldFunction& hz_offset); + + + virtual ~AreaYMoment() { } + + virtual void operator() (const libMesh::Point& p, + const Real t, + Real& m) const; + + + virtual void derivative ( const MAST::FunctionBase& f, + const libMesh::Point& p, + const Real t, + Real& m) const; + + protected: + const std::function _Afunc; + const std::function _dAfunc; + const MAST::FieldFunction &_DIM1, &_DIM2, + &_hz_offset; + }; + + + /*! + * calculates the area moment about the Z-axis due to an offset + * along the Y-axis + */ + class AreaZMoment: public MAST::FieldFunction { + public: + AreaZMoment(const std::function Afunc, + const std::function dAfunc, + const MAST::FieldFunction& DIM1, + const MAST::FieldFunction& DIM2, + const MAST::FieldFunction& hy_offset); + + virtual ~AreaZMoment() { } + + virtual void operator() (const libMesh::Point& p, + const Real t, + Real& m) const; + + + virtual void derivative ( const MAST::FunctionBase& f, + const libMesh::Point& p, + const Real t, + Real& m) const; + + protected: + const std::function _Afunc; + const std::function _dAfunc; + const MAST::FieldFunction &_DIM1, &_DIM2, + &_hy_offset; + }; + + + /*! + * calculates the 2x2 matrix of area inertia for the section with + * individual entries as + * + * 0 x 0 = int_omega (y+yoff)^2 dy dz + * 0 x 1 = int_omega (y+yoff) (z+zoff) dy dz + * 1 x 0 = int_omega (y+yoff) (z+zoff) dy dz + * 1 x 1 = int_omega (z+zoff)^2 dy dz + */ + class AreaInertiaMatrix: public MAST::FieldFunction { + public: + AreaInertiaMatrix(const std::function Izfunc, + const std::function dIzfunc, + const std::function Iyfunc, + const std::function dIyfunc, + const std::function Afunc, + const std::function dAfunc, + const MAST::FieldFunction& DIM1, + const MAST::FieldFunction& DIM2, + const MAST::FieldFunction& hy_offset, + const MAST::FieldFunction& hz_offset); + + virtual ~AreaInertiaMatrix() { } + + virtual void operator() (const libMesh::Point& p, + const Real t, + RealMatrixX& m) const; + + + virtual void derivative ( const MAST::FunctionBase& f, + const libMesh::Point& p, + const Real t, + RealMatrixX& m) const; + + protected: + const std::function _Izfunc, _Iyfunc, + _Afunc; + const std::function _dIzfunc, _dIyfunc, _dAfunc; + const MAST::FieldFunction &_DIM1, &_DIM2, + &_hy_offset, &_hz_offset; + }; + } +} + + +namespace MAST { + + class Solid1D2ParameterSectionElementPropertyCard : public MAST::Solid1DnParameterSectionElementPropertyCard//MAST::Solid1DSectionElementPropertyCard + { + public: + Solid1D2ParameterSectionElementPropertyCard(): + //MAST::Solid1DSectionElementPropertyCard() {} + MAST::Solid1DnParameterSectionElementPropertyCard() {} + + /*! + * virtual destructor + */ + virtual ~Solid1D2ParameterSectionElementPropertyCard() { } + }; +} + + +#endif // __mast__solid_1d_2parameter_section_element_property_card__ diff --git a/src/property_cards/solid_1d_tube_section_element_property_card.cpp b/src/property_cards/solid_1d_tube_section_element_property_card.cpp new file mode 100644 index 00000000..7673de37 --- /dev/null +++ b/src/property_cards/solid_1d_tube_section_element_property_card.cpp @@ -0,0 +1,409 @@ +/* + * MAST: Multidisciplinary-design Adaptation and Sensitivity Toolkit + * Copyright (C) 2013-2019 Manav Bhatia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +// MAST includes +#include "property_cards/solid_1d_tube_section_element_property_card.h" + + +#define PI 3.1415926535897932 + + +// Annulus (TUBE in Siemens NX Nastran and Astros 21.2) +void MAST::Solid1DTubeSectionProperty::calcA(Real& DIM1, Real& DIM2, Real& A){ + A = PI*(DIM1*DIM1-DIM2*DIM2); +} + +void MAST::Solid1DTubeSectionProperty::calcdA(Real& DIM1, Real& DIM2, + Real& dDIM1, Real& dDIM2, + Real& dA){ + dA = PI*(DIM1*dDIM1-DIM2*dDIM2)*2.0; +} + +void MAST::Solid1DTubeSectionProperty::calcIz(Real& DIM1, Real& DIM2, Real& Iz){ + Iz = (PI*(DIM1*DIM1*DIM1*DIM1-DIM2*DIM2*DIM2*DIM2))/4.0; +} + +void MAST::Solid1DTubeSectionProperty::calcdIz(Real& DIM1, Real& DIM2, + Real& dDIM1, Real& dDIM2, + Real& dIz){ + dIz = PI*((DIM1*DIM1*DIM1)*dDIM1-(DIM2*DIM2*DIM2)*dDIM2); +} + +void MAST::Solid1DTubeSectionProperty::calcIy(Real& DIM1, Real& DIM2, Real& Iy){ + Iy = (PI*(DIM1*DIM1*DIM1*DIM1-DIM2*DIM2*DIM2*DIM2))/4.0; +} + +void MAST::Solid1DTubeSectionProperty::calcdIy(Real& DIM1, Real& DIM2, + Real& dDIM1, Real& dDIM2, + Real& dIy){ + dIy = PI*((DIM1*DIM1*DIM1)*dDIM1-(DIM2*DIM2*DIM2)*dDIM2); +} + +void MAST::Solid1DTubeSectionProperty::calcIp(Real& DIM1, Real& DIM2, Real& Ip){ + Ip = (PI*(DIM1*DIM1*DIM1*DIM1-DIM2*DIM2*DIM2*DIM2))/2.0; +} + +void MAST::Solid1DTubeSectionProperty::calcdIp(Real& DIM1, Real& DIM2, + Real& dDIM1, Real& dDIM2, + Real& dIp){ + dIp = PI*((DIM1*DIM1*DIM1)*dDIM1-(DIM2*DIM2*DIM2)*dDIM2)*2.0; +} + +void MAST::Solid1DTubeSectionProperty::calcJ(Real& DIM1, Real& DIM2, Real& J){ + J = (PI*(DIM1*DIM1*DIM1*DIM1-DIM2*DIM2*DIM2*DIM2))/2.0; +} + +void MAST::Solid1DTubeSectionProperty::calcdJ(Real& DIM1, Real& DIM2, + Real& dDIM1, Real& dDIM2, + Real& dJ){ + dJ = PI*((DIM1*DIM1*DIM1)*dDIM1-(DIM2*DIM2*DIM2)*dDIM2)*2.0; +} + + +const std::vector +MAST::Solid1DTubeSectionElementPropertyCard::get_geom_points(const libMesh::Point& p, const Real t, const uint n) const +{ + const MAST::FieldFunction + &DIM1 = this->get >("DIM1"), + &DIM2 = this->get >("DIM2"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real DIM1v, DIM2v, offset_y, offset_z; + DIM1(p, t, DIM1v); DIM2(p, t, DIM2v); + hy_off(p, t, offset_y); hz_off(p, t, offset_z); + + libMesh::Point offset(offset_z, offset_y); + std::vector geom_points(n); + for (uint i=0; i +MAST::Solid1DTubeSectionElementPropertyCard::get_geom_points_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, const uint n) const +{ + const MAST::FieldFunction + &DIM1 = this->get >("DIM1"), + &DIM2 = this->get >("DIM2"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real DIM1v, DIM2v, offset_y, offset_z; + Real dDIM1v, dDIM2v, doffset_y, doffset_z; + DIM1(p, t, DIM1v); DIM1.derivative(f, p, t, dDIM1v); + DIM2(p, t, DIM2v); DIM2.derivative(f, p, t, dDIM2v); + hy_off(p, t, offset_y); hy_off.derivative(f, p, t, doffset_y); + hz_off(p, t, offset_z); hz_off.derivative(f, p, t, doffset_z); + + libMesh::Point doffset(doffset_z, doffset_y); + std::vector dgeom_points(n); + for (uint i=0; i> +MAST::Solid1DTubeSectionElementPropertyCard::get_holes_points(const libMesh::Point& p, const Real t, const uint n) const +{ + const MAST::FieldFunction + &DIM1 = this->get >("DIM1"), + &DIM2 = this->get >("DIM2"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real DIM1v, DIM2v, offset_y, offset_z; + DIM1(p, t, DIM1v); DIM2(p, t, DIM2v); + hy_off(p, t, offset_y); hz_off(p, t, offset_z); + + libMesh::Point offset(offset_z, offset_y); + std::vector hole_points(n); + for (uint i=0; i> +MAST::Solid1DTubeSectionElementPropertyCard::get_holes_points_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, const uint n) const +{ + const MAST::FieldFunction + &DIM1 = this->get >("DIM1"), + &DIM2 = this->get >("DIM2"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real DIM1v, DIM2v, offset_y, offset_z; + Real dDIM1v, dDIM2v, doffset_y, doffset_z; + DIM1(p, t, DIM1v); DIM1.derivative(f, p, t, dDIM1v); + DIM2(p, t, DIM2v); DIM2.derivative(f, p, t, dDIM2v); + hy_off(p, t, offset_y); hy_off.derivative(f, p, t, doffset_y); + hz_off(p, t, offset_z); hz_off.derivative(f, p, t, doffset_z); + + libMesh::Point doffset(doffset_z, doffset_y); + std::vector dholes_points(n); + for (uint i=0; i + &DIM1 = this->get >("DIM1"), + &DIM2 = this->get >("DIM2"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real DIM1v, DIM2v, offset_y, offset_z; + DIM1(p, t, DIM1v); DIM2(p, t, DIM2v); + hy_off(p, t, offset_y); hz_off(p, t, offset_z); + + return libMesh::Point(offset_z, offset_y, 0.); +} + + +const libMesh::Point +MAST::Solid1DTubeSectionElementPropertyCard::get_shear_center_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t) const +{ + const MAST::FieldFunction + &DIM1 = this->get >("DIM1"), + &DIM2 = this->get >("DIM2"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real DIM1v, DIM2v, offset_y, offset_z; + Real dDIM1v, dDIM2v, doffset_y, doffset_z; + DIM1(p, t, DIM1v); DIM1.derivative(f, p, t, dDIM1v); + DIM2(p, t, DIM2v); DIM2.derivative(f, p, t, dDIM2v); + hy_off(p, t, offset_y); hy_off.derivative(f, p, t, doffset_y); + hz_off(p, t, offset_z); hz_off.derivative(f, p, t, doffset_z); + + return libMesh::Point(doffset_z, doffset_y, 0.); +} + + +const libMesh::Point +MAST::Solid1DTubeSectionElementPropertyCard::get_centroid(const libMesh::Point& p, const Real t) const +{ + const MAST::FieldFunction + &DIM1 = this->get >("DIM1"), + &DIM2 = this->get >("DIM2"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real DIM1v, DIM2v, offset_y, offset_z; + DIM1(p, t, DIM1v); DIM2(p, t, DIM2v); + hy_off(p, t, offset_y); hz_off(p, t, offset_z); + + return libMesh::Point(offset_z, offset_y, 0.); +} + + +const libMesh::Point +MAST::Solid1DTubeSectionElementPropertyCard::get_centroid_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t) const +{ + const MAST::FieldFunction + &DIM1 = this->get >("DIM1"), + &DIM2 = this->get >("DIM2"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real DIM1v, DIM2v, offset_y, offset_z; + Real dDIM1v, dDIM2v, doffset_y, doffset_z; + DIM1(p, t, DIM1v); DIM1.derivative(f, p, t, dDIM1v); + DIM2(p, t, DIM2v); DIM2.derivative(f, p, t, dDIM2v); + hy_off(p, t, offset_y); hy_off.derivative(f, p, t, doffset_y); + hz_off(p, t, offset_z); hz_off.derivative(f, p, t, doffset_z); + + return libMesh::Point(doffset_z, doffset_y, 0.); +} + + +const std::vector +MAST::Solid1DTubeSectionElementPropertyCard::get_stress_points(const libMesh::Point& p, const Real t, const libMesh::Point ps) const +{ + const MAST::FieldFunction + &DIM1 = this->get >("DIM1"), + &DIM2 = this->get >("DIM2"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real DIM1v, DIM2v, offset_y, offset_z; + DIM1(p, t, DIM1v); DIM2(p, t, DIM2v); + hy_off(p, t, offset_y); hz_off(p, t, offset_z); + + libMesh::Point offset(offset_z, offset_y); + + return {libMesh::Point(0., DIM1v, 0.) + offset - ps, + libMesh::Point(DIM1v, 0., 0.) + offset - ps, + libMesh::Point(0. -DIM1v, 0.) + offset - ps, + libMesh::Point(-DIM1v, 0., 0.) + offset - ps + }; +} + + +const std::vector +MAST::Solid1DTubeSectionElementPropertyCard::get_stress_points_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, const libMesh::Point dps) const +{ + const MAST::FieldFunction + &DIM1 = this->get >("DIM1"), + &DIM2 = this->get >("DIM2"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real DIM1v, DIM2v, offset_y, offset_z; + Real dDIM1v, dDIM2v, doffset_y, doffset_z; + DIM1(p, t, DIM1v); DIM1.derivative(f, p, t, dDIM1v); + DIM2(p, t, DIM2v); DIM2.derivative(f, p, t, dDIM2v); + hy_off(p, t, offset_y); hy_off.derivative(f, p, t, doffset_y); + hz_off(p, t, offset_z); hz_off.derivative(f, p, t, doffset_z); + + libMesh::Point offset(offset_z, offset_y); + + libMesh::Point doffset(doffset_z, doffset_y); + + return {libMesh::Point(0., dDIM1v, 0.) + doffset - dps, + libMesh::Point(dDIM1v, 0., 0.) + doffset - dps, + libMesh::Point(0. -dDIM1v, 0.) + doffset - dps, + libMesh::Point(-dDIM1v, 0., 0.) + doffset - dps + }; +} + + +void MAST::Solid1DTubeSectionElementPropertyCard::init(const libMesh::LibMeshInit& init) +{ + libmesh_assert(!_initialized); + + MAST::FieldFunction + &DIM1 = this->get >("DIM1"), + &DIM2 = this->get >("DIM2"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + // Check that dimensions are physically correct + Real DIM1v, DIM2v; + DIM1(DIM1v); DIM2(DIM2v); + if (DIM1v<=0){ + libmesh_error_msg("DIM1<=0"); + } + else if (DIM2v<=0){ + libmesh_error_msg("DIM2<=0"); + } + else if (DIM2v>=DIM1v){ + libmesh_error_msg("DIM2>=DIM1"); + } + + // Create a cross section model of this section + cross_section.reset(new MAST::CrossSection(init, 3500, *this, libMesh::TRI6)); + +// _A.reset(new MAST::Solid1DnParameterSectionProperty::Area(*cross_section)); +// +// _Ay.reset(new MAST::Solid1DnParameterSectionProperty::AreaYMoment(*cross_section)); +// +// _Az.reset(new MAST::Solid1DnParameterSectionProperty::AreaZMoment(*cross_section)); +// +// _AI.reset(new MAST::Solid1DnParameterSectionProperty::AreaInertiaMatrix(*cross_section)); +// +// _Ip.reset(new MAST::Solid1DnParameterSectionProperty::PolarInertia(*cross_section)); +// +// _J.reset(new MAST::Solid1DnParameterSectionProperty::TorsionalConstant(*cross_section)); + + _A.reset(new MAST::Solid1D2ParameterSectionProperty::Area(MAST::Solid1DTubeSectionProperty::calcA, + MAST::Solid1DTubeSectionProperty::calcdA, + DIM1, DIM2)); + + _Ay.reset(new MAST::Solid1D2ParameterSectionProperty::AreaYMoment( + MAST::Solid1DTubeSectionProperty::calcA, + MAST::Solid1DTubeSectionProperty::calcdA, + DIM1, DIM2, + hz_off)); + + _Az.reset(new MAST::Solid1D2ParameterSectionProperty::AreaZMoment( + MAST::Solid1DTubeSectionProperty::calcA, + MAST::Solid1DTubeSectionProperty::calcdA, + DIM1, DIM2, + hy_off)); + + _AI.reset(new MAST::Solid1D2ParameterSectionProperty::AreaInertiaMatrix( + MAST::Solid1DTubeSectionProperty::calcIz, + MAST::Solid1DTubeSectionProperty::calcdIz, + MAST::Solid1DTubeSectionProperty::calcIy, + MAST::Solid1DTubeSectionProperty::calcdIy, + MAST::Solid1DTubeSectionProperty::calcA, + MAST::Solid1DTubeSectionProperty::calcdA, + DIM1, DIM2, + hy_off, + hz_off)); + + _Ip.reset(new MAST::Solid1D2ParameterSectionProperty::PolarInertia( + MAST::Solid1DTubeSectionProperty::calcIp, + MAST::Solid1DTubeSectionProperty::calcdIp, + MAST::Solid1DTubeSectionProperty::calcA, + MAST::Solid1DTubeSectionProperty::calcdA, + DIM1, DIM2, + hy_off, + hz_off)); + + _J.reset(new MAST::Solid1D2ParameterSectionProperty::TorsionalConstant( + MAST::Solid1DTubeSectionProperty::calcJ, + MAST::Solid1DTubeSectionProperty::calcdJ, + DIM1, DIM2)); + + _Kappa.reset(new MAST::Solid1DnParameterSectionProperty::ShearCoefficientMatrix(*cross_section)); + + _Gamma.reset(new MAST::Solid1DnParameterSectionProperty::WarpingConstant(*cross_section)); + + _initialized = true; +} + +void MAST::Solid1DTubeSectionElementPropertyCard::create_cross_section( + const libMesh::LibMeshInit& init, const uint n_target_elems, + const libMesh::ElemType element_type) +{ + cross_section.reset(new MAST::CrossSection(init, n_target_elems, + *this, element_type)); +} + + +void MAST::Solid1DTubeSectionElementPropertyCard::calculate_properties_pilkey() +{ + cross_section->calculate_geometric_properties(); + cross_section->calculate_warping_properties(); +} diff --git a/src/property_cards/solid_1d_tube_section_element_property_card.h b/src/property_cards/solid_1d_tube_section_element_property_card.h new file mode 100644 index 00000000..5b3a3648 --- /dev/null +++ b/src/property_cards/solid_1d_tube_section_element_property_card.h @@ -0,0 +1,117 @@ +/* + * MAST: Multidisciplinary-design Adaptation and Sensitivity Toolkit + * Copyright (C) 2013-2019 Manav Bhatia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * +// * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __mast__solid_1d_tube_section_element_property_card__ +#define __mast__solid_1d_tube_section_element_property_card__ + + +// MAST includes +#include "property_cards/solid_1d_nparameter_section_element_property_card.h" +#include "property_cards/solid_1d_2parameter_section_element_property_card.h" + + +// Annulus (TUBE in Siemens NX Nastran and Astros 21.2) +namespace MAST{ + namespace Solid1DTubeSectionProperty{ + void calcA(Real& DIM1, Real& DIM2, Real& A); + + void calcdA(Real& DIM1, Real& DIM2, Real& dDIM1, Real& dDIM2, Real& dA); + + void calcIz(Real& DIM1, Real& DIM2, Real& Iz); + + void calcdIz(Real& DIM1, Real& DIM2, Real& dDIM1, Real& dDIM2, Real& dIz); + + void calcIy(Real& DIM1, Real& DIM2, Real& Iy); + + void calcdIy(Real& DIM1, Real& DIM2, Real& dDIM1, Real& dDIM2, Real& dIy); + + void calcIp(Real& DIM1, Real& DIM2, Real& Ip); + + void calcdIp(Real& DIM1, Real& DIM2, Real& dDIM1, Real& dDIM2, Real& dIp); + + void calcJ(Real& DIM1, Real& DIM2, Real& J); + + void calcdJ(Real& DIM1, Real& DIM2, Real& dDIM1, Real& dDIM2, Real& dJ); + + } +} + +namespace MAST { + + class Solid1DTubeSectionElementPropertyCard : public MAST::Solid1DnParameterSectionElementPropertyCard + { + public: + Solid1DTubeSectionElementPropertyCard(): + MAST::Solid1DnParameterSectionElementPropertyCard() {} + + /*! + * virtual destructor + */ + virtual ~Solid1DTubeSectionElementPropertyCard() { } + + virtual void init(const libMesh::LibMeshInit& init); + + virtual void create_cross_section( + const libMesh::LibMeshInit& init, + const uint n_target_elems=3500, + const libMesh::ElemType element_type=libMesh::TRI6); + + virtual void calculate_properties_pilkey(); + + virtual const std::vector get_geom_points(const libMesh::Point& p, const Real t, const uint n=201) const override; + + virtual const std::vector get_geom_points_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, const uint n=201) const override; + + virtual const libMesh::Point get_shear_center(const libMesh::Point& p, const Real t) const override; + + virtual const libMesh::Point get_shear_center_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t) const; + + virtual const libMesh::Point get_centroid(const libMesh::Point& p, const Real t) const override; + + virtual const libMesh::Point get_centroid_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t) const override; + + virtual const std::vector get_stress_points(const libMesh::Point& p, const Real t, const libMesh::Point ps) const override; + + virtual const std::vector get_stress_points_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, const libMesh::Point dps) const override; + + virtual const std::vector> get_holes_points(const libMesh::Point& p, const Real t, const uint n=201) const override; + + virtual const std::vector> get_holes_points_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, const uint n=201) const override; + + std::unique_ptr cross_section; + + const bool is_bisymmetric() const + { + return true; + } + + const bool is_symmetric_z() const + { + return true; + } + + const bool is_symmetric_y() const + { + return true; + } + }; +} + + +#endif // __mast__solid_1d_tube_section_element_property_card__ diff --git a/tests/property/CMakeLists.txt b/tests/property/CMakeLists.txt index 48d482aa..2658d539 100644 --- a/tests/property/CMakeLists.txt +++ b/tests/property/CMakeLists.txt @@ -1,9 +1,10 @@ target_sources(mast_catch_tests PRIVATE ${CMAKE_CURRENT_LIST_DIR}/mast_solid_1d_section_element_property_card.cpp - ${CMAKE_CURRENT_LIST_DIR}/mast_solid_1d_arbitrary_section_element_property_card.cpp - ${CMAKE_CURRENT_LIST_DIR}/mast_solid_1d_rod_section_element_property_card.cpp + ${CMAKE_CURRENT_LIST_DIR}/mast_solid_1d_arbitrary_section_element_property_card ${CMAKE_CURRENT_LIST_DIR}/mast_solid_1d_bar_section_element_property_card.cpp + ${CMAKE_CURRENT_LIST_DIR}/mast_solid_1d_rod_section_element_property_card.cpp + ${CMAKE_CURRENT_LIST_DIR}/mast_solid_1d_tube_section_element_property_card.cpp ${CMAKE_CURRENT_LIST_DIR}/mast_solid_2d_section_element_property_card.cpp ${CMAKE_CURRENT_LIST_DIR}/mast_3d_isotropic_element_property_card.cpp) @@ -481,38 +482,43 @@ set_tests_properties(Rod_Element_Property_Card_1D_Dynamic_mpi ## ============================================================================ -# ## ============================================================================ -# # 1D TUBE Cross Section -# add_test(NAME Tube_Element_Property_Card_1D_Base -# COMMAND mast_catch_tests "tube_element_property_card_constant_base_1d") -# set_tests_properties(Tube_Element_Property_Card_1D_Base -# PROPERTIES -# FIXTURES_REQUIRED Isotropic_Material_1D_Structural) -# -# add_test(NAME Tube_Element_Property_Card_1D_Heat_Transfer -# COMMAND mast_catch_tests "tube_element_property_card_constant_heat_transfer_1d") -# set_tests_properties(Tube_Element_Property_Card_1D_Heat_Transfer -# PROPERTIES -# FIXTURES_REQUIRED Isotropic_Material_1D_Heat_Transfer) -# -# add_test(NAME Tube_Element_Property_Card_1D_Thermoelastic -# COMMAND mast_catch_tests "tube_element_property_card_constant_thermoelastic_1d") -# set_tests_properties(Tube_Element_Property_Card_1D_Thermoelastic -# PROPERTIES -# FIXTURES_REQUIRED Isotropic_Material_1D_Thermoelastic) -# -# add_test(NAME Tube_Element_Property_Card_1D_Structural -# COMMAND mast_catch_tests "tube_element_property_card_constant_structural_1d") -# set_tests_properties(Tube_Element_Property_Card_1D_Structural -# PROPERTIES -# FIXTURES_REQUIRED Isotropic_Material_1D_Structural) -# -# add_test(NAME Tube_Element_Property_Card_1D_Dynamic -# COMMAND mast_catch_tests "tube_element_property_card_constant_dynamic_1d") -# set_tests_properties(Tube_Element_Property_Card_1D_Dynamic -# PROPERTIES -# FIXTURES_REQUIRED Isotropic_Material_1D_Dynamic) -# ## ============================================================================ +## ============================================================================ +# 1D TUBE Cross Section +add_test(NAME Tube_Element_Property_Card_1D_Base + COMMAND $ "tube_element_property_card_constant_base_1d") +set_tests_properties(Tube_Element_Property_Card_1D_Base + PROPERTIES + LABELS "SEQ" + FIXTURES_REQUIRED Isotropic_Material_1D_Structural) + +add_test(NAME Tube_Element_Property_Card_1D_Heat_Transfer + COMMAND $ "tube_element_property_card_constant_heat_transfer_1d") +set_tests_properties(Tube_Element_Property_Card_1D_Heat_Transfer + PROPERTIES + LABELS "SEQ" + FIXTURES_REQUIRED Isotropic_Material_1D_Heat_Transfer) + +add_test(NAME Tube_Element_Property_Card_1D_Thermoelastic + COMMAND $ "tube_element_property_card_constant_thermoelastic_1d") +set_tests_properties(Tube_Element_Property_Card_1D_Thermoelastic + PROPERTIES + LABELS "SEQ" + FIXTURES_REQUIRED Isotropic_Material_1D_Thermoelastic) + +add_test(NAME Tube_Element_Property_Card_1D_Structural + COMMAND $ "tube_element_property_card_constant_structural_1d") +set_tests_properties(Tube_Element_Property_Card_1D_Structural + PROPERTIES + LABELS "SEQ" + FIXTURES_REQUIRED Isotropic_Material_1D_Structural) + +add_test(NAME Tube_Element_Property_Card_1D_Dynamic + COMMAND $ "tube_element_property_card_constant_dynamic_1d") +set_tests_properties(Tube_Element_Property_Card_1D_Dynamic + PROPERTIES + LABELS "SEQ" + FIXTURES_REQUIRED Isotropic_Material_1D_Dynamic) +## ============================================================================ # ## ============================================================================ diff --git a/tests/property/mast_solid_1d_tube_section_element_property_card.cpp b/tests/property/mast_solid_1d_tube_section_element_property_card.cpp new file mode 100644 index 00000000..ba5f02cf --- /dev/null +++ b/tests/property/mast_solid_1d_tube_section_element_property_card.cpp @@ -0,0 +1,1020 @@ +// Catch2 includes +#include "catch.hpp" + +// libMesh includes +#include "libmesh/point.h" + +// MAST includes +#include "base/parameter.h" +#include "base/constant_field_function.h" +#include "property_cards/isotropic_material_property_card.h" +#include "property_cards/solid_1d_tube_section_element_property_card.h" + +// Custom includes +#include "test_helpers.h" + +extern libMesh::LibMeshInit* p_global_init; + +#define PI 3.1415926535897932 + + +TEST_CASE("tube_element_property_card_constant_base_1d", + "[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + + const Real cE = 72.0e9; + const Real cnu = 0.33; + const Real cG = cE / (2.0 * (1.0+cnu) ); + const Real calpha = 5.43e-05; + const Real crho = 1420.5; + const Real ccp = 908.0; + const Real ck = 237.0; + const Real ckappa = 5.3284279639775167e-01; + + const Real coff_y = 0.35; + const Real coff_z = 0.26; + + // Define Material Properties as MAST Parameters + MAST::Parameter E("E_param", cE); // Modulus of Elasticity + MAST::Parameter nu("nu_param", cnu); // Poisson's ratio + MAST::Parameter alpha("alpha_param", calpha); // Coefficient of thermal expansion + MAST::Parameter rho("rho_param", crho); // Density + MAST::Parameter cp("cp_param", ccp); // Specific Heat Capacity + MAST::Parameter k("k_param", ck); // Thermal Conductivity + + // Define Section Properties as MAST Parameters + MAST::Parameter r_o("DIM1", 1.125); // Outer radius + MAST::Parameter r_i("DIM2", 0.750); // Inner radius + MAST::Parameter offset_y("offy_param", coff_y); // Section offset in y-direction + MAST::Parameter offset_z("offz_param", coff_z); // Section offset in z-direction + + // Create field functions to dsitribute these constant parameters throughout the model + // Section Property Field Functions + MAST::ConstantFieldFunction DIM1_f("DIM1", r_o); + MAST::ConstantFieldFunction DIM2_f("DIM2", r_i); + MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); + MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); + // Material Property Field Functions + MAST::ConstantFieldFunction E_f("E", E); + MAST::ConstantFieldFunction nu_f("nu", nu); + MAST::ConstantFieldFunction alpha_f("alpha_expansion", alpha); + MAST::ConstantFieldFunction rho_f("rho", rho); + MAST::ConstantFieldFunction cp_f("cp", cp); + MAST::ConstantFieldFunction k_f("k_th", k); + + // Initialize the material + MAST::IsotropicMaterialPropertyCard material; + + // Add the material property constant field functions to the material card + material.add(rho_f); + material.add(k_f); + material.add(cp_f); + material.add(E_f); + material.add(nu_f); + material.add(alpha_f); + + // Initialize the section + MAST::Solid1DTubeSectionElementPropertyCard section; + + + // Add the section property constant field functions to the section card + section.add(DIM1_f); + section.add(DIM2_f); + section.add(offsety_f); + section.add(offsetz_f); + + // Add the material card to the section card + section.set_material(material); + + // Specify a section orientation point and add it to the section. + RealVectorX orientation = RealVectorX::Zero(3); + orientation(1) = 1.0; + section.y_vector() = orientation; + + // Now initialize the section + section.init(*p_global_init); + + // True values + const Real ro = r_o(); + const Real ri = r_i(); + const Real area_true = PI*(pow(ro,2.0) - pow(ri,2.0)); + const Real first_area_moment_z_true = area_true * coff_y; + const Real first_area_moment_y_true = area_true * coff_z; + const Real Izzc_true = PI*(pow(ro,4.0) - pow(ri,4.0))/4.0; + const Real Iyyc_true = PI*(pow(ro,4.0) - pow(ri,4.0))/4.0; + const Real Izyc_true = 0.0; + const Real Ipc_true = PI*(pow(ro,4.0) - pow(ri,4.0))/2.0; + const Real second_area_moment_zz_true = Izzc_true + area_true * coff_y * coff_y; + const Real second_area_moment_yy_true = Iyyc_true + area_true * coff_z * coff_z; + const Real second_area_moment_zy_true = Izyc_true + area_true * coff_y * coff_z; + const Real second_area_moment_polar_true = second_area_moment_zz_true + second_area_moment_yy_true; + + const Real torsion_constant_true = 2.0184430643017226e+00; + const Real warping_constant_true = 2.7224768298299495e-11; + const Real kappa_z_true = 5.3284267813657360e-01; + const Real kappa_y_true = 5.3284267085782810e-01; + const Real xs_true = coff_z; + const Real ys_true = coff_y; + const Real xc_true = coff_z; + const Real yc_true = coff_y; + + const libMesh::Point point(4.3, -3.5, -6.7); + const Real time = 8.22; + + REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional + REQUIRE( section.depends_on(r_o) ); + REQUIRE( section.depends_on(offset_y) ); + REQUIRE( section.depends_on(r_i) ); + REQUIRE( section.depends_on(offset_z) ); + REQUIRE( section.depends_on(k) ); + REQUIRE( section.depends_on(cp) ); + REQUIRE( section.depends_on(rho) ); + REQUIRE( section.if_isotropic() ); + + REQUIRE_FALSE( section.if_diagonal_mass_matrix() ); + + section.set_diagonal_mass_matrix(true); + REQUIRE( section.if_diagonal_mass_matrix() ); +} + + +TEST_CASE("tube_element_property_card_constant_heat_transfer_1d", + "[heat_transfer],[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + + const Real cE = 72.0e9; + const Real cnu = 0.33; + const Real cG = cE / (2.0 * (1.0+cnu) ); + const Real calpha = 5.43e-05; + const Real crho = 1420.5; + const Real ccp = 908.0; + const Real ck = 237.0; + const Real ckappa = 5.3284279639775167e-01; + + const Real coff_y = 0.35; + const Real coff_z = 0.26; + + // Define Material Properties as MAST Parameters + MAST::Parameter E("E_param", cE); // Modulus of Elasticity + MAST::Parameter nu("nu_param", cnu); // Poisson's ratio + MAST::Parameter alpha("alpha_param", calpha); // Coefficient of thermal expansion + MAST::Parameter rho("rho_param", crho); // Density + MAST::Parameter cp("cp_param", ccp); // Specific Heat Capacity + MAST::Parameter k("k_param", ck); // Thermal Conductivity + + // Define Section Properties as MAST Parameters + MAST::Parameter r_o("DIM1", 1.125); // Outer radius + MAST::Parameter r_i("DIM2", 0.750); // Inner radius + MAST::Parameter offset_y("offy_param", coff_y); // Section offset in y-direction + MAST::Parameter offset_z("offz_param", coff_z); // Section offset in z-direction + + // Create field functions to dsitribute these constant parameters throughout the model + // Section Property Field Functions + MAST::ConstantFieldFunction DIM1_f("DIM1", r_o); + MAST::ConstantFieldFunction DIM2_f("DIM2", r_i); + MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); + MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); + // Material Property Field Functions + MAST::ConstantFieldFunction E_f("E", E); + MAST::ConstantFieldFunction nu_f("nu", nu); + MAST::ConstantFieldFunction alpha_f("alpha_expansion", alpha); + MAST::ConstantFieldFunction rho_f("rho", rho); + MAST::ConstantFieldFunction cp_f("cp", cp); + MAST::ConstantFieldFunction k_f("k_th", k); + + // Initialize the material + MAST::IsotropicMaterialPropertyCard material; + + // Add the material property constant field functions to the material card + material.add(rho_f); + material.add(k_f); + material.add(cp_f); + material.add(E_f); + material.add(nu_f); + material.add(alpha_f); + + // Initialize the section + MAST::Solid1DTubeSectionElementPropertyCard section; + + + // Add the section property constant field functions to the section card + section.add(DIM1_f); + section.add(DIM2_f); + section.add(offsety_f); + section.add(offsetz_f); + + // Add the material card to the section card + section.set_material(material); + + // Specify a section orientation point and add it to the section. + RealVectorX orientation = RealVectorX::Zero(3); + orientation(1) = 1.0; + section.y_vector() = orientation; + + // Now initialize the section + section.init(*p_global_init); + + // True values + const Real ro = r_o(); + const Real ri = r_i(); + const Real area_true = PI*(pow(ro,2.0) - pow(ri,2.0)); + const Real first_area_moment_z_true = area_true * coff_y; + const Real first_area_moment_y_true = area_true * coff_z; + const Real Izzc_true = PI*(pow(ro,4.0) - pow(ri,4.0))/4.0; + const Real Iyyc_true = PI*(pow(ro,4.0) - pow(ri,4.0))/4.0; + const Real Izyc_true = 0.0; + const Real Ipc_true = PI*(pow(ro,4.0) - pow(ri,4.0))/2.0; + const Real second_area_moment_zz_true = Izzc_true + area_true * coff_y * coff_y; + const Real second_area_moment_yy_true = Iyyc_true + area_true * coff_z * coff_z; + const Real second_area_moment_zy_true = Izyc_true + area_true * coff_y * coff_z; + const Real second_area_moment_polar_true = second_area_moment_zz_true + second_area_moment_yy_true; + + const Real torsion_constant_true = 2.0184430643017226e+00; + const Real warping_constant_true = 2.7224768298299495e-11; + const Real kappa_z_true = 5.3284267813657360e-01; + const Real kappa_y_true = 5.3284267085782810e-01; + const Real xs_true = coff_z; + const Real ys_true = coff_y; + const Real xc_true = coff_z; + const Real yc_true = coff_y; + + const libMesh::Point point(4.3, -3.5, -6.7); + const Real time = 8.22; + + Real area; + const MAST::FieldFunction& Area = section.A(); + Area(point, time, area); + REQUIRE( area == Approx(area_true) ); + + + SECTION("1D section thermal conductance matrix") + { + /** + * As of Dec. 17, 2019, inertia_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * inertia_matrix to be obtained without any input arguments. + */ + std::unique_ptr> conduct_mat = section.thermal_conductance_matrix(); + + RealMatrixX D_sec_conduc; + conduct_mat->operator()(point, time, D_sec_conduc); + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_conduc_true = RealMatrixX::Zero(1,1); + D_sec_conduc_true(0,0) = ck * area_true; + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_conduc); + std::vector truth = eigen_matrix_to_std_vector(D_sec_conduc_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } + + SECTION("1D section thermal capacitance matrix") + { + /** + * As of Dec. 17, 2019, inertia_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * inertia_matrix to be obtained without any input arguments. + */ + std::unique_ptr> capaci_mat = section.thermal_capacitance_matrix(); + + RealMatrixX D_sec_capac; + capaci_mat->operator()(point, time, D_sec_capac); + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_capac_true = RealMatrixX::Zero(1,1); + D_sec_capac_true(0,0) = ccp * crho * area_true; + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_capac); + std::vector truth = eigen_matrix_to_std_vector(D_sec_capac_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } +} + + +TEST_CASE("tube_element_property_card_constant_thermoelastic_1d", + "[thermoelastic],[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + + const Real cE = 72.0e9; + const Real cnu = 0.33; + const Real cG = cE / (2.0 * (1.0+cnu) ); + const Real calpha = 5.43e-05; + const Real crho = 1420.5; + const Real ccp = 908.0; + const Real ck = 237.0; + const Real ckappa = 5.3284279639775167e-01; + + const Real coff_y = 0.35; + const Real coff_z = 0.26; + + // Define Material Properties as MAST Parameters + MAST::Parameter E("E_param", cE); // Modulus of Elasticity + MAST::Parameter nu("nu_param", cnu); // Poisson's ratio + MAST::Parameter alpha("alpha_param", calpha); // Coefficient of thermal expansion + MAST::Parameter rho("rho_param", crho); // Density + MAST::Parameter cp("cp_param", ccp); // Specific Heat Capacity + MAST::Parameter k("k_param", ck); // Thermal Conductivity + + // Define Section Properties as MAST Parameters + MAST::Parameter r_o("DIM1", 1.125); // Outer radius + MAST::Parameter r_i("DIM2", 0.750); // Inner radius + MAST::Parameter offset_y("offy_param", coff_y); // Section offset in y-direction + MAST::Parameter offset_z("offz_param", coff_z); // Section offset in z-direction + + // Create field functions to dsitribute these constant parameters throughout the model + // Section Property Field Functions + MAST::ConstantFieldFunction DIM1_f("DIM1", r_o); + MAST::ConstantFieldFunction DIM2_f("DIM2", r_i); + MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); + MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); + // Material Property Field Functions + MAST::ConstantFieldFunction E_f("E", E); + MAST::ConstantFieldFunction nu_f("nu", nu); + MAST::ConstantFieldFunction alpha_f("alpha_expansion", alpha); + MAST::ConstantFieldFunction rho_f("rho", rho); + MAST::ConstantFieldFunction cp_f("cp", cp); + MAST::ConstantFieldFunction k_f("k_th", k); + + // Initialize the material + MAST::IsotropicMaterialPropertyCard material; + + // Add the material property constant field functions to the material card + material.add(rho_f); + material.add(k_f); + material.add(cp_f); + material.add(E_f); + material.add(nu_f); + material.add(alpha_f); + + // Initialize the section + MAST::Solid1DTubeSectionElementPropertyCard section; + + + // Add the section property constant field functions to the section card + section.add(DIM1_f); + section.add(DIM2_f); + section.add(offsety_f); + section.add(offsetz_f); + + // Add the material card to the section card + section.set_material(material); + + // Specify a section orientation point and add it to the section. + RealVectorX orientation = RealVectorX::Zero(3); + orientation(1) = 1.0; + section.y_vector() = orientation; + + // Now initialize the section + section.init(*p_global_init); + + // True values + const Real ro = r_o(); + const Real ri = r_i(); + const Real area_true = PI*(pow(ro,2.0) - pow(ri,2.0)); + const Real first_area_moment_z_true = area_true * coff_y; + const Real first_area_moment_y_true = area_true * coff_z; + const Real Izzc_true = PI*(pow(ro,4.0) - pow(ri,4.0))/4.0; + const Real Iyyc_true = PI*(pow(ro,4.0) - pow(ri,4.0))/4.0; + const Real Izyc_true = 0.0; + const Real Ipc_true = PI*(pow(ro,4.0) - pow(ri,4.0))/2.0; + const Real second_area_moment_zz_true = Izzc_true + area_true * coff_y * coff_y; + const Real second_area_moment_yy_true = Iyyc_true + area_true * coff_z * coff_z; + const Real second_area_moment_zy_true = Izyc_true + area_true * coff_y * coff_z; + const Real second_area_moment_polar_true = second_area_moment_zz_true + second_area_moment_yy_true; + + const Real torsion_constant_true = 2.0184430643017226e+00; + const Real warping_constant_true = 2.7224768298299495e-11; + const Real kappa_z_true = 5.3284267813657360e-01; + const Real kappa_y_true = 5.3284267085782810e-01; + const Real xs_true = coff_z; + const Real ys_true = coff_y; + const Real xc_true = coff_z; + const Real yc_true = coff_y; + + const libMesh::Point point(4.3, -3.5, -6.7); + const Real time = 8.22; + + SECTION("1D thermal expansion A matrix") + { + /** + * As of Dec. 17, 2019, thermal_expansion_A_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * thermal_expansion_A_matrix to be obtained without any input arguments. + */ + + Real area; + const MAST::FieldFunction& Area = section.A(); + Area(point, time, area); + CHECK( area == Approx(area_true) ); + + std::unique_ptr> texp_A_mat = section.thermal_expansion_A_matrix(); + + RealMatrixX D_sec_texpA; + texp_A_mat->operator()(point, time, D_sec_texpA); + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_texpA_true = RealMatrixX::Zero(2,1); + D_sec_texpA_true(0,0) = cE * calpha * area_true; + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_texpA); + std::vector truth = eigen_matrix_to_std_vector(D_sec_texpA_true); + + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } + + SECTION("1D thermal expansion B matrix") + { + /** + * As of Dec. 17, 2019, thermal_expansion_B_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * thermal_expansion_B_matrix to be obtained without any input arguments. + */ + + Real first_area_moment_y; + const MAST::FieldFunction& Ay = section.Ay(); + Ay(point, time, first_area_moment_y); + CHECK( first_area_moment_y == Approx(first_area_moment_y_true) ); + + Real first_area_moment_z; + const MAST::FieldFunction& Az = section.Az(); + Az(point, time, first_area_moment_z); + CHECK( first_area_moment_z == Approx(first_area_moment_z_true) ); + + std::unique_ptr> texp_B_mat = section.thermal_expansion_B_matrix(); + + RealMatrixX D_sec_texpB; + texp_B_mat->operator()(point, time, D_sec_texpB); + + libMesh::out << "texp_B_mat =\n" << D_sec_texpB << std::endl; + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_texpB_true = RealMatrixX::Zero(2,1); + D_sec_texpB_true(0,0) = cE * calpha * first_area_moment_z; + D_sec_texpB_true(1,0) = cE * calpha * first_area_moment_y; + + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_texpB); + std::vector truth = eigen_matrix_to_std_vector(D_sec_texpB_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } +} + + +TEST_CASE("tube_element_property_card_constant_dynamic_1d", + "[dynamic],[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + + const Real cE = 72.0e9; + const Real cnu = 0.33; + const Real cG = cE / (2.0 * (1.0+cnu) ); + const Real calpha = 5.43e-05; + const Real crho = 1420.5; + const Real ccp = 908.0; + const Real ck = 237.0; + const Real ckappa = 5.3284279639775167e-01; + + const Real coff_y = 0.35; + const Real coff_z = 0.26; + + // Define Material Properties as MAST Parameters + MAST::Parameter E("E_param", cE); // Modulus of Elasticity + MAST::Parameter nu("nu_param", cnu); // Poisson's ratio + MAST::Parameter alpha("alpha_param", calpha); // Coefficient of thermal expansion + MAST::Parameter rho("rho_param", crho); // Density + MAST::Parameter cp("cp_param", ccp); // Specific Heat Capacity + MAST::Parameter k("k_param", ck); // Thermal Conductivity + + // Define Section Properties as MAST Parameters + MAST::Parameter r_o("DIM1", 1.125); // Outer radius + MAST::Parameter r_i("DIM2", 0.750); // Inner radius + MAST::Parameter offset_y("offy_param", coff_y); // Section offset in y-direction + MAST::Parameter offset_z("offz_param", coff_z); // Section offset in z-direction + + // Create field functions to dsitribute these constant parameters throughout the model + // Section Property Field Functions + MAST::ConstantFieldFunction DIM1_f("DIM1", r_o); + MAST::ConstantFieldFunction DIM2_f("DIM2", r_i); + MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); + MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); + // Material Property Field Functions + MAST::ConstantFieldFunction E_f("E", E); + MAST::ConstantFieldFunction nu_f("nu", nu); + MAST::ConstantFieldFunction alpha_f("alpha_expansion", alpha); + MAST::ConstantFieldFunction rho_f("rho", rho); + MAST::ConstantFieldFunction cp_f("cp", cp); + MAST::ConstantFieldFunction k_f("k_th", k); + + // Initialize the material + MAST::IsotropicMaterialPropertyCard material; + + // Add the material property constant field functions to the material card + material.add(rho_f); + material.add(k_f); + material.add(cp_f); + material.add(E_f); + material.add(nu_f); + material.add(alpha_f); + + // Initialize the section + MAST::Solid1DTubeSectionElementPropertyCard section; + + + // Add the section property constant field functions to the section card + section.add(DIM1_f); + section.add(DIM2_f); + section.add(offsety_f); + section.add(offsetz_f); + + // Add the material card to the section card + section.set_material(material); + + // Specify a section orientation point and add it to the section. + RealVectorX orientation = RealVectorX::Zero(3); + orientation(1) = 1.0; + section.y_vector() = orientation; + + // Now initialize the section + section.init(*p_global_init); + + // True values + const Real ro = r_o(); + const Real ri = r_i(); + const Real area_true = PI*(pow(ro,2.0) - pow(ri,2.0)); + const Real first_area_moment_z_true = area_true * coff_y; + const Real first_area_moment_y_true = area_true * coff_z; + const Real Izzc_true = PI*(pow(ro,4.0) - pow(ri,4.0))/4.0; + const Real Iyyc_true = PI*(pow(ro,4.0) - pow(ri,4.0))/4.0; + const Real Izyc_true = 0.0; + const Real Ipc_true = PI*(pow(ro,4.0) - pow(ri,4.0))/2.0; + const Real second_area_moment_zz_true = Izzc_true + area_true * coff_y * coff_y; + const Real second_area_moment_yy_true = Iyyc_true + area_true * coff_z * coff_z; + const Real second_area_moment_zy_true = Izyc_true + area_true * coff_y * coff_z; + const Real second_area_moment_polar_true = second_area_moment_zz_true + second_area_moment_yy_true; + + const Real torsion_constant_true = 2.0184430643017226e+00; + const Real warping_constant_true = 2.7224768298299495e-11; + const Real kappa_z_true = 5.3284267813657360e-01; + const Real kappa_y_true = 5.3284267085782810e-01; + const Real xs_true = coff_z; + const Real ys_true = coff_y; + const Real xc_true = coff_z; + const Real yc_true = coff_y; + + const libMesh::Point point(4.3, -3.5, -6.7); + const Real time = 8.22; + + SECTION("1D section inertia matrix") + { + /** + * As of Dec. 17, 2019, inertia_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * inertia_matrix to be obtained without any input arguments. + */ + std::unique_ptr> inertia_mat = section.inertia_matrix(); + + RealMatrixX D_sec_iner; + inertia_mat->operator()(point, time, D_sec_iner); + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_iner_true = RealMatrixX::Zero(6,6); + + Real area; + const MAST::FieldFunction& Area = section.A(); + Area(point, time, area); + REQUIRE( area == Approx(area_true) ); + D_sec_iner_true(0,0) = D_sec_iner_true(1,1) = D_sec_iner_true(2,2) = area_true; + + Real Ip; + const MAST::FieldFunction& PolarInertia = section.Ip(); + PolarInertia(point, time, Ip); + CHECK( Ip == Approx(second_area_moment_polar_true) ); + D_sec_iner_true(3,3) = second_area_moment_polar_true; + + Real first_area_moment_y; + const MAST::FieldFunction& Ay = section.Ay(); + Ay(point, time, first_area_moment_y); + CHECK( first_area_moment_y == Approx(first_area_moment_y_true) ); + D_sec_iner_true(0,4) = D_sec_iner_true(4,0) = first_area_moment_y_true; + + Real first_area_moment_z; + const MAST::FieldFunction& Az = section.Az(); + Az(point, time, first_area_moment_z); + CHECK( first_area_moment_z == Approx(first_area_moment_z_true) ); + D_sec_iner_true(0,5) = D_sec_iner_true(5,0) = first_area_moment_z_true; + + RealMatrixX I; + const MAST::FieldFunction& Inertias = section.I(); + Inertias(point, time, I); + REQUIRE( I(0,1) == I(1,0) ); + Real Iyy = I(1,1); + Real Izz = I(0,0); + Real Izy = I(0,1); + REQUIRE( Izz == Approx(second_area_moment_zz_true) ); + REQUIRE( Iyy == Approx(second_area_moment_yy_true) ); + REQUIRE( Izy == Approx(second_area_moment_zy_true) ); + + D_sec_iner_true(4,4) = Iyy; // TODO: Should this be Izz? + D_sec_iner_true(4,5) = Izy; + D_sec_iner_true(5,4) = Izy; + D_sec_iner_true(5,5) = Izz; // TODO: Should this be Iyy?? + + D_sec_iner_true *= rho(); + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_iner); + std::vector truth = eigen_matrix_to_std_vector(D_sec_iner_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } +} + + +TEST_CASE("tube_element_property_card_constant_structural_1d", + "[structural],[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + + const Real cE = 72.0e9; + const Real cnu = 0.33; + const Real cG = cE / (2.0 * (1.0+cnu) ); + const Real calpha = 5.43e-05; + const Real crho = 1420.5; + const Real ccp = 908.0; + const Real ck = 237.0; + const Real ckappa = 5.3284279639775167e-01; + + const Real coff_y = 0.35; + const Real coff_z = 0.26; + + // Define Material Properties as MAST Parameters + MAST::Parameter E("E_param", cE); // Modulus of Elasticity + MAST::Parameter nu("nu_param", cnu); // Poisson's ratio + MAST::Parameter alpha("alpha_param", calpha); // Coefficient of thermal expansion + MAST::Parameter rho("rho_param", crho); // Density + MAST::Parameter cp("cp_param", ccp); // Specific Heat Capacity + MAST::Parameter k("k_param", ck); // Thermal Conductivity + + // Define Section Properties as MAST Parameters + MAST::Parameter r_o("DIM1", 1.125); // Outer radius + MAST::Parameter r_i("DIM2", 0.750); // Inner radius + MAST::Parameter offset_y("offy_param", coff_y); // Section offset in y-direction + MAST::Parameter offset_z("offz_param", coff_z); // Section offset in z-direction + + // Create field functions to dsitribute these constant parameters throughout the model + // Section Property Field Functions + MAST::ConstantFieldFunction DIM1_f("DIM1", r_o); + MAST::ConstantFieldFunction DIM2_f("DIM2", r_i); + MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); + MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); + // Material Property Field Functions + MAST::ConstantFieldFunction E_f("E", E); + MAST::ConstantFieldFunction nu_f("nu", nu); + MAST::ConstantFieldFunction alpha_f("alpha_expansion", alpha); + MAST::ConstantFieldFunction rho_f("rho", rho); + MAST::ConstantFieldFunction cp_f("cp", cp); + MAST::ConstantFieldFunction k_f("k_th", k); + + // Initialize the material + MAST::IsotropicMaterialPropertyCard material; + + // Add the material property constant field functions to the material card + material.add(rho_f); + material.add(k_f); + material.add(cp_f); + material.add(E_f); + material.add(nu_f); + material.add(alpha_f); + + // Initialize the section + MAST::Solid1DTubeSectionElementPropertyCard section; + + + // Add the section property constant field functions to the section card + section.add(DIM1_f); + section.add(DIM2_f); + section.add(offsety_f); + section.add(offsetz_f); + + // Add the material card to the section card + section.set_material(material); + + // Specify a section orientation point and add it to the section. + RealVectorX orientation = RealVectorX::Zero(3); + orientation(1) = 1.0; + section.y_vector() = orientation; + + // Now initialize the section + section.init(*p_global_init); + + // True values + const Real ro = r_o(); + const Real ri = r_i(); + const Real area_true = PI*(pow(ro,2.0) - pow(ri,2.0)); + const Real first_area_moment_z_true = area_true * coff_y; + const Real first_area_moment_y_true = area_true * coff_z; + const Real Izzc_true = PI*(pow(ro,4.0) - pow(ri,4.0))/4.0; + const Real Iyyc_true = PI*(pow(ro,4.0) - pow(ri,4.0))/4.0; + const Real Izyc_true = 0.0; + const Real Ipc_true = PI*(pow(ro,4.0) - pow(ri,4.0))/2.0; + const Real second_area_moment_zz_true = Izzc_true + area_true * coff_y * coff_y; + const Real second_area_moment_yy_true = Iyyc_true + area_true * coff_z * coff_z; + const Real second_area_moment_zy_true = Izyc_true + area_true * coff_y * coff_z; + const Real second_area_moment_polar_true = second_area_moment_zz_true + second_area_moment_yy_true; + + const Real torsion_constant_true = 2.0184430643017226e+00; + const Real warping_constant_true = 2.7224768298299495e-11; + const Real kappa_z_true = 5.3284267813657360e-01; + const Real kappa_y_true = 5.3284267085782810e-01; + const Real xs_true = coff_z; + const Real ys_true = coff_y; + const Real xc_true = coff_z; + const Real yc_true = coff_y; + + const libMesh::Point point(4.3, -3.5, -6.7); + const Real time = 8.22; + + SECTION("set_get_bending_model") + { + // NOTE: MAST::DKT and MAST::MINDLIN are not valid options for 1D sections, even though their input is accepted. + section.set_bending_model(MAST::BERNOULLI); + section.set_bending_model(MAST::DEFAULT_BENDING); + section.set_bending_model(MAST::NO_BENDING); + section.set_bending_model(MAST::TIMOSHENKO); + + // TODO: Implement element creation for testing of getting bending_model and checking default + //REQUIRE( section.bending_model() + } + +// SECTION("quadrature_order") +// { +// section.set_bending_model(MAST::MINDLIN); +// REQUIRE( section.extra_quadrature_order(elem) == 0 ); +// +// section.set_bending_model(MAST::DKT); +// REQUIRE( section.extra_quadrature_order(elem) == 2 ); +// } + + SECTION("1D extension stiffness matrix") + { + /** + * As of Dec. 17, 2019, stiffness_A_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * stiffness_A_matrix to be obtained without any input arguments. + */ + Real area; + const MAST::FieldFunction& Area = section.A(); + Area(point, time, area); + REQUIRE( area == Approx(area_true) ); + + Real torsion_constant; + const MAST::FieldFunction& TorsionConstant = section.J(); + TorsionConstant(point, time, torsion_constant); + REQUIRE( torsion_constant == Approx(torsion_constant_true).epsilon(0.05) ); + + std::unique_ptr> extension_stiffness_mat = section.stiffness_A_matrix(); + + RealMatrixX D_sec_ext; + extension_stiffness_mat->operator()(point, time, D_sec_ext); + + libMesh::out << "D_sec_ext\n" << D_sec_ext << std::endl; + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_ext_true = RealMatrixX::Zero(2,2); + D_sec_ext_true(0,0) = cE * area_true; + D_sec_ext_true(1,1) = cG * torsion_constant_true; + + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_ext); + std::vector truth = eigen_matrix_to_std_vector(D_sec_ext_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth).epsilon(0.05) ); + } + + + SECTION("1D bending section stiffness matrix") + { + /** + * As of Dec. 17, 2019, stiffness_D_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * stiffness_D_matrix to be obtained without any input arguments. + */ + RealMatrixX I; + const MAST::FieldFunction& Inertias = section.I(); + Inertias(point, time, I); + REQUIRE( I(0,1) == I(1,0) ); + Real Iyy = I(1,1); + Real Izz = I(0,0); + Real Izy = I(0,1); + REQUIRE( Izz == Approx(second_area_moment_zz_true) ); + REQUIRE( Iyy == Approx(second_area_moment_yy_true) ); + REQUIRE( Izy == Approx(second_area_moment_zy_true) ); + + std::unique_ptr> bending_stiffness_mat = section.stiffness_D_matrix(); + + RealMatrixX D_sec_bnd; + bending_stiffness_mat->operator()(point, time, D_sec_bnd); + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_bnd_true = RealMatrixX::Zero(2,2); + D_sec_bnd_true(0,0) = cE * second_area_moment_zz_true; + D_sec_bnd_true(1,1) = cE * second_area_moment_yy_true; + D_sec_bnd_true(0,1) = cE * second_area_moment_zy_true; + D_sec_bnd_true(1,0) = cE * second_area_moment_zy_true; + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_bnd); + std::vector truth = eigen_matrix_to_std_vector(D_sec_bnd_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } + + SECTION("1D extension-bending section stiffness matrix") + { + /** + * As of Dec. 17, 2019, stiffness_B_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * stiffness_B_matrix to be obtained without any input arguments. + */ + Real first_area_moment_y; + const MAST::FieldFunction& Ay = section.Ay(); + Ay(point, time, first_area_moment_y); + CHECK( first_area_moment_y == Approx(first_area_moment_y_true) ); + + Real first_area_moment_z; + const MAST::FieldFunction& Az = section.Az(); + Az(point, time, first_area_moment_z); + CHECK( first_area_moment_z == Approx(first_area_moment_z_true) ); + + std::unique_ptr> bndext_stiffness_mat = section.stiffness_B_matrix(); + + RealMatrixX D_sec_bndext; + bndext_stiffness_mat->operator()(point, time, D_sec_bndext); + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_bndext_true = RealMatrixX::Zero(2,2); + D_sec_bndext_true(0,0) = cE * first_area_moment_z_true; + D_sec_bndext_true(0,1) = cE * first_area_moment_y_true; + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_bndext); + std::vector truth = eigen_matrix_to_std_vector(D_sec_bndext_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } + + SECTION("1D transverse shear section stiffness matrix") + { + /** + * As of Dec. 17, 2019, transverse_shear_stiffness_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * transverse_shear_stiffness_matrix to be obtained without any input arguments. + */ + Real area; + const MAST::FieldFunction& Area = section.A(); + Area(point, time, area); + REQUIRE( area == Approx(area_true) ); + + std::unique_ptr> trans_shear_stiffness_mat = section.transverse_shear_stiffness_matrix(); + + RealMatrixX D_sec_shr; + trans_shear_stiffness_mat->operator()(point, time, D_sec_shr); + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_shr_true = RealMatrixX::Zero(2,2); + D_sec_shr_true(0,0) = cG * kappa_z_true * area_true; + D_sec_shr_true(1,1) = cG * kappa_y_true * area_true; + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_shr); + std::vector truth = eigen_matrix_to_std_vector(D_sec_shr_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth).epsilon(0.01) ); + } + + +// SECTION("1D spring section stiffness matrix") +// { +// /** +// * As of Dec. 17, 2019, spring_stiffness_matrix requires the input of an +// * MAST::ElementBase object, but does not actually use it. To get +// * around requiring the creation of such an object (and therefore +// * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, +// * and MAST::GeomElem objects as well). +// * +// * To remedy this, an additional method was added to MAST which allows +// * transverse_shear_stiffness_matrix to be obtained without any input arguments. +// */ +// std::unique_ptr> spring_stiffness_mat = section.stiffness_S_matrix(); +// +// RealMatrixX D_sec_spring; +// spring_stiffness_mat->operator()(point, time, D_sec_spring); +// +// // Hard-coded value of the section's extension stiffness +// // NOTE: Should be all zero's for non-bushing sections +// RealMatrixX D_sec_spring_true = RealMatrixX::Zero(4,6); +// +// // Convert the test and truth Eigen::Matrix objects to std::vector +// // since Catch2 has built in methods to compare vectors +// std::vector test = eigen_matrix_to_std_vector(D_sec_spring); +// std::vector truth = eigen_matrix_to_std_vector(D_sec_spring_true); +// +// // Floating point approximations are diffcult to compare since the +// // values typically aren't exactly equal due to numerical error. +// // Therefore, we use the Approx comparison instead of Equals +// CHECK_THAT( test, Catch::Approx(truth) ); +// } +} From 843f07e2a401bf8dd6ebdb42bb6b9beb0781f6f4 Mon Sep 17 00:00:00 2001 From: David John Neiferd <13425967+JohnDN90@users.noreply.github.com> Date: Mon, 24 Feb 2020 17:22:59 -0500 Subject: [PATCH 09/27] Added TUBE2 and I1 sections. Added missing MPI tests for TUBE section Added missing sensitivity tests for TUBE section. --- src/property_cards/CMakeLists.txt | 4 + ...id_1d_I1_section_element_property_card.cpp | 599 ++++++ ...olid_1d_I1_section_element_property_card.h | 151 ++ ...1d_tube2_section_element_property_card.cpp | 390 ++++ ...d_1d_tube2_section_element_property_card.h | 117 ++ tests/property/CMakeLists.txt | 300 ++- ...id_1d_I1_section_element_property_card.cpp | 1659 +++++++++++++++++ ...1d_tube2_section_element_property_card.cpp | 1510 +++++++++++++++ ..._1d_tube_section_element_property_card.cpp | 488 +++++ 9 files changed, 5146 insertions(+), 72 deletions(-) create mode 100644 src/property_cards/solid_1d_I1_section_element_property_card.cpp create mode 100644 src/property_cards/solid_1d_I1_section_element_property_card.h create mode 100644 src/property_cards/solid_1d_tube2_section_element_property_card.cpp create mode 100644 src/property_cards/solid_1d_tube2_section_element_property_card.h create mode 100644 tests/property/mast_solid_1d_I1_section_element_property_card.cpp create mode 100644 tests/property/mast_solid_1d_tube2_section_element_property_card.cpp diff --git a/src/property_cards/CMakeLists.txt b/src/property_cards/CMakeLists.txt index cfb4d3fe..e53801dc 100644 --- a/src/property_cards/CMakeLists.txt +++ b/src/property_cards/CMakeLists.txt @@ -30,10 +30,14 @@ target_sources(mast ${CMAKE_CURRENT_LIST_DIR}/solid_1d_2parameter_section_element_property_card.h ${CMAKE_CURRENT_LIST_DIR}/solid_1d_bar_section_element_property_card.cpp ${CMAKE_CURRENT_LIST_DIR}/solid_1d_bar_section_element_property_card.h + ${CMAKE_CURRENT_LIST_DIR}/solid_1d_I1_section_element_property_card.cpp + ${CMAKE_CURRENT_LIST_DIR}/solid_1d_I1_section_element_property_card.h ${CMAKE_CURRENT_LIST_DIR}/solid_1d_rod_section_element_property_card.cpp ${CMAKE_CURRENT_LIST_DIR}/solid_1d_rod_section_element_property_card.h ${CMAKE_CURRENT_LIST_DIR}/solid_1d_tube_section_element_property_card.cpp ${CMAKE_CURRENT_LIST_DIR}/solid_1d_tube_section_element_property_card.h + ${CMAKE_CURRENT_LIST_DIR}/solid_1d_tube2_section_element_property_card.cpp + ${CMAKE_CURRENT_LIST_DIR}/solid_1d_tube2_section_element_property_card.h ${CMAKE_CURRENT_LIST_DIR}/solid_2d_section_element_property_card.cpp ${CMAKE_CURRENT_LIST_DIR}/solid_2d_section_element_property_card.h ${CMAKE_CURRENT_LIST_DIR}/cross_section_property_pilkey.cpp diff --git a/src/property_cards/solid_1d_I1_section_element_property_card.cpp b/src/property_cards/solid_1d_I1_section_element_property_card.cpp new file mode 100644 index 00000000..087727ae --- /dev/null +++ b/src/property_cards/solid_1d_I1_section_element_property_card.cpp @@ -0,0 +1,599 @@ +/* + * MAST: Multidisciplinary-design Adaptation and Sensitivity Toolkit + * Copyright (C) 2013-2019 Manav Bhatia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +// MAST includes +#include "property_cards/solid_1d_I1_section_element_property_card.h" + + +// Bi-Symmetric I_Beam (I1 in Nastran) +void MAST::Solid1DI1SectionProperty::calcA(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& A){ + A = DIM4*(DIM1+DIM2)-DIM1*DIM3; +} + +void MAST::Solid1DI1SectionProperty::calcdA(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dA){ + dA = -DIM1*dDIM3+DIM4*dDIM2-dDIM1*(DIM3-DIM4)+dDIM4*(DIM1+DIM2); +} + +void MAST::Solid1DI1SectionProperty::calcIz(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& Iz){ + Iz = (DIM2*(DIM3*DIM3*DIM3))/1.2E+1-((DIM3*DIM3*DIM3-DIM4*DIM4*DIM4)*(DIM1+DIM2))/1.2E+1; +} + +void MAST::Solid1DI1SectionProperty::calcdIz(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dIz){ + dIz = ((DIM4*DIM4*DIM4)*dDIM2)/1.2E+1-(dDIM1*(DIM3*DIM3*DIM3-DIM4*DIM4*DIM4))/1.2E+1+((DIM4*DIM4)*dDIM4*(DIM1+DIM2))/4.0-(DIM1*(DIM3*DIM3)*dDIM3)/4.0; +} + +void MAST::Solid1DI1SectionProperty::calcIy(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& Iy){ + Iy = ((DIM2*DIM2*DIM2)*DIM3)/1.2E+1-((DIM3/2.0-DIM4/2.0)*pow(DIM1+DIM2,3.0))/6.0; +} + +void MAST::Solid1DI1SectionProperty::calcdIy(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dIy){ + dIy = (dDIM4*pow(DIM1+DIM2,3.0))/1.2E+1+dDIM2*(((DIM2*DIM2)*DIM3)/4.0-((DIM3/2.0-DIM4/2.0)*pow(DIM1+DIM2,2.0))/2.0)-dDIM3*(pow(DIM1+DIM2,3.0)/1.2E+1-(DIM2*DIM2*DIM2)/1.2E+1)-(dDIM1*(DIM3/2.0-DIM4/2.0)*pow(DIM1+DIM2,2.0))/2.0; +} + +void MAST::Solid1DI1SectionProperty::calcIp(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& Ip){ + Ip = (DIM2*(DIM3*DIM3*DIM3))/1.2E+1+((DIM2*DIM2*DIM2)*DIM3)/1.2E+1-((DIM3/2.0-DIM4/2.0)*pow(DIM1+DIM2,3.0))/6.0-((DIM3*DIM3*DIM3-DIM4*DIM4*DIM4)*(DIM1+DIM2))/1.2E+1; +} + +void MAST::Solid1DI1SectionProperty::calcdIp(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dIp){ + dIp = -dDIM1*(((DIM3/2.0-DIM4/2.0)*pow(DIM1+DIM2,2.0))/2.0+(DIM3*DIM3*DIM3)/1.2E+1-(DIM4*DIM4*DIM4)/1.2E+1)+dDIM4*(pow(DIM1+DIM2,3.0)/1.2E+1+((DIM4*DIM4)*(DIM1+DIM2))/4.0)+dDIM2*(((DIM2*DIM2)*DIM3)/4.0-((DIM3/2.0-DIM4/2.0)*pow(DIM1+DIM2,2.0))/2.0+(DIM4*DIM4*DIM4)/1.2E+1)-(DIM1*dDIM3*(DIM1*DIM1+(DIM2*DIM2)*3.0+(DIM3*DIM3)*3.0+DIM1*DIM2*3.0))/1.2E+1; +} + +void MAST::Solid1DI1SectionProperty::calcJ1_w(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& J1_w){ + J1_w = (DIM2*DIM2*DIM2)*DIM3; +} + +void MAST::Solid1DI1SectionProperty::calcdJ1_w(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dJ1_w){ + dJ1_w = (DIM2*DIM2*DIM2)*dDIM3+(DIM2*DIM2)*DIM3*dDIM2*3.0; +} + +void MAST::Solid1DI1SectionProperty::calcJ2_w(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& J2_w){ + J2_w = DIM2*(DIM3*DIM3*DIM3); +} + +void MAST::Solid1DI1SectionProperty::calcdJ2_w(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dJ2_w){ + dJ2_w = (DIM3*DIM3*DIM3)*dDIM2+DIM2*(DIM3*DIM3)*dDIM3*3.0; +} + +void MAST::Solid1DI1SectionProperty::calcJ1_f(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& J1_f){ + J1_f = pow(DIM3-DIM4,3.0)*(DIM1+DIM2)*(-1.0/8.0); +} + +void MAST::Solid1DI1SectionProperty::calcdJ1_f(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dJ1_f){ + dJ1_f = dDIM1*pow(DIM3-DIM4,3.0)*(-1.0/8.0)-(dDIM2*pow(DIM3-DIM4,3.0))/8.0-dDIM3*pow(DIM3-DIM4,2.0)*(DIM1+DIM2)*(3.0/8.0)+dDIM4*pow(DIM3-DIM4,2.0)*(DIM1+DIM2)*(3.0/8.0); +} + +void MAST::Solid1DI1SectionProperty::calcJ2_f(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& J2_f){ + J2_f = -(DIM3/2.0-DIM4/2.0)*pow(DIM1+DIM2,3.0); +} + +void MAST::Solid1DI1SectionProperty::calcdJ2_f(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dJ2_f){ + dJ2_f = dDIM3*pow(DIM1+DIM2,3.0)*(-1.0/2.0)+(dDIM4*pow(DIM1+DIM2,3.0))/2.0-dDIM1*(DIM3/2.0-DIM4/2.0)*pow(DIM1+DIM2,2.0)*3.0-dDIM2*(DIM3/2.0-DIM4/2.0)*pow(DIM1+DIM2,2.0)*3.0; +} + +void MAST::Solid1DI1SectionProperty::calck1_f(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& k1_f){ + k1_f = 1.0/3.0; +} + +void MAST::Solid1DI1SectionProperty::calcdk1_f(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dk1_f){ + dk1_f = 0.0; +} + +void MAST::Solid1DI1SectionProperty::calck2_f(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& k2_f){ + k2_f = 1.0/3.0; +} + +void MAST::Solid1DI1SectionProperty::calcdk2_f(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dk2_f){ + dk2_f = 0.0; +} + +void MAST::Solid1DI1SectionProperty::calck1_w(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& k1_w){ + k1_w = 1.0/3.0; +} + +void MAST::Solid1DI1SectionProperty::calcdk1_w(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dk1_w){ + dk1_w = 0.0; +} + +void MAST::Solid1DI1SectionProperty::calck2_w(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& k2_w){ + k2_w = 1.0/3.0; +} + +void MAST::Solid1DI1SectionProperty::calcdk2_w(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dk2_w){ + dk2_w = 0.0; +} + +void MAST::Solid1DI1SectionProperty::calcJc(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& Jc){ + Jc = pow(DIM3-DIM4,4.0)*(-2.1E+1/8.0E+2)-(1.0/pow(DIM3-DIM4,6.0)*pow(DIM2*DIM2+DIM3*DIM3+DIM4*DIM4-DIM3*DIM4*2.0,4.0)*((DIM2*DIM2)*7.25E+2+(DIM3*DIM3)*1.05E+2+(DIM4*DIM4)*1.05E+2+DIM2*DIM3*1.102E+3-DIM2*DIM4*1.102E+3-DIM3*DIM4*2.1E+2))/2.0E+4; +} + +void MAST::Solid1DI1SectionProperty::calcdJc(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dJc){ + dJc = -dDIM3*(pow(DIM3-DIM4,3.0)*(2.1E+1/2.0E+2)-1.0/pow(DIM3-DIM4,7.0)*pow(DIM2*DIM2+DIM3*DIM3+DIM4*DIM4-DIM3*DIM4*2.0,4.0)*((DIM2*DIM2)*7.25E+2+(DIM3*DIM3)*1.05E+2+(DIM4*DIM4)*1.05E+2+DIM2*DIM3*1.102E+3-DIM2*DIM4*1.102E+3-DIM3*DIM4*2.1E+2)*3.0E-4+(1.0/pow(DIM3-DIM4,6.0)*(DIM2*1.102E+3+DIM3*2.1E+2-DIM4*2.1E+2)*pow(DIM2*DIM2+DIM3*DIM3+DIM4*DIM4-DIM3*DIM4*2.0,4.0))/2.0E+4+(1.0/pow(DIM3-DIM4,6.0)*(DIM3*2.0-DIM4*2.0)*pow(DIM2*DIM2+DIM3*DIM3+DIM4*DIM4-DIM3*DIM4*2.0,3.0)*((DIM2*DIM2)*7.25E+2+(DIM3*DIM3)*1.05E+2+(DIM4*DIM4)*1.05E+2+DIM2*DIM3*1.102E+3-DIM2*DIM4*1.102E+3-DIM3*DIM4*2.1E+2))/5.0E+3)+dDIM4*(pow(DIM3-DIM4,3.0)*(2.1E+1/2.0E+2)-1.0/pow(DIM3-DIM4,7.0)*pow(DIM2*DIM2+DIM3*DIM3+DIM4*DIM4-DIM3*DIM4*2.0,4.0)*((DIM2*DIM2)*7.25E+2+(DIM3*DIM3)*1.05E+2+(DIM4*DIM4)*1.05E+2+DIM2*DIM3*1.102E+3-DIM2*DIM4*1.102E+3-DIM3*DIM4*2.1E+2)*3.0E-4+(1.0/pow(DIM3-DIM4,6.0)*(DIM2*1.102E+3+DIM3*2.1E+2-DIM4*2.1E+2)*pow(DIM2*DIM2+DIM3*DIM3+DIM4*DIM4-DIM3*DIM4*2.0,4.0))/2.0E+4+(1.0/pow(DIM3-DIM4,6.0)*(DIM3*2.0-DIM4*2.0)*pow(DIM2*DIM2+DIM3*DIM3+DIM4*DIM4-DIM3*DIM4*2.0,3.0)*((DIM2*DIM2)*7.25E+2+(DIM3*DIM3)*1.05E+2+(DIM4*DIM4)*1.05E+2+DIM2*DIM3*1.102E+3-DIM2*DIM4*1.102E+3-DIM3*DIM4*2.1E+2))/5.0E+3)-(dDIM2*1.0/pow(DIM3-DIM4,6.0)*pow(DIM2*DIM2+DIM3*DIM3+DIM4*DIM4-DIM3*DIM4*2.0,3.0)*(DIM2*(DIM3*DIM3)*1.145E+3+(DIM2*DIM2)*DIM3*4.959E+3+DIM2*(DIM4*DIM4)*1.145E+3-(DIM2*DIM2)*DIM4*4.959E+3+DIM3*(DIM4*DIM4)*1.653E+3-(DIM3*DIM3)*DIM4*1.653E+3+(DIM2*DIM2*DIM2)*3.625E+3+(DIM3*DIM3*DIM3)*5.51E+2-(DIM4*DIM4*DIM4)*5.51E+2-DIM2*DIM3*DIM4*2.29E+3))/1.0E+4; +} + + +// TODO: Improve accuracy of calculation of torsion constant and corresponding derivative +void MAST::Solid1DI1SectionProperty::calcJ(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& J) +{ + Real t_f = 0.5*(DIM4-DIM3); + Real w_f = DIM2+DIM1; + Real h_w = DIM3; + Real t_w = DIM2; + + Real k_f, k_w, c, J_w, J_f; + Real wf = t_w/t_f; + + // Sum of rectangles with correction of El Darwish and Johnson + if ( (wf>0.5) and (wf<1.0) ) + { + k_f = 0.3333333333333333; + k_w = 0.3333333333333333; + calcJc(DIM1, DIM2, DIM3, DIM4, c); + } + + // Sum of rectangles method, with rectangles corrected for aspect ratios + else + { + if (w_f>t_f){ + calck1_f(DIM1, DIM2, DIM3, DIM4, k_f); + } + else{ + calck2_f(DIM1, DIM2, DIM3, DIM4, k_f); + } + + if (h_w>t_w){ + calck1_w(DIM1, DIM2, DIM3, DIM4, k_w); + } + else{ + calck2_w(DIM1, DIM2, DIM3, DIM4, k_w); + } + c = 0.0; + } + + + if (w_f>t_f){ + calcJ1_f(DIM1, DIM2, DIM3, DIM4, J_f); + } + else{ + calcJ2_f(DIM1, DIM2, DIM3, DIM4, J_f); + } + + if (h_w>t_w){ + calcJ1_w(DIM1, DIM2, DIM3, DIM4, J_w); + } + else{ + calcJ2_w(DIM1, DIM2, DIM3, DIM4, J_w); + } + + J = 2.0*(k_f*J_f) + (k_w*J_w) + c; +} + + + +void MAST::Solid1DI1SectionProperty::calcdJ(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dJ) +{ + Real t_f = 0.5*(DIM4-DIM3); + Real w_f = DIM2+DIM1; + Real h_w = DIM3; + Real t_w = DIM2; + + Real k_f, k_w, c, dk_f, dk_w, dc, J_w, J_f, dJ_w, dJ_f; + Real wf = t_w/t_f; + + // Sum of rectangles with correction of El Darwish and Johnson + if ( (wf>0.5) and (wf<1.0) ) + { + k_f = 0.3333333333333333; + k_w = 0.3333333333333333; + dk_f = 0.0; + dk_w = 0.0; + calcdJc(DIM1, DIM2, DIM3, DIM4, dDIM1, dDIM2, dDIM3, dDIM4, dc); + } + + // Sum of rectangles method, with rectangles corrected for aspect ratios + else + { + if (w_f>t_f){ + calck1_f(DIM1, DIM2, DIM3, DIM4, k_f); + calcdk1_f(DIM1, DIM2, DIM3, DIM4, dDIM1, dDIM2, dDIM3, dDIM4, dk_f); + } + else{ + calck2_f(DIM1, DIM2, DIM3, DIM4, k_f); + calcdk2_f(DIM1, DIM2, DIM3, DIM4, dDIM1, dDIM2, dDIM3, dDIM4, dk_f); + } + + if (h_w>t_w){ + calck1_w(DIM1, DIM2, DIM3, DIM4, k_w); + calcdk1_w(DIM1, DIM2, DIM3, DIM4, dDIM1, dDIM2, dDIM3, dDIM4, dk_w); + } + else{ + calck2_w(DIM1, DIM2, DIM3, DIM4, k_w); + calcdk2_w(DIM1, DIM2, DIM3, DIM4, dDIM1, dDIM2, dDIM3, dDIM4, dk_w); + } + dc = 0.0; + } + + + if (w_f>t_f){ + calcJ1_f(DIM1, DIM2, DIM3, DIM4, J_f); + calcdJ1_f(DIM1, DIM2, DIM3, DIM4, dDIM1, dDIM2, dDIM3, dDIM4, dJ_f); + } + else{ + calcJ2_f(DIM1, DIM2, DIM3, DIM4, J_f); + calcdJ2_f(DIM1, DIM2, DIM3, DIM4, dDIM1, dDIM2, dDIM3, dDIM4, dJ_f); + } + + if (h_w>t_w){ + calcJ1_w(DIM1, DIM2, DIM3, DIM4, J_w); + calcdJ1_w(DIM1, DIM2, DIM3, DIM4, dDIM1, dDIM2, dDIM3, dDIM4, dJ_w); + } + else{ + calcJ2_w(DIM1, DIM2, DIM3, DIM4, J_w); + calcdJ2_w(DIM1, DIM2, DIM3, DIM4, dDIM1, dDIM2, dDIM3, dDIM4, dJ_w); + } + + dJ = 2.0*(dk_f*J_f + k_f*dJ_f) + (dk_w*J_w + k_w*dJ_w) + dc; +} + + +const std::vector +MAST::Solid1DI1SectionElementPropertyCard::get_geom_points(const libMesh::Point& p, const Real t, const uint n) const +{ + const MAST::FieldFunction + &DIM1 = this->get >("DIM1"), + &DIM2 = this->get >("DIM2"), + &DIM3 = this->get >("DIM3"), + &DIM4 = this->get >("DIM4"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + // Check that dimensions are physically correct + Real DIM1v, DIM2v, DIM3v, DIM4v; + DIM1(p, t, DIM1v); DIM2(p, t, DIM2v); DIM3(p, t, DIM3v); DIM4(p, t, DIM4v); + + Real offset_y, offset_z; + hy_off(p, t, offset_y); hz_off(p, t, offset_z); + + libMesh::Point shift(0.5*(DIM1v+DIM2v), 0.5*DIM4v); + libMesh::Point offset(offset_z, offset_y); + + Real th = 0.5*(DIM4v - DIM3v); + std::vector points = { + libMesh::Point(0., 0.) - shift + offset, + libMesh::Point(DIM1v+DIM2v, 0.) - shift + offset, + libMesh::Point(DIM1v+DIM2v, th) - shift + offset, + libMesh::Point(0.5*DIM1v+DIM2v, th) - shift + offset, + libMesh::Point(0.5*DIM1v+DIM2v, th+DIM3v) - shift + offset, + libMesh::Point(DIM1v+DIM2v, th+DIM3v) - shift + offset, + libMesh::Point(DIM1v+DIM2v, DIM4v) - shift + offset, + libMesh::Point(0., DIM4v) - shift + offset, + libMesh::Point(0., th+DIM3v) - shift + offset, + libMesh::Point(0.5*DIM1v, th+DIM3v) - shift + offset, + libMesh::Point(0.5*DIM1v, th) - shift + offset, + libMesh::Point(0., th) - shift + offset + }; + + return points; +} + + +const std::vector +MAST::Solid1DI1SectionElementPropertyCard::get_geom_points_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, const uint n) const +{ + const MAST::FieldFunction + &DIM1 = this->get >("DIM1"), + &DIM2 = this->get >("DIM2"), + &DIM3 = this->get >("DIM3"), + &DIM4 = this->get >("DIM4"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + // Check that dimensions are physically correct + Real DIM1v, DIM2v, DIM3v, DIM4v; + DIM1(p, t, DIM1v); DIM2(p, t, DIM2v); DIM3(p, t, DIM3v); DIM4(p, t, DIM4v); + + Real dDIM1v, dDIM2v, dDIM3v, dDIM4v; + DIM1.derivative(f, p, t, dDIM1v); DIM2.derivative(f, p, t, dDIM2v); + DIM3.derivative(f, p, t, dDIM3v); DIM4.derivative(f, p, t, dDIM4v); + + Real offset_y, offset_z, doffset_y, doffset_z; + hy_off(p, t, offset_y); hy_off.derivative(f, p, t, doffset_y); + hz_off(p, t, offset_z); hz_off.derivative(f, p, t, doffset_z); + + libMesh::Point dshift(0.5*(dDIM1v+dDIM2v), 0.5*dDIM4v); + libMesh::Point doffset(doffset_z, doffset_y); + + Real dt = 0.5*(dDIM4v - dDIM3v); + std::vector points = { + libMesh::Point(0., 0.) - dshift + doffset, + libMesh::Point(dDIM1v+dDIM2v, 0.) - dshift + doffset, + libMesh::Point(dDIM1v+dDIM2v, dt) - dshift + doffset, + libMesh::Point(0.5*dDIM1v+dDIM2v, dt) - dshift + doffset, + libMesh::Point(0.5*dDIM1v+dDIM2v, dt+dDIM3v) - dshift + doffset, + libMesh::Point(dDIM1v+dDIM2v, dt+dDIM3v) - dshift + doffset, + libMesh::Point(dDIM1v+dDIM2v, dDIM4v) - dshift + doffset, + libMesh::Point(0., dDIM4v) - dshift + doffset, + libMesh::Point(0., dt+dDIM3v) - dshift + doffset, + libMesh::Point(0.5*dDIM1v, dt+dDIM3v) - dshift + doffset, + libMesh::Point(0.5*dDIM1v, dt) - dshift + doffset, + libMesh::Point(0., dt) - dshift + doffset + }; + + return points; +} + + +const libMesh::Point +MAST::Solid1DI1SectionElementPropertyCard::get_shear_center(const libMesh::Point& p, const Real t) const +{ + const MAST::FieldFunction + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real offset_y, offset_z; + hy_off(p, t, offset_y); + hz_off(p, t, offset_z); + + /*! + * I1 section is bisymmetric and thus the shear center is located at the + * centroid. In this case, the origin lies on the centroid. + */ + libMesh::Point offset(offset_z, offset_y); + return libMesh::Point(0., 0., 0.) + offset; +} + + +const libMesh::Point +MAST::Solid1DI1SectionElementPropertyCard::get_shear_center_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t) const +{ + const MAST::FieldFunction + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real doffset_y, doffset_z; + hy_off.derivative(f, p, t, doffset_y); + hz_off.derivative(f, p, t, doffset_z); + + /*! + * I1 section is bisymmetric and thus the shear center is located at the + * centroid. In this case, the origin lies on the centroid. + */ + libMesh::Point doffset(doffset_z, doffset_y); + return libMesh::Point(0., 0., 0.) + doffset; +} + + +const libMesh::Point +MAST::Solid1DI1SectionElementPropertyCard::get_centroid(const libMesh::Point& p, const Real t) const +{ + const MAST::FieldFunction + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real offset_y, offset_z; + hy_off(p, t, offset_y); + hz_off(p, t, offset_z); + + /*! + * In this case, the origin lies on the centroid. + */ + libMesh::Point offset(offset_z, offset_y); + return libMesh::Point(0., 0., 0.) + offset; +} + + + +const libMesh::Point +MAST::Solid1DI1SectionElementPropertyCard::get_centroid_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t) const +{ + const MAST::FieldFunction + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real doffset_y, doffset_z; + hy_off.derivative(f, p, t, doffset_y); + hz_off.derivative(f, p, t, doffset_z); + + /*! + * In this case, the origin lies on the centroid. + */ + libMesh::Point doffset(doffset_z, doffset_y); + return libMesh::Point(0., 0., 0.) + doffset; +} + +const std::vector +MAST::Solid1DI1SectionElementPropertyCard::get_stress_points(const libMesh::Point& p, const Real t, const libMesh::Point ps) const +{ + // Ordered C, D, E, F as defined in MSC Nastran manual (See PBARL or PBEAML) + const MAST::FieldFunction + &DIM1 = this->get >("DIM1"), + &DIM2 = this->get >("DIM2"), + &DIM3 = this->get >("DIM3"), + &DIM4 = this->get >("DIM4"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real DIM1v, DIM2v, DIM3v, DIM4v; + DIM1(p, t, DIM1v); DIM2(p, t, DIM2v); DIM3(p, t, DIM3v); DIM4(p, t, DIM4v); + + Real offset_y, offset_z; + hy_off(p, t, offset_y); hz_off(p, t, offset_z); + + libMesh::Point offset(offset_z, offset_y); + + // Points + libMesh::Point shift(0., 0., 0.); + std::vector points = { + libMesh::Point(0.5*(DIM1v+DIM2v), 0.5*DIM4v) - shift - ps + offset, + libMesh::Point(0.5*(DIM1v+DIM2v), -0.5*DIM4v) - shift - ps + offset, + libMesh::Point(-0.5*(DIM1v+DIM2v), -0.5*DIM4v) - shift - ps + offset, + libMesh::Point(-0.5*(DIM1v+DIM2v), 0.5*DIM4v) - shift - ps + offset + }; + + return points; +}; + +const std::vector +MAST::Solid1DI1SectionElementPropertyCard::get_stress_points_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, const libMesh::Point dps) const +{ + const MAST::FieldFunction + &DIM1 = this->get >("DIM1"), + &DIM2 = this->get >("DIM2"), + &DIM3 = this->get >("DIM3"), + &DIM4 = this->get >("DIM4"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + // Check that dimensions are physically correct + Real DIM1v, DIM2v, DIM3v, DIM4v; + DIM1(p, t, DIM1v); DIM2(p, t, DIM2v); DIM3(p, t, DIM3v); DIM4(p, t, DIM4v); + + Real dDIM1v, dDIM2v, dDIM3v, dDIM4v; + DIM1.derivative(f, p, t, dDIM1v); DIM2.derivative(f, p, t, dDIM2v); + DIM3.derivative(f, p, t, dDIM3v); DIM4.derivative(f, p, t, dDIM4v); + + Real offset_y, offset_z, doffset_y, doffset_z; + hy_off(p, t, offset_y); hy_off.derivative(f, p, t, doffset_y); + hz_off(p, t, offset_z); hz_off.derivative(f, p, t, doffset_z); + + libMesh::Point doffset(doffset_z, doffset_y); + + // Points + std::vector points = { + libMesh::Point(0.5*(dDIM1v+dDIM2v), 0.5*dDIM4v) - dps + doffset, + libMesh::Point(0.5*(dDIM1v+dDIM2v), -0.5*dDIM4v) - dps + doffset, + libMesh::Point(-0.5*(dDIM1v+dDIM2v), -0.5*dDIM4v) - dps + doffset, + libMesh::Point(-0.5*(dDIM1v+dDIM2v), 0.5*dDIM4v) - dps + doffset + }; +} + +void MAST::Solid1DI1SectionElementPropertyCard::init(const libMesh::LibMeshInit& init) { + + libmesh_assert(!_initialized); + + MAST::FieldFunction + &DIM1 = this->get >("DIM1"), + &DIM2 = this->get >("DIM2"), + &DIM3 = this->get >("DIM3"), + &DIM4 = this->get >("DIM4"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + // Check that dimensions are physically correct + Real DIM1v, DIM2v, DIM3v, DIM4v, DIM5v; + DIM1(DIM1v); DIM2(DIM2v); DIM3(DIM3v); DIM4(DIM4v); + if (DIM1v<=0){ + libmesh_error_msg("DIM1<=0"); + } + else if (DIM2v<=0){ + libmesh_error_msg("DIM2<=0"); + } + else if (DIM3v<=0){ + libmesh_error_msg("DIM3<=0"); + } + else if (DIM4v<=0){ + libmesh_error_msg("DIM4<=0"); + } + else if (DIM4v<=DIM3v){ + libmesh_error_msg("DIM4<=DIM3"); + } + + // Create a cross section model of this section + cross_section.reset(new MAST::CrossSection(init, 3500, *this, libMesh::TRI6)); + +// _A.reset(new MAST::Solid1D4ParameterSectionProperty::Area(MAST::Solid1DI1SectionProperty::calcA, +// MAST::Solid1DI1SectionProperty::calcdA, +// DIM1, DIM2, DIM3, +// DIM4)); +// +// _Ay.reset(new MAST::Solid1D4ParameterSectionProperty::AreaYMoment( +// MAST::Solid1DI1SectionProperty::calcA, +// MAST::Solid1DI1SectionProperty::calcdA, +// DIM1, DIM2, +// DIM3, DIM4, +// hz_off)); +// +// _Az.reset(new MAST::Solid1D4ParameterSectionProperty::AreaZMoment( +// MAST::Solid1DI1SectionProperty::calcA, +// MAST::Solid1DI1SectionProperty::calcdA, +// DIM1, DIM2, +// DIM3, DIM4, +// hy_off)); +// +// _J.reset(new MAST::Solid1D4ParameterSectionProperty::TorsionalConstant( +// MAST::Solid1DI1SectionProperty::calcJ, +// MAST::Solid1DI1SectionProperty::calcdJ, +// DIM1, DIM2, +// DIM3, DIM4)); +// +// _Ip.reset(new MAST::Solid1D4ParameterSectionProperty::PolarInertia( +// MAST::Solid1DI1SectionProperty::calcIp, +// MAST::Solid1DI1SectionProperty::calcdIp, +// MAST::Solid1DI1SectionProperty::calcA, +// MAST::Solid1DI1SectionProperty::calcdA, +// DIM1, DIM2, +// DIM3, DIM4, +// hy_off, +// hz_off)); +// +// _AI.reset(new MAST::Solid1D4ParameterSectionProperty::AreaInertiaMatrix( +// MAST::Solid1DI1SectionProperty::calcIz, +// MAST::Solid1DI1SectionProperty::calcdIz, +// MAST::Solid1DI1SectionProperty::calcIy, +// MAST::Solid1DI1SectionProperty::calcdIy, +// MAST::Solid1DI1SectionProperty::calcA, +// MAST::Solid1DI1SectionProperty::calcdA, +// DIM1, DIM2, +// DIM3, DIM4, +// hy_off, +// hz_off)); + + _A.reset(new MAST::Solid1DnParameterSectionProperty::Area(*cross_section)); + + _Ay.reset(new MAST::Solid1DnParameterSectionProperty::AreaYMoment(*cross_section)); + + _Az.reset(new MAST::Solid1DnParameterSectionProperty::AreaZMoment(*cross_section)); + + _AI.reset(new MAST::Solid1DnParameterSectionProperty::AreaInertiaMatrix(*cross_section)); + + _Ip.reset(new MAST::Solid1DnParameterSectionProperty::PolarInertia(*cross_section)); + + _J.reset(new MAST::Solid1DnParameterSectionProperty::TorsionalConstant(*cross_section)); + + _Kappa.reset(new MAST::Solid1DnParameterSectionProperty::ShearCoefficientMatrix(*cross_section)); + + _Gamma.reset(new MAST::Solid1DnParameterSectionProperty::WarpingConstant(*cross_section)); + + _initialized = true; +} + + +void MAST::Solid1DI1SectionElementPropertyCard::create_cross_section( + const libMesh::LibMeshInit& init, const uint n_target_elems, + const libMesh::ElemType element_type) +{ + cross_section.reset(new MAST::CrossSection(init, n_target_elems, + *this, element_type)); +} + + +void MAST::Solid1DI1SectionElementPropertyCard::calculate_properties_pilkey() +{ + cross_section->calculate_geometric_properties(); + cross_section->calculate_warping_properties(); +} diff --git a/src/property_cards/solid_1d_I1_section_element_property_card.h b/src/property_cards/solid_1d_I1_section_element_property_card.h new file mode 100644 index 00000000..a70406d7 --- /dev/null +++ b/src/property_cards/solid_1d_I1_section_element_property_card.h @@ -0,0 +1,151 @@ +/* + * MAST: Multidisciplinary-design Adaptation and Sensitivity Toolkit + * Copyright (C) 2013-2019 Manav Bhatia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * +// * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __mast__solid_1d_I1_section_element_property_card__ +#define __mast__solid_1d_I1_section_element_property_card__ + + +// MAST includes +// #include "property_cards/solid_1d_4parameter_section_element_property_card.h" +#include "property_cards/solid_1d_nparameter_section_element_property_card.h" +#include "property_cards/cross_section_property_pilkey.h" + + +// Bi-symmetric I-beam (I1 in MSC Nastran) +namespace MAST{ + namespace Solid1DI1SectionProperty{ + void calcA(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& A); + + void calcdA(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dA); + + void calcIz(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& Iz); + + void calcdIz(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dIz); + + void calcIy(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& Iy); + + void calcdIy(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dIy); + + void calcIp(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& Ip); + + void calcdIp(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dIp); + + void calcJ1_w(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& J1_w); + + void calcdJ1_w(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dJ1_w); + + void calcJ2_w(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& J2_w); + + void calcdJ2_w(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dJ2_w); + + void calcJ1_f(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& J1_f); + + void calcdJ1_f(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dJ1_f); + + void calcJ2_f(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& J2_f); + + void calcdJ2_f(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dJ2_f); + + void calck1_f(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& k1_f); + + void calcdk1_f(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dk1_f); + + void calck2_f(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& k2_f); + + void calcdk2_f(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dk2_f); + + void calck1_w(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& k1_w); + + void calcdk1_w(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dk1_w); + + void calck2_w(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& k2_w); + + void calcdk2_w(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dk2_w); + + void calcJc(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& Jc); + + void calcdJc(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dJc); + + void calcJ(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& J); + + void calcdJ(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dJ); + + } +} + + +namespace MAST { + + class Solid1DI1SectionElementPropertyCard : public MAST::Solid1DnParameterSectionElementPropertyCard + { + public: + Solid1DI1SectionElementPropertyCard(): + MAST::Solid1DnParameterSectionElementPropertyCard() {} + + /*! + * virtual destructor + */ + virtual ~Solid1DI1SectionElementPropertyCard() { } + + virtual void init(const libMesh::LibMeshInit& init); + + virtual void create_cross_section( + const libMesh::LibMeshInit& init, + const uint n_target_elems=3500, + const libMesh::ElemType element_type=libMesh::TRI6); + + virtual void calculate_properties_pilkey(); + + virtual const std::vector get_geom_points(const libMesh::Point& p, const Real t, const uint n=201) const override; + + virtual const std::vector get_geom_points_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, const uint n=201) const override; + + virtual const libMesh::Point get_shear_center(const libMesh::Point& p, const Real t) const override; + + virtual const libMesh::Point get_shear_center_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t) const; + + virtual const libMesh::Point get_centroid(const libMesh::Point& p, const Real t) const override; + + virtual const libMesh::Point get_centroid_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t) const override; + + virtual const std::vector get_stress_points(const libMesh::Point& p, const Real t, const libMesh::Point ps) const override; + + virtual const std::vector get_stress_points_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, const libMesh::Point dps) const override; + + std::unique_ptr cross_section; + + const bool is_bisymmetric() const + { + return true; + } + + const bool is_symmetric_z() const + { + return true; + } + + const bool is_symmetric_y() const + { + return true; + } + }; +} + + +#endif // __mast__solid_1d_I1_section_element_property_card__ diff --git a/src/property_cards/solid_1d_tube2_section_element_property_card.cpp b/src/property_cards/solid_1d_tube2_section_element_property_card.cpp new file mode 100644 index 00000000..c4accdb1 --- /dev/null +++ b/src/property_cards/solid_1d_tube2_section_element_property_card.cpp @@ -0,0 +1,390 @@ +/* + * MAST: Multidisciplinary-design Adaptation and Sensitivity Toolkit + * Copyright (C) 2013-2019 Manav Bhatia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +// MAST includes +#include "property_cards/solid_1d_tube2_section_element_property_card.h" + + +#define PI 3.1415926535897932 + + +// Annulus (Alternative Parameterization) (TUBE2 in Nastran) +void MAST::Solid1DTube2SectionProperty::calcA(Real& DIM1, Real& DIM2, Real& A){ + A = 3.141592653589793*(DIM1*DIM1-pow(DIM1-DIM2,2.0)); +} + +void MAST::Solid1DTube2SectionProperty::calcdA(Real& DIM1, Real& DIM2, Real& dDIM1, Real& dDIM2, Real& dA){ + dA = DIM2*dDIM1*3.141592653589793*2.0+dDIM2*3.141592653589793*(DIM1*2.0-DIM2*2.0); +} + +void MAST::Solid1DTube2SectionProperty::calcIz(Real& DIM1, Real& DIM2, Real& Iz){ + Iz = (3.141592653589793*(DIM1*DIM1*DIM1*DIM1-pow(DIM1-DIM2,4.0)))/4.0; +} + +void MAST::Solid1DTube2SectionProperty::calcdIz(Real& DIM1, Real& DIM2, Real& dDIM1, Real& dDIM2, Real& dIz){ + dIz = (dDIM1*3.141592653589793*((DIM1*DIM1*DIM1)*4.0-pow(DIM1-DIM2,3.0)*4.0))/4.0+dDIM2*3.141592653589793*pow(DIM1-DIM2,3.0); +} + +void MAST::Solid1DTube2SectionProperty::calcIy(Real& DIM1, Real& DIM2, Real& Iy){ + Iy = (3.141592653589793*(DIM1*DIM1*DIM1*DIM1-pow(DIM1-DIM2,4.0)))/4.0; +} + +void MAST::Solid1DTube2SectionProperty::calcdIy(Real& DIM1, Real& DIM2, Real& dDIM1, Real& dDIM2, Real& dIy){ + dIy = (dDIM1*3.141592653589793*((DIM1*DIM1*DIM1)*4.0-pow(DIM1-DIM2,3.0)*4.0))/4.0+dDIM2*3.141592653589793*pow(DIM1-DIM2,3.0); +} + +void MAST::Solid1DTube2SectionProperty::calcIp(Real& DIM1, Real& DIM2, Real& Ip){ + Ip = (3.141592653589793*(DIM1*DIM1*DIM1*DIM1-pow(DIM1-DIM2,4.0)))/2.0; +} + +void MAST::Solid1DTube2SectionProperty::calcdIp(Real& DIM1, Real& DIM2, Real& dDIM1, Real& dDIM2, Real& dIp){ + dIp = (dDIM1*3.141592653589793*((DIM1*DIM1*DIM1)*4.0-pow(DIM1-DIM2,3.0)*4.0))/2.0+dDIM2*3.141592653589793*pow(DIM1-DIM2,3.0)*2.0; +} + +void MAST::Solid1DTube2SectionProperty::calcJ(Real& DIM1, Real& DIM2, Real& J){ + J = (3.141592653589793*(DIM1*DIM1*DIM1*DIM1-pow(DIM1-DIM2,4.0)))/2.0; +} + +void MAST::Solid1DTube2SectionProperty::calcdJ(Real& DIM1, Real& DIM2, Real& dDIM1, Real& dDIM2, Real& dJ){ + dJ = (dDIM1*3.141592653589793*((DIM1*DIM1*DIM1)*4.0-pow(DIM1-DIM2,3.0)*4.0))/2.0+dDIM2*3.141592653589793*pow(DIM1-DIM2,3.0)*2.0; +} + + +const std::vector +MAST::Solid1DTube2SectionElementPropertyCard::get_geom_points(const libMesh::Point& p, const Real t, const uint n) const +{ + const MAST::FieldFunction + &DIM1 = this->get >("DIM1"), + &DIM2 = this->get >("DIM2"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real DIM1v, DIM2v, offset_y, offset_z; + DIM1(p, t, DIM1v); DIM2(p, t, DIM2v); + hy_off(p, t, offset_y); hz_off(p, t, offset_z); + + libMesh::Point offset(offset_z, offset_y); + std::vector geom_points(n); + for (uint i=0; i +MAST::Solid1DTube2SectionElementPropertyCard::get_geom_points_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, const uint n) const +{ + const MAST::FieldFunction + &DIM1 = this->get >("DIM1"), + &DIM2 = this->get >("DIM2"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real DIM1v, DIM2v, offset_y, offset_z; + Real dDIM1v, dDIM2v, doffset_y, doffset_z; + DIM1(p, t, DIM1v); DIM1.derivative(f, p, t, dDIM1v); + DIM2(p, t, DIM2v); DIM2.derivative(f, p, t, dDIM2v); + hy_off(p, t, offset_y); hy_off.derivative(f, p, t, doffset_y); + hz_off(p, t, offset_z); hz_off.derivative(f, p, t, doffset_z); + + libMesh::Point doffset(doffset_z, doffset_y); + std::vector dgeom_points(n); + for (uint i=0; i> +MAST::Solid1DTube2SectionElementPropertyCard::get_holes_points(const libMesh::Point& p, const Real t, const uint n) const +{ + const MAST::FieldFunction + &DIM1 = this->get >("DIM1"), + &DIM2 = this->get >("DIM2"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real DIM1v, DIM2v, offset_y, offset_z; + DIM1(p, t, DIM1v); DIM2(p, t, DIM2v); + hy_off(p, t, offset_y); hz_off(p, t, offset_z); + + libMesh::Point offset(offset_z, offset_y); + std::vector hole_points(n); + for (uint i=0; i> +MAST::Solid1DTube2SectionElementPropertyCard::get_holes_points_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, const uint n) const +{ + const MAST::FieldFunction + &DIM1 = this->get >("DIM1"), + &DIM2 = this->get >("DIM2"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real DIM1v, DIM2v, offset_y, offset_z; + Real dDIM1v, dDIM2v, doffset_y, doffset_z; + DIM1(p, t, DIM1v); DIM1.derivative(f, p, t, dDIM1v); + DIM2(p, t, DIM2v); DIM2.derivative(f, p, t, dDIM2v); + hy_off(p, t, offset_y); hy_off.derivative(f, p, t, doffset_y); + hz_off(p, t, offset_z); hz_off.derivative(f, p, t, doffset_z); + + libMesh::Point doffset(doffset_z, doffset_y); + std::vector dholes_points(n); + for (uint i=0; i + &DIM1 = this->get >("DIM1"), + &DIM2 = this->get >("DIM2"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real DIM1v, DIM2v, offset_y, offset_z; + DIM1(p, t, DIM1v); DIM2(p, t, DIM2v); + hy_off(p, t, offset_y); hz_off(p, t, offset_z); + + return libMesh::Point(offset_z, offset_y, 0.); +} + + +const libMesh::Point +MAST::Solid1DTube2SectionElementPropertyCard::get_shear_center_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t) const +{ + const MAST::FieldFunction + &DIM1 = this->get >("DIM1"), + &DIM2 = this->get >("DIM2"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real DIM1v, DIM2v, offset_y, offset_z; + Real dDIM1v, dDIM2v, doffset_y, doffset_z; + DIM1(p, t, DIM1v); DIM1.derivative(f, p, t, dDIM1v); + DIM2(p, t, DIM2v); DIM2.derivative(f, p, t, dDIM2v); + hy_off(p, t, offset_y); hy_off.derivative(f, p, t, doffset_y); + hz_off(p, t, offset_z); hz_off.derivative(f, p, t, doffset_z); + + return libMesh::Point(doffset_z, doffset_y, 0.); +} + + +const libMesh::Point +MAST::Solid1DTube2SectionElementPropertyCard::get_centroid(const libMesh::Point& p, const Real t) const +{ + const MAST::FieldFunction + &DIM1 = this->get >("DIM1"), + &DIM2 = this->get >("DIM2"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real DIM1v, DIM2v, offset_y, offset_z; + DIM1(p, t, DIM1v); DIM2(p, t, DIM2v); + hy_off(p, t, offset_y); hz_off(p, t, offset_z); + + return libMesh::Point(offset_z, offset_y, 0.); +} + + +const libMesh::Point +MAST::Solid1DTube2SectionElementPropertyCard::get_centroid_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t) const +{ + const MAST::FieldFunction + &DIM1 = this->get >("DIM1"), + &DIM2 = this->get >("DIM2"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real DIM1v, DIM2v, offset_y, offset_z; + Real dDIM1v, dDIM2v, doffset_y, doffset_z; + DIM1(p, t, DIM1v); DIM1.derivative(f, p, t, dDIM1v); + DIM2(p, t, DIM2v); DIM2.derivative(f, p, t, dDIM2v); + hy_off(p, t, offset_y); hy_off.derivative(f, p, t, doffset_y); + hz_off(p, t, offset_z); hz_off.derivative(f, p, t, doffset_z); + + return libMesh::Point(doffset_z, doffset_y, 0.); +} + + +const std::vector +MAST::Solid1DTube2SectionElementPropertyCard::get_stress_points(const libMesh::Point& p, const Real t, const libMesh::Point ps) const +{ + const MAST::FieldFunction + &DIM1 = this->get >("DIM1"), + &DIM2 = this->get >("DIM2"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real DIM1v, DIM2v, offset_y, offset_z; + DIM1(p, t, DIM1v); DIM2(p, t, DIM2v); + hy_off(p, t, offset_y); hz_off(p, t, offset_z); + + libMesh::Point offset(offset_z, offset_y); + + return {libMesh::Point(0., DIM1v, 0.) + offset - ps, + libMesh::Point(DIM1v, 0., 0.) + offset - ps, + libMesh::Point(0. -DIM1v, 0.) + offset - ps, + libMesh::Point(-DIM1v, 0., 0.) + offset - ps + }; +} + + +const std::vector +MAST::Solid1DTube2SectionElementPropertyCard::get_stress_points_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, const libMesh::Point dps) const +{ + const MAST::FieldFunction + &DIM1 = this->get >("DIM1"), + &DIM2 = this->get >("DIM2"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real DIM1v, DIM2v, offset_y, offset_z; + Real dDIM1v, dDIM2v, doffset_y, doffset_z; + DIM1(p, t, DIM1v); DIM1.derivative(f, p, t, dDIM1v); + DIM2(p, t, DIM2v); DIM2.derivative(f, p, t, dDIM2v); + hy_off(p, t, offset_y); hy_off.derivative(f, p, t, doffset_y); + hz_off(p, t, offset_z); hz_off.derivative(f, p, t, doffset_z); + + libMesh::Point offset(offset_z, offset_y); + + libMesh::Point doffset(doffset_z, doffset_y); + + return {libMesh::Point(0., dDIM1v, 0.) + doffset - dps, + libMesh::Point(dDIM1v, 0., 0.) + doffset - dps, + libMesh::Point(0. -dDIM1v, 0.) + doffset - dps, + libMesh::Point(-dDIM1v, 0., 0.) + doffset - dps + }; +} + + +void MAST::Solid1DTube2SectionElementPropertyCard::init(const libMesh::LibMeshInit& init) { + + libmesh_assert(!_initialized); + + MAST::FieldFunction + &DIM1 = this->get >("DIM1"), + &DIM2 = this->get >("DIM2"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + // Check that dimensions are physically correct + Real DIM1v, DIM2v; + DIM1(DIM1v); DIM2(DIM2v); + if (DIM1v<=0){ + libmesh_error_msg("DIM1<=0"); + } + else if (DIM2v<=0){ + libmesh_error_msg("DIM2<=0"); + } + else if (DIM2v>=DIM1v){ + libmesh_error_msg("DIM2>=DIM1"); + } + + // Create a cross section model of this section + cross_section.reset(new MAST::CrossSection(init, 3500, *this, libMesh::TRI6)); + + _A.reset(new MAST::Solid1D2ParameterSectionProperty::Area(MAST::Solid1DTube2SectionProperty::calcA, + MAST::Solid1DTube2SectionProperty::calcdA, + DIM1, DIM2)); + + _Ay.reset(new MAST::Solid1D2ParameterSectionProperty::AreaYMoment( + MAST::Solid1DTube2SectionProperty::calcA, + MAST::Solid1DTube2SectionProperty::calcdA, + DIM1, DIM2, + hz_off)); + + _Az.reset(new MAST::Solid1D2ParameterSectionProperty::AreaZMoment( + MAST::Solid1DTube2SectionProperty::calcA, + MAST::Solid1DTube2SectionProperty::calcdA, + DIM1, DIM2, + hy_off)); + + _Ip.reset(new MAST::Solid1D2ParameterSectionProperty::PolarInertia( + MAST::Solid1DTube2SectionProperty::calcIp, + MAST::Solid1DTube2SectionProperty::calcdIp, + MAST::Solid1DTube2SectionProperty::calcA, + MAST::Solid1DTube2SectionProperty::calcdA, + DIM1, DIM2, + hy_off, + hz_off)); + + _AI.reset(new MAST::Solid1D2ParameterSectionProperty::AreaInertiaMatrix( + MAST::Solid1DTube2SectionProperty::calcIz, + MAST::Solid1DTube2SectionProperty::calcdIz, + MAST::Solid1DTube2SectionProperty::calcIy, + MAST::Solid1DTube2SectionProperty::calcdIy, + MAST::Solid1DTube2SectionProperty::calcA, + MAST::Solid1DTube2SectionProperty::calcdA, + DIM1, DIM2, + hy_off, + hz_off)); + + _J.reset(new MAST::Solid1D2ParameterSectionProperty::TorsionalConstant( + MAST::Solid1DTube2SectionProperty::calcJ, + MAST::Solid1DTube2SectionProperty::calcdJ, + DIM1, DIM2)); + + //_J.reset(new MAST::Solid1DnParameterSectionProperty::TorsionalConstant(*cross_section)); + + _Kappa.reset(new MAST::Solid1DnParameterSectionProperty::ShearCoefficientMatrix(*cross_section)); + + _Gamma.reset(new MAST::Solid1DnParameterSectionProperty::WarpingConstant(*cross_section)); + + _initialized = true; +} + + +void MAST::Solid1DTube2SectionElementPropertyCard::create_cross_section( + const libMesh::LibMeshInit& init, const uint n_target_elems, + const libMesh::ElemType element_type) +{ + cross_section.reset(new MAST::CrossSection(init, n_target_elems, + *this, element_type)); +} + + +void MAST::Solid1DTube2SectionElementPropertyCard::calculate_properties_pilkey() +{ + cross_section->calculate_geometric_properties(); + cross_section->calculate_warping_properties(); +} diff --git a/src/property_cards/solid_1d_tube2_section_element_property_card.h b/src/property_cards/solid_1d_tube2_section_element_property_card.h new file mode 100644 index 00000000..55e4f8f8 --- /dev/null +++ b/src/property_cards/solid_1d_tube2_section_element_property_card.h @@ -0,0 +1,117 @@ +/* + * MAST: Multidisciplinary-design Adaptation and Sensitivity Toolkit + * Copyright (C) 2013-2019 Manav Bhatia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * +// * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __mast__solid_1d_tube2_section_element_property_card__ +#define __mast__solid_1d_tube2_section_element_property_card__ + + +// MAST includes +#include "property_cards/solid_1d_2parameter_section_element_property_card.h" +#include "property_cards/solid_1d_nparameter_section_element_property_card.h" + + +// Annulus (Alternative Parameterization) (TUBE2 in Nastran) +namespace MAST{ + namespace Solid1DTube2SectionProperty{ + void calcA(Real& DIM1, Real& DIM2, Real& A); + + void calcdA(Real& DIM1, Real& DIM2, Real& dDIM1, Real& dDIM2, Real& dA); + + void calcIz(Real& DIM1, Real& DIM2, Real& Iz); + + void calcdIz(Real& DIM1, Real& DIM2, Real& dDIM1, Real& dDIM2, Real& dIz); + + void calcIy(Real& DIM1, Real& DIM2, Real& Iy); + + void calcdIy(Real& DIM1, Real& DIM2, Real& dDIM1, Real& dDIM2, Real& dIy); + + void calcIp(Real& DIM1, Real& DIM2, Real& Ip); + + void calcdIp(Real& DIM1, Real& DIM2, Real& dDIM1, Real& dDIM2, Real& dIp); + + void calcJ(Real& DIM1, Real& DIM2, Real& J); + + void calcdJ(Real& DIM1, Real& DIM2, Real& dDIM1, Real& dDIM2, Real& dJ); + + } +} + +namespace MAST { + + class Solid1DTube2SectionElementPropertyCard : public MAST::Solid1DnParameterSectionElementPropertyCard + { + public: + Solid1DTube2SectionElementPropertyCard(): + MAST::Solid1DnParameterSectionElementPropertyCard() {} + + /*! + * virtual destructor + */ + virtual ~Solid1DTube2SectionElementPropertyCard() { } + + virtual void init(const libMesh::LibMeshInit& init); + + virtual void create_cross_section( + const libMesh::LibMeshInit& init, + const uint n_target_elems=3500, + const libMesh::ElemType element_type=libMesh::TRI6); + + virtual void calculate_properties_pilkey(); + + virtual const std::vector get_geom_points(const libMesh::Point& p, const Real t, const uint n=201) const override; + + virtual const std::vector get_geom_points_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, const uint n=201) const override; + + virtual const libMesh::Point get_shear_center(const libMesh::Point& p, const Real t) const override; + + virtual const libMesh::Point get_shear_center_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t) const; + + virtual const libMesh::Point get_centroid(const libMesh::Point& p, const Real t) const override; + + virtual const libMesh::Point get_centroid_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t) const override; + + virtual const std::vector get_stress_points(const libMesh::Point& p, const Real t, const libMesh::Point ps) const override; + + virtual const std::vector get_stress_points_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, const libMesh::Point dps) const override; + + virtual const std::vector> get_holes_points(const libMesh::Point& p, const Real t, const uint n=201) const override; + + virtual const std::vector> get_holes_points_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, const uint n=201) const override; + + std::unique_ptr cross_section; + + const bool is_bisymmetric() const + { + return true; + } + + const bool is_symmetric_z() const + { + return true; + } + + const bool is_symmetric_y() const + { + return true; + } + }; +} + + +#endif // __mast__solid_1d_tube2_section_element_property_card__ diff --git a/tests/property/CMakeLists.txt b/tests/property/CMakeLists.txt index 2658d539..9db05de1 100644 --- a/tests/property/CMakeLists.txt +++ b/tests/property/CMakeLists.txt @@ -3,8 +3,10 @@ target_sources(mast_catch_tests ${CMAKE_CURRENT_LIST_DIR}/mast_solid_1d_section_element_property_card.cpp ${CMAKE_CURRENT_LIST_DIR}/mast_solid_1d_arbitrary_section_element_property_card ${CMAKE_CURRENT_LIST_DIR}/mast_solid_1d_bar_section_element_property_card.cpp + ${CMAKE_CURRENT_LIST_DIR}/mast_solid_1d_I1_section_element_property_card.cpp ${CMAKE_CURRENT_LIST_DIR}/mast_solid_1d_rod_section_element_property_card.cpp ${CMAKE_CURRENT_LIST_DIR}/mast_solid_1d_tube_section_element_property_card.cpp + ${CMAKE_CURRENT_LIST_DIR}/mast_solid_1d_tube2_section_element_property_card.cpp ${CMAKE_CURRENT_LIST_DIR}/mast_solid_2d_section_element_property_card.cpp ${CMAKE_CURRENT_LIST_DIR}/mast_3d_isotropic_element_property_card.cpp) @@ -485,111 +487,265 @@ set_tests_properties(Rod_Element_Property_Card_1D_Dynamic_mpi ## ============================================================================ # 1D TUBE Cross Section add_test(NAME Tube_Element_Property_Card_1D_Base - COMMAND $ "tube_element_property_card_constant_base_1d") + COMMAND $ -w NoTests "tube_element_property_card_constant_base_1d") set_tests_properties(Tube_Element_Property_Card_1D_Base PROPERTIES LABELS "SEQ" FIXTURES_REQUIRED Isotropic_Material_1D_Structural) +add_test(NAME Tube_Element_Property_Card_1D_Base_mpi + COMMAND ${MPIEXEC_EXECUTABLE} -np 2 $ -w NoTests "tube_element_property_card_constant_base_1d") +set_tests_properties(Tube_Element_Property_Card_1D_Base_mpi + PROPERTIES + LABELS "MPI" + FIXTURES_REQUIRED Isotropic_Material_1D_Structural_mpi) + +add_test(NAME Tube_Element_Property_Card_1D_Base_Sensitivity + COMMAND $ -w NoTests "tube_element_property_card_constant_base_sensitivity_1d") +set_tests_properties(Tube_Element_Property_Card_1D_Base_Sensitivity + PROPERTIES + LABELS "SEQ" + FIXTURES_REQUIRED Tube_Element_Property_Card_1D_Base) + +add_test(NAME Tube_Element_Property_Card_1D_Base_Sensitivity_mpi + COMMAND ${MPIEXEC_EXECUTABLE} -np 2 $ -w NoTests "tube_element_property_card_constant_base_sensitivity_1d") +set_tests_properties(Tube_Element_Property_Card_1D_Base_Sensitivity_mpi + PROPERTIES + LABELS "MPI" + FIXTURES_REQUIRED Tube_Element_Property_Card_1D_Base_mpi) + add_test(NAME Tube_Element_Property_Card_1D_Heat_Transfer - COMMAND $ "tube_element_property_card_constant_heat_transfer_1d") + COMMAND $ -w NoTests "tube_element_property_card_constant_heat_transfer_1d") set_tests_properties(Tube_Element_Property_Card_1D_Heat_Transfer PROPERTIES LABELS "SEQ" FIXTURES_REQUIRED Isotropic_Material_1D_Heat_Transfer) + +add_test(NAME Tube_Element_Property_Card_1D_Heat_Transfer_mpi + COMMAND ${MPIEXEC_EXECUTABLE} -np 2 $ -w NoTests "tube_element_property_card_constant_heat_transfer_1d") +set_tests_properties(Tube_Element_Property_Card_1D_Heat_Transfer_mpi + PROPERTIES + LABELS "MPI" + FIXTURES_REQUIRED Isotropic_Material_1D_Heat_Transfer_mpi) add_test(NAME Tube_Element_Property_Card_1D_Thermoelastic - COMMAND $ "tube_element_property_card_constant_thermoelastic_1d") + COMMAND $ -w NoTests "tube_element_property_card_constant_thermoelastic_1d") set_tests_properties(Tube_Element_Property_Card_1D_Thermoelastic PROPERTIES LABELS "SEQ" FIXTURES_REQUIRED Isotropic_Material_1D_Thermoelastic) + +add_test(NAME Tube_Element_Property_Card_1D_Thermoelastic_mpi + COMMAND ${MPIEXEC_EXECUTABLE} -np 2 $ -w NoTests "tube_element_property_card_constant_thermoelastic_1d") +set_tests_properties(Tube_Element_Property_Card_1D_Thermoelastic_mpi + PROPERTIES + LABELS "MPI" + FIXTURES_REQUIRED Isotropic_Material_1D_Thermoelastic_mpi) add_test(NAME Tube_Element_Property_Card_1D_Structural - COMMAND $ "tube_element_property_card_constant_structural_1d") + COMMAND $ -w NoTests "tube_element_property_card_constant_structural_1d") set_tests_properties(Tube_Element_Property_Card_1D_Structural PROPERTIES LABELS "SEQ" FIXTURES_REQUIRED Isotropic_Material_1D_Structural) +add_test(NAME Tube_Element_Property_Card_1D_Structural_mpi + COMMAND ${MPIEXEC_EXECUTABLE} -np 2 $ -w NoTests "tube_element_property_card_constant_structural_1d") +set_tests_properties(Tube_Element_Property_Card_1D_Structural_mpi + PROPERTIES + LABELS "MPI" + FIXTURES_REQUIRED Isotropic_Material_1D_Structural_mpi) + add_test(NAME Tube_Element_Property_Card_1D_Dynamic - COMMAND $ "tube_element_property_card_constant_dynamic_1d") + COMMAND $ -w NoTests "tube_element_property_card_constant_dynamic_1d") set_tests_properties(Tube_Element_Property_Card_1D_Dynamic PROPERTIES LABELS "SEQ" FIXTURES_REQUIRED Isotropic_Material_1D_Dynamic) + +add_test(NAME Tube_Element_Property_Card_1D_Dynamic_mpi + COMMAND ${MPIEXEC_EXECUTABLE} -np 2 $ -w NoTests "tube_element_property_card_constant_dynamic_1d") +set_tests_properties(Tube_Element_Property_Card_1D_Dynamic_mpi + PROPERTIES + LABELS "MPI" + FIXTURES_REQUIRED Isotropic_Material_1D_Dynamic_mpi) ## ============================================================================ -# ## ============================================================================ -# # 1D TUBE2 Cross Section -# add_test(NAME Tube2_Element_Property_Card_1D_Base -# COMMAND mast_catch_tests "tube2_element_property_card_constant_base_1d") -# set_tests_properties(Tube2_Element_Property_Card_1D_Base -# PROPERTIES -# FIXTURES_REQUIRED Isotropic_Material_1D_Structural) -# -# add_test(NAME Tube2_Element_Property_Card_1D_Heat_Transfer -# COMMAND mast_catch_tests "tube2_element_property_card_constant_heat_transfer_1d") -# set_tests_properties(Tube2_Element_Property_Card_1D_Heat_Transfer -# PROPERTIES -# FIXTURES_REQUIRED Isotropic_Material_1D_Heat_Transfer) -# -# add_test(NAME Tube2_Element_Property_Card_1D_Thermoelastic -# COMMAND mast_catch_tests "tube2_element_property_card_constant_thermoelastic_1d") -# set_tests_properties(Tube2_Element_Property_Card_1D_Thermoelastic -# PROPERTIES -# FIXTURES_REQUIRED Isotropic_Material_1D_Thermoelastic) -# -# add_test(NAME Tube2_Element_Property_Card_1D_Structural -# COMMAND mast_catch_tests "tube2_element_property_card_constant_structural_1d") -# set_tests_properties(Tube2_Element_Property_Card_1D_Structural -# PROPERTIES -# FIXTURES_REQUIRED Isotropic_Material_1D_Structural) -# -# add_test(NAME Tube2_Element_Property_Card_1D_Dynamic -# COMMAND mast_catch_tests "tube2_element_property_card_constant_dynamic_1d") -# set_tests_properties(Tube2_Element_Property_Card_1D_Dynamic -# PROPERTIES -# FIXTURES_REQUIRED Isotropic_Material_1D_Dynamic) -# ## ============================================================================ +## ============================================================================ +# 1D TUBE2 Cross Section +add_test(NAME Tube2_Element_Property_Card_1D_Base + COMMAND $ -w NoTests "tube2_element_property_card_constant_base_1d") +set_tests_properties(Tube2_Element_Property_Card_1D_Base + PROPERTIES + LABELS "SEQ" + FIXTURES_REQUIRED Isotropic_Material_1D_Structural) + +add_test(NAME Tube2_Element_Property_Card_1D_Base_mpi + COMMAND ${MPIEXEC_EXECUTABLE} -np 2 $ -w NoTests "tube2_element_property_card_constant_base_1d") +set_tests_properties(Tube2_Element_Property_Card_1D_Base_mpi + PROPERTIES + LABELS "MPI" + FIXTURES_REQUIRED Isotropic_Material_1D_Structural_mpi) + +add_test(NAME Tube2_Element_Property_Card_1D_Base_Sensitivity + COMMAND $ -w NoTests "tube2_element_property_card_constant_base_sensitivity_1d") +set_tests_properties(Tube2_Element_Property_Card_1D_Base_Sensitivity + PROPERTIES + LABELS "SEQ" + FIXTURES_REQUIRED Tube2_Element_Property_Card_1D_Base) + +add_test(NAME Tube2_Element_Property_Card_1D_Base_Sensitivity_mpi + COMMAND ${MPIEXEC_EXECUTABLE} -np 2 $ -w NoTests "tube2_element_property_card_constant_base_sensitivity_1d") +set_tests_properties(Tube2_Element_Property_Card_1D_Base_Sensitivity_mpi + PROPERTIES + LABELS "MPI" + FIXTURES_REQUIRED Tube2_Element_Property_Card_1D_Base_mpi) + +add_test(NAME Tube2_Element_Property_Card_1D_Heat_Transfer + COMMAND $ -w NoTests "tube2_element_property_card_constant_heat_transfer_1d") +set_tests_properties(Tube2_Element_Property_Card_1D_Heat_Transfer + PROPERTIES + LABELS "SEQ" + FIXTURES_REQUIRED Isotropic_Material_1D_Heat_Transfer) + +add_test(NAME Tube2_Element_Property_Card_1D_Heat_Transfer_mpi + COMMAND ${MPIEXEC_EXECUTABLE} -np 2 $ -w NoTests "tube2_element_property_card_constant_heat_transfer_1d") +set_tests_properties(Tube2_Element_Property_Card_1D_Heat_Transfer_mpi + PROPERTIES + LABELS "MPI" + FIXTURES_REQUIRED Isotropic_Material_1D_Heat_Transfer_mpi) +add_test(NAME Tube2_Element_Property_Card_1D_Thermoelastic + COMMAND $ -w NoTests "tube2_element_property_card_constant_thermoelastic_1d") +set_tests_properties(Tube2_Element_Property_Card_1D_Thermoelastic + PROPERTIES + LABELS "SEQ" + FIXTURES_REQUIRED Isotropic_Material_1D_Thermoelastic) + +add_test(NAME Tube2_Element_Property_Card_1D_Thermoelastic_mpi + COMMAND ${MPIEXEC_EXECUTABLE} -np 2 $ -w NoTests "tube2_element_property_card_constant_thermoelastic_1d") +set_tests_properties(Tube2_Element_Property_Card_1D_Thermoelastic_mpi + PROPERTIES + LABELS "MPI" + FIXTURES_REQUIRED Isotropic_Material_1D_Thermoelastic_mpi) -# ## ============================================================================ -# # 1D I1 Cross Section -# add_test(NAME I1_Element_Property_Card_1D_Base -# COMMAND mast_catch_tests "I1_element_property_card_constant_base_1d") -# set_tests_properties(I1_Element_Property_Card_1D_Base -# PROPERTIES -# FIXTURES_REQUIRED Isotropic_Material_1D_Structural) -# -# add_test(NAME I1_Element_Property_Card_1D_Base_Sensitivity -# COMMAND mast_catch_tests "I1_element_property_card_constant_base_sensitivity_1d") -# set_tests_properties(I1_Element_Property_Card_1D_Base_Sensitivity -# PROPERTIES -# FIXTURES_REQUIRED I1_Element_Property_Card_1D_Base) -# -# add_test(NAME I1_Element_Property_Card_1D_Heat_Transfer -# COMMAND mast_catch_tests "I1_element_property_card_constant_heat_transfer_1d") -# set_tests_properties(I1_Element_Property_Card_1D_Heat_Transfer -# PROPERTIES -# FIXTURES_REQUIRED Isotropic_Material_1D_Heat_Transfer) -# -# add_test(NAME I1_Element_Property_Card_1D_Thermoelastic -# COMMAND mast_catch_tests "I1_element_property_card_constant_thermoelastic_1d") -# set_tests_properties(I1_Element_Property_Card_1D_Thermoelastic -# PROPERTIES -# FIXTURES_REQUIRED Isotropic_Material_1D_Thermoelastic) -# -# add_test(NAME I1_Element_Property_Card_1D_Structural -# COMMAND mast_catch_tests "I1_element_property_card_constant_structural_1d") -# set_tests_properties(I1_Element_Property_Card_1D_Structural -# PROPERTIES -# FIXTURES_REQUIRED Isotropic_Material_1D_Structural) -# -# add_test(NAME I1_Element_Property_Card_1D_Dynamic -# COMMAND mast_catch_tests "I1_element_property_card_constant_dynamic_1d") -# ## ============================================================================ +add_test(NAME Tube2_Element_Property_Card_1D_Structural + COMMAND $ -w NoTests "tube2_element_property_card_constant_structural_1d") +set_tests_properties(Tube2_Element_Property_Card_1D_Structural + PROPERTIES + LABELS "SEQ" + FIXTURES_REQUIRED Isotropic_Material_1D_Structural) + +add_test(NAME Tube2_Element_Property_Card_1D_Structural_mpi + COMMAND ${MPIEXEC_EXECUTABLE} -np 2 $ -w NoTests "tube2_element_property_card_constant_structural_1d") +set_tests_properties(Tube2_Element_Property_Card_1D_Structural_mpi + PROPERTIES + LABELS "MPI" + FIXTURES_REQUIRED Isotropic_Material_1D_Structural_mpi) + +add_test(NAME Tube2_Element_Property_Card_1D_Dynamic + COMMAND $ -w NoTests "tube2_element_property_card_constant_dynamic_1d") +set_tests_properties(Tube2_Element_Property_Card_1D_Dynamic + PROPERTIES + LABELS "SEQ" + FIXTURES_REQUIRED Isotropic_Material_1D_Dynamic) + +add_test(NAME Tube2_Element_Property_Card_1D_Dynamic_mpi + COMMAND ${MPIEXEC_EXECUTABLE} -np 2 $ -w NoTests "tube2_element_property_card_constant_dynamic_1d") +set_tests_properties(Tube2_Element_Property_Card_1D_Dynamic_mpi + PROPERTIES + LABELS "MPI" + FIXTURES_REQUIRED Isotropic_Material_1D_Dynamic_mpi) +## ============================================================================ + + +## ============================================================================ +# 1D I1 Cross Section +add_test(NAME I1_Element_Property_Card_1D_Base + COMMAND $ -w NoTests "I1_element_property_card_constant_base_1d") +set_tests_properties(I1_Element_Property_Card_1D_Base + PROPERTIES + LABELS "SEQ" + FIXTURES_REQUIRED Isotropic_Material_1D_Structural) + +add_test(NAME I1_Element_Property_Card_1D_Base_mpi + COMMAND ${MPIEXEC_EXECUTABLE} -np 2 $ -w NoTests "I1_element_property_card_constant_base_1d") +set_tests_properties(I1_Element_Property_Card_1D_Base_mpi + PROPERTIES + LABELS "MPI" + FIXTURES_REQUIRED Isotropic_Material_1D_Structural_mpi) + +add_test(NAME I1_Element_Property_Card_1D_Base_Sensitivity + COMMAND $ -w NoTests "I1_element_property_card_constant_base_sensitivity_1d") +set_tests_properties(I1_Element_Property_Card_1D_Base_Sensitivity + PROPERTIES + LABELS "SEQ" + FIXTURES_REQUIRED I1_Element_Property_Card_1D_Base) + +add_test(NAME I1_Element_Property_Card_1D_Base_Sensitivity_mpi + COMMAND ${MPIEXEC_EXECUTABLE} -np 2 $ -w NoTests "I1_element_property_card_constant_base_sensitivity_1d") +set_tests_properties(I1_Element_Property_Card_1D_Base_Sensitivity_mpi + PROPERTIES + LABELS "MPI" + FIXTURES_REQUIRED I1_Element_Property_Card_1D_Base_mpi) + +add_test(NAME I1_Element_Property_Card_1D_Heat_Transfer + COMMAND $ -w NoTests "I1_element_property_card_constant_heat_transfer_1d") +set_tests_properties(I1_Element_Property_Card_1D_Heat_Transfer + PROPERTIES + LABELS "SEQ" + FIXTURES_REQUIRED Isotropic_Material_1D_Heat_Transfer) + +add_test(NAME I1_Element_Property_Card_1D_Heat_Transfer_mpi + COMMAND ${MPIEXEC_EXECUTABLE} -np 2 $ -w NoTests "I1_element_property_card_constant_heat_transfer_1d") +set_tests_properties(I1_Element_Property_Card_1D_Heat_Transfer_mpi + PROPERTIES + LABELS "MPI" + FIXTURES_REQUIRED Isotropic_Material_1D_Heat_Transfer_mpi) + +add_test(NAME I1_Element_Property_Card_1D_Thermoelastic + COMMAND $ -w NoTests "I1_element_property_card_constant_thermoelastic_1d") +set_tests_properties(I1_Element_Property_Card_1D_Thermoelastic + PROPERTIES + LABELS "SEQ" + FIXTURES_REQUIRED Isotropic_Material_1D_Thermoelastic) + +add_test(NAME I1_Element_Property_Card_1D_Thermoelastic_mpi + COMMAND ${MPIEXEC_EXECUTABLE} -np 2 $ -w NoTests "I1_element_property_card_constant_thermoelastic_1d") +set_tests_properties(I1_Element_Property_Card_1D_Thermoelastic_mpi + PROPERTIES + LABELS "MPI" + FIXTURES_REQUIRED Isotropic_Material_1D_Thermoelastic_mpi) + +add_test(NAME I1_Element_Property_Card_1D_Structural + COMMAND $ -w NoTests "I1_element_property_card_constant_structural_1d") +set_tests_properties(I1_Element_Property_Card_1D_Structural + PROPERTIES + LABELS "SEQ" + FIXTURES_REQUIRED Isotropic_Material_1D_Structural) + +add_test(NAME I1_Element_Property_Card_1D_Structural_mpi + COMMAND ${MPIEXEC_EXECUTABLE} -np 2 $ -w NoTests "I1_element_property_card_constant_structural_1d") +set_tests_properties(I1_Element_Property_Card_1D_Structural_mpi + PROPERTIES + LABELS "MPI" + FIXTURES_REQUIRED Isotropic_Material_1D_Structural_mpi) + +add_test(NAME I1_Element_Property_Card_1D_Dynamic + COMMAND $ -w NoTests "I1_element_property_card_constant_dynamic_1d") +set_tests_properties(I1_Element_Property_Card_1D_Dynamic + PROPERTIES + LABELS "SEQ" + FIXTURES_REQUIRED Isotropic_Material_1D_Dynamic) + +add_test(NAME I1_Element_Property_Card_1D_Dynamic_mpi + COMMAND ${MPIEXEC_EXECUTABLE} -np 2 $ -w NoTests "I1_element_property_card_constant_dynamic_1d") +set_tests_properties(I1_Element_Property_Card_1D_Dynamic_mpi + PROPERTIES + LABELS "MPI" + FIXTURES_REQUIRED Isotropic_Material_1D_Dynamic_mpi) +## ============================================================================ # ## ============================================================================ diff --git a/tests/property/mast_solid_1d_I1_section_element_property_card.cpp b/tests/property/mast_solid_1d_I1_section_element_property_card.cpp new file mode 100644 index 00000000..fb20c6e9 --- /dev/null +++ b/tests/property/mast_solid_1d_I1_section_element_property_card.cpp @@ -0,0 +1,1659 @@ +// Catch2 includes +#include "catch.hpp" + +// libMesh includes +#include "libmesh/point.h" + +// MAST includes +#include "base/parameter.h" +#include "base/constant_field_function.h" +#include "property_cards/isotropic_material_property_card.h" +#include "property_cards/solid_1d_I1_section_element_property_card.h" + +// Custom includes +#include "test_helpers.h" + +extern libMesh::LibMeshInit* p_global_init; + +#define PI 3.1415926535897932 + +/** + * A BAR is defined as a solid rectangular cross section defined by two + * parameters. + */ +TEST_CASE("I1_element_property_card_constant_base_1d", + "[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + + // Define Material Properties as MAST Parameters + MAST::Parameter rho("rho_param", 1420.5); // Density + MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity + MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio + MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity + MAST::Parameter k("k_param", 237.0); // Thermal Conductivity + + const Real G = E() / (2. * (1. + nu())); + + // Define Section Properties as MAST Parameters + MAST::Parameter DIM1("DIM1", 3.770); + MAST::Parameter DIM2("DIM2", 0.170); + MAST::Parameter DIM3("DIM3", 5.470); + MAST::Parameter DIM4("DIM4", 5.900); + + MAST::Parameter offset_y("offy_param", -0.787); // Section offset in y-direction + MAST::Parameter offset_z("offz_param", 0.687); // Section offset in z-direction + + // Define Sensitivity Parameters + std::vector sens_params = {&DIM1}; + uint n_s = sens_params.size(); + + // Create field functions to dsitribute these constant parameters throughout the model + // Section Property Field Functions + MAST::ConstantFieldFunction DIM1_f("DIM1", DIM1); + MAST::ConstantFieldFunction DIM2_f("DIM2", DIM2); + MAST::ConstantFieldFunction DIM3_f("DIM3", DIM3); + MAST::ConstantFieldFunction DIM4_f("DIM4", DIM4); + MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); + MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); + // Material Property Field Functions + MAST::ConstantFieldFunction rho_f("rho", rho); + MAST::ConstantFieldFunction E_f("E", E); + MAST::ConstantFieldFunction nu_f("nu", nu); + MAST::ConstantFieldFunction cp_f("cp", cp); + MAST::ConstantFieldFunction k_f("k_th", k); + + // Initialize the material + MAST::IsotropicMaterialPropertyCard material; + + // Add the material property constant field functions to the material card + material.add(rho_f); + material.add(k_f); + material.add(cp_f); + material.add(E_f); + material.add(nu_f); + + // Initialize the section + MAST::Solid1DI1SectionElementPropertyCard section; + + // Add the section property constant field functions to the section card + section.add(DIM1_f); + section.add(DIM2_f); + section.add(DIM3_f); + section.add(DIM4_f); + + section.add(offsety_f); + section.add(offsetz_f); + + // Add the material card to the section card + section.set_material(material); + + // Specify a section orientation point and add it to the section. + RealVectorX orientation = RealVectorX::Zero(3); + orientation(1) = 1.0; + section.y_vector() = orientation; + + // Now initialize the section + section.init(*p_global_init); + + REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional + REQUIRE( section.depends_on(DIM1) ); + REQUIRE( section.depends_on(offset_y) ); + REQUIRE( section.depends_on(offset_z) ); + REQUIRE( section.depends_on(k) ); + REQUIRE( section.depends_on(cp) ); + REQUIRE( section.depends_on(rho) ); + + REQUIRE( section.if_isotropic() ); + + // True values + const Real area_true = 2.6241000000000039e+00; + const Real torsion_constant_true = 3.4912416307463445e-02; + const Real first_area_moment_z_true = -2.0651667000000016e+00; + const Real first_area_moment_y_true = 1.8027567000000015e+00; + const Real second_area_moment_zz_true = 1.7639240550400139e+01; + const Real second_area_moment_yy_true = 3.4324069553999919e+00; + const Real second_area_moment_zy_true = -1.4187695228999926e+00; + const Real second_area_moment_polar_true = 2.1071647505800129e+01; + const Real Izzc_true = 1.6013954357500140e+01; + const Real Iyyc_true = 2.1939131024999914e+00; + const Real Izyc_true = 7.5495165674510645e-15; + const Real Ipc_true = 1.8207867460000131e+01; + const Real warping_constant_true = 1.7690289289249652e+01; + const Real kappa_z_true = 5.4403106725573769e-01; + const Real kappa_y_true = 3.5065087923352467e-01; + const Real xs_true = 6.8699874537432160e-01; + const Real ys_true = -7.8699671905199586e-01; + const Real xst_true = 6.8699874537432160e-01; + const Real yst_true = -7.8699671905199586e-01; + const Real xc_true = 6.8699999999999961e-01; + const Real yc_true = -7.8699999999999948e-01; + const libMesh::Point centroid_true(xc_true, yc_true); + const libMesh::Point shear_center_true(xs_true, ys_true); + + const libMesh::Point point(4.3, -3.5, -6.7); + const Real time = 8.22; + + SECTION("section_properties") + { + Real area; + const MAST::FieldFunction& Area = section.A(); + Area(point, time, area); + CHECK( area == Approx(area_true) ); + + Real first_area_moment_y; + const MAST::FieldFunction& Ay = section.Ay(); + Ay(point, time, first_area_moment_y); + CHECK( first_area_moment_y == Approx(first_area_moment_y_true) ); + + Real first_area_moment_z; + const MAST::FieldFunction& Az = section.Az(); + Az(point, time, first_area_moment_z); + CHECK( first_area_moment_z == Approx(first_area_moment_z_true) ); + + RealMatrixX I; + const MAST::FieldFunction& Inertias = section.I(); + Inertias(point, time, I); + CHECK( I(0,1) == I(1,0) ); + Real Iyy = I(1,1); + Real Izz = I(0,0); + Real Izy = I(0,1); + CHECK( Izz == Approx(second_area_moment_zz_true) ); + CHECK( Iyy == Approx(second_area_moment_yy_true) ); + CHECK( Izy == Approx(second_area_moment_zy_true) ); + + Real Ip; + const MAST::FieldFunction& PolarInertia = section.Ip(); + PolarInertia(point, time, Ip); + CHECK( Ip == Approx(second_area_moment_polar_true) ); + + Real torsion_constant; + const MAST::FieldFunction& TorsionConstant = section.J(); + TorsionConstant(point, time, torsion_constant); + CHECK( torsion_constant == Approx(torsion_constant_true).epsilon(0.005)); + + Real warping_constant; + const MAST::FieldFunction& WarpingConstant = section.Gam(); + WarpingConstant(point, time, warping_constant); + CHECK( warping_constant == Approx(warping_constant_true).epsilon(0.005) ); + + RealMatrixX shear_coefficients; + const MAST::FieldFunction& ShearCoefficientMatrix = section.Kap(); + ShearCoefficientMatrix(point, time, shear_coefficients); + CHECK( shear_coefficients(0,0) == Approx(kappa_z_true).epsilon(0.005) ); + CHECK( shear_coefficients(1,1) == Approx(kappa_y_true).epsilon(0.005) ); + + libMesh::Point centroid = section.get_centroid(point, time); + CHECK( centroid(0) == Approx(centroid_true(0)) ); + CHECK( centroid(1) == Approx(centroid_true(1)) ); + + libMesh::Point shear_center = section.get_shear_center(point, time); + CHECK(shear_center(0) == Approx(xs_true).epsilon(0.005)); + CHECK(shear_center(1) == Approx(ys_true).epsilon(0.005)); + } + + SECTION("stress_points") + { + const std::vector stress_points_true = { + libMesh::Point(1.9700000000000000e+00, 2.9500000000000002e+00, 0.), + libMesh::Point(1.9700000000000000e+00, -2.9500000000000002e+00, 0.), + libMesh::Point(-1.9700000000000000e+00, -2.9500000000000002e+00, 0.), + libMesh::Point(-1.9700000000000000e+00, 2.9500000000000002e+00, 0.) + }; + libMesh::Point centroid = section.get_centroid(point, time); + CHECK( centroid(0) == Approx(centroid_true(0)) ); + CHECK( centroid(1) == Approx(centroid_true(1)) ); + std::vector stress_points = section.get_stress_points(point, time, centroid); + + for (uint i=0; i sens_params = {&DIM1, &DIM2, &DIM3, &DIM4}; + uint n_s = sens_params.size(); + + // Create field functions to dsitribute these constant parameters throughout the model + // Section Property Field Functions + MAST::ConstantFieldFunction DIM1_f("DIM1", DIM1); + MAST::ConstantFieldFunction DIM2_f("DIM2", DIM2); + MAST::ConstantFieldFunction DIM3_f("DIM3", DIM3); + MAST::ConstantFieldFunction DIM4_f("DIM4", DIM4); + MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); + MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); + // Material Property Field Functions + MAST::ConstantFieldFunction rho_f("rho", rho); + MAST::ConstantFieldFunction E_f("E", E); + MAST::ConstantFieldFunction nu_f("nu", nu); + MAST::ConstantFieldFunction cp_f("cp", cp); + MAST::ConstantFieldFunction k_f("k_th", k); + + // Initialize the material + MAST::IsotropicMaterialPropertyCard material; + + // Add the material property constant field functions to the material card + material.add(rho_f); + material.add(k_f); + material.add(cp_f); + material.add(E_f); + material.add(nu_f); + + // Initialize the section + MAST::Solid1DI1SectionElementPropertyCard section; + + // Add the section property constant field functions to the section card + section.add(DIM1_f); + section.add(DIM2_f); + section.add(DIM3_f); + section.add(DIM4_f); + + section.add(offsety_f); + section.add(offsetz_f); + + // Add the material card to the section card + section.set_material(material); + + // Specify a section orientation point and add it to the section. + RealVectorX orientation = RealVectorX::Zero(3); + orientation(1) = 1.0; + section.y_vector() = orientation; + + // Now initialize the section + section.init(*p_global_init); + + REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional + REQUIRE( section.depends_on(DIM1) ); + REQUIRE( section.depends_on(offset_y) ); + REQUIRE( section.depends_on(offset_z) ); + REQUIRE( section.depends_on(k) ); + REQUIRE( section.depends_on(cp) ); + REQUIRE( section.depends_on(rho) ); + + REQUIRE( section.if_isotropic() ); + + // True values + const Real area_true = 2.6241000000000039e+00; + const Real torsion_constant_true = 3.4912416307463445e-02; + const Real first_area_moment_z_true = -2.0651667000000016e+00; + const Real first_area_moment_y_true = 1.8027567000000015e+00; + const Real second_area_moment_zz_true = 1.7639240550400139e+01; + const Real second_area_moment_yy_true = 3.4324069553999919e+00; + const Real second_area_moment_zy_true = -1.4187695228999926e+00; + const Real second_area_moment_polar_true = 2.1071647505800129e+01; + const Real Izzc_true = 1.6013954357500140e+01; + const Real Iyyc_true = 2.1939131024999914e+00; + const Real Izyc_true = 7.5495165674510645e-15; + const Real Ipc_true = 1.8207867460000131e+01; + const Real warping_constant_true = 1.7690289289249652e+01; + const Real kappa_z_true = 5.4403106725573769e-01; + const Real kappa_y_true = 3.5065087923352467e-01; + const Real xs_true = 6.8699874537432160e-01; + const Real ys_true = -7.8699671905199586e-01; + const Real xst_true = 6.8699874537432160e-01; + const Real yst_true = -7.8699671905199586e-01; + const Real xc_true = 6.8699999999999961e-01; + const Real yc_true = -7.8699999999999948e-01; + const libMesh::Point centroid_true(xc_true, yc_true); + const libMesh::Point shear_center_true(xs_true, ys_true); + + const libMesh::Point point(4.3, -3.5, -6.7); + const Real time = 8.22; + + Real dA_dDIM1, dA_dDIM2; + Real dCz_dDIM1, dCz_dDIM2; + Real dCy_dDIM1, dCy_dDIM2; + Real dQz_dDIM1, dQz_dDIM2; + Real dQy_dDIM1, dQy_dDIM2; + Real dIzz_dDIM1, dIzz_dDIM2; + Real dIyy_dDIM1, dIyy_dDIM2; + Real dIzy_dDIM1, dIzy_dDIM2; + Real dIp_dDIM1, dIp_dDIM2; + Real dIzzc_dDIM1, dIzzc_dDIM2; + Real dIyyc_dDIM1, dIyyc_dDIM2; + Real dIzyc_dDIM1, dIzyc_dDIM2; + Real dIpc_dDIM1, dIpc_dDIM2; + Real dJ_dDIM1, dJ_dDIM2; + Real dxs_dDIM1, dxs_dDIM2; + Real dys_dDIM1, dys_dDIM2; + Real dW_dDIM1, dW_dDIM2; + + Real f_h, f_2h, f_n, f_2n; + RealVectorX fv_h, fv_2h, fv_n, fv_2n; + RealMatrixX fm_h, fm_2h, fm_n, fm_2n; + + const Real delta = 1.220703125e-04; // (np.spacing(1))**(0.25) + + // Area Sensitivity Check + const MAST::FieldFunction& Area = section.A(); + std::vector dA(n_s); + for (uint i=0; i dA_cd(n_s); + for (uint i=0; iname() << " = " << dA[i] << "\tdA_cd = " << dA_cd[i] << std::endl; + REQUIRE(dA[i] == Approx(dA_cd[i])); + } + + + // Centroid Sensitivity Check + std::vector dC(n_s); + for (uint i=0; i dC_cd(n_s); + for (uint i=0; iname() << " = " << dC[i] << "\tdC_cd = " << dC_cd[i] << std::endl; + REQUIRE(dC[i](0) == Approx(dC_cd[i](0)).margin(1.49e-08) ); + REQUIRE(dC[i](1) == Approx(dC_cd[i](1)).margin(1.49e-08) ); + } + + // First Area Moments Sensitivity Check + const MAST::FieldFunction& Area_y = section.Ay(); + std::vector dAy(n_s); + for (uint i=0; i dAy_cd(n_s); + for (uint i=0; iname() << " = " << dAy[i] << "\tdAy_cd = " << dAy_cd[i] << std::endl; + REQUIRE(dAy[i] == Approx(dAy_cd[i])); + } + + + const MAST::FieldFunction& Area_z = section.Az(); + std::vector dAz(n_s); + for (uint i=0; i dAz_cd(n_s); + for (uint i=0; iname() << " = " << dAz[i] << "\tdAz_cd = " << dAz_cd[i] << std::endl; + REQUIRE(dAz[i] == Approx(dAz_cd[i])); + } + + + // Second Area Moments Sensitivity Check + const MAST::FieldFunction& Inertia = section.I(); + std::vector dI(n_s); + for (uint i=0; i dI_cd(n_s); + for (uint i=0; iname() << " =\n" << dI[i] << "\ndI_cd = \n" << dI_cd[i] << std::endl; + + Real dIzz = dI[i](0,0); + Real dIyy = dI[i](1,1); + Real dIyz = dI[i](1,0); + Real dIzy = dI[i](0,1); + + Real dIzz_cd = dI_cd[i](0,0); + Real dIyy_cd = dI_cd[i](1,1); + Real dIyz_cd = dI_cd[i](1,0); + Real dIzy_cd = dI_cd[i](0,1); + + REQUIRE(dIzz == Approx(dIzz_cd)); + REQUIRE(dIyy == Approx(dIyy_cd)); + REQUIRE(dIyz == Approx(dIyz_cd)); + REQUIRE(dIzy == Approx(dIzy_cd)); + REQUIRE(dIyz == dIzy); // symmetry check + } + + + // Second Area Polar Moment Sensitivity Check + const MAST::FieldFunction& PolarInertia = section.Ip(); + std::vector dIp(n_s); + for (uint i=0; i dIp_cd(n_s); + for (uint i=0; iname() << " = " << dIp[i] << "\tdIp_cd = " << dIp_cd[i] << std::endl; + REQUIRE(dIp[i] == Approx(dIp_cd[i])); + } + + +// // Shear Center Sensitivity Check +// std::vector dCs(n_s); +// for (uint i=0; i dCs_cd(n_s); +// for (uint i=0; iname() << " = " << dCs[i] << "\tdCs_cd = " << dCs_cd[i] << std::endl; +// REQUIRE(dCs[i](0) == Approx(dCs_cd[i](0)) ); +// REQUIRE(dCs[i](1) == Approx(dCs_cd[i](1)) ); +// } + + + // Torsion Constant Sensitivity Check + // NOTE: The field function below is not made constant because currently a finite difference is used to calculate sensitivity. + MAST::FieldFunction& TorsionConstant = section.J(); + std::vector dJ(n_s); + for (uint i=0; i dJ_cd(n_s); + for (uint i=0; iname() << " = " << dJ[i] << "\tdJ_cd = " << dJ_cd[i] << std::endl; + REQUIRE(dJ[i] == Approx(dJ_cd[i]).epsilon(0.1) ); + // NOTE: 10% error margin due to 'exact' sensitivity being calculated using finite difference + } + + + // Shear Coefficient Sensitivity Check + // NOTE: The field function below is not made constant because currently a finite difference is used to calculate sensitivity. + MAST::FieldFunction& Kappa = section.Kap(); + std::vector dK(n_s); + for (uint i=0; i dK_cd(n_s); + for (uint i=0; iname() << " =\n" << dK[i] << "\ndK_cd = \n" << dK_cd[i] << std::endl; + + Real dKzz = dK[i](0,0); + Real dKyy = dK[i](1,1); + Real dKyz = dK[i](1,0); + Real dKzy = dK[i](0,1); + + Real dKzz_cd = dK_cd[i](0,0); + Real dKyy_cd = dK_cd[i](1,1); + Real dKyz_cd = dK_cd[i](1,0); + Real dKzy_cd = dK_cd[i](0,1); + + REQUIRE(dKzz == Approx(dKzz_cd).epsilon(0.1)); + REQUIRE(dKyy == Approx(dKyy_cd).epsilon(0.1)); + //REQUIRE(dKyz == Approx(dKyz_cd).epsilon(0.1)); // Comparison can be hard when this is nearly infinite (~1e+13) + //REQUIRE(dKzy == Approx(dKzy_cd).epsilon(0.1)); // Comparison can be hard when this is nearly infinite (~1e+13) + // NOTE: 10% error margin due to 'exact' sensitivity being calculated using finite difference + REQUIRE(dKyz == dKzy); // symmetry check + } + + + // Warping Constant Sensitivity Check + // NOTE: The field function below is not made constant because currently a finite difference is used to calculate sensitivity. + MAST::FieldFunction& WarpingConstant = section.Gam(); + std::vector dW(n_s); + for (uint i=0; i dW_cd(n_s); + for (uint i=0; iname() << " = " << dW[i] << "\tdW_cd = " << dW_cd[i] << std::endl; + REQUIRE(dW[i] == Approx(dW_cd[i]).epsilon(0.1) ); + // NOTE: 10% error margin due to 'exact' sensitivity being calculated using finite difference + } +} + + +TEST_CASE("I1_element_property_card_constant_heat_transfer_1d", + "[heat_transfer],[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + + // Define Material Properties as MAST Parameters + MAST::Parameter rho("rho_param", 1420.5); // Density + MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity + MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio + MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity + MAST::Parameter k("k_param", 237.0); // Thermal Conductivity + + const Real G = E() / (2. * (1. + nu())); + + // Define Section Properties as MAST Parameters + MAST::Parameter DIM1("DIM1", 3.770); + MAST::Parameter DIM2("DIM2", 0.170); + MAST::Parameter DIM3("DIM3", 5.470); + MAST::Parameter DIM4("DIM4", 5.900); + + MAST::Parameter offset_y("offy_param", -0.787); // Section offset in y-direction + MAST::Parameter offset_z("offz_param", 0.687); // Section offset in z-direction + + // Define Sensitivity Parameters + std::vector sens_params = {&DIM1}; + uint n_s = sens_params.size(); + + // Create field functions to dsitribute these constant parameters throughout the model + // Section Property Field Functions + MAST::ConstantFieldFunction DIM1_f("DIM1", DIM1); + MAST::ConstantFieldFunction DIM2_f("DIM2", DIM2); + MAST::ConstantFieldFunction DIM3_f("DIM3", DIM3); + MAST::ConstantFieldFunction DIM4_f("DIM4", DIM4); + MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); + MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); + // Material Property Field Functions + MAST::ConstantFieldFunction rho_f("rho", rho); + MAST::ConstantFieldFunction E_f("E", E); + MAST::ConstantFieldFunction nu_f("nu", nu); + MAST::ConstantFieldFunction cp_f("cp", cp); + MAST::ConstantFieldFunction k_f("k_th", k); + + // Initialize the material + MAST::IsotropicMaterialPropertyCard material; + + // Add the material property constant field functions to the material card + material.add(rho_f); + material.add(k_f); + material.add(cp_f); + material.add(E_f); + material.add(nu_f); + + // Initialize the section + MAST::Solid1DI1SectionElementPropertyCard section; + + // Add the section property constant field functions to the section card + section.add(DIM1_f); + section.add(DIM2_f); + section.add(DIM3_f); + section.add(DIM4_f); + + section.add(offsety_f); + section.add(offsetz_f); + + // Add the material card to the section card + section.set_material(material); + + // Specify a section orientation point and add it to the section. + RealVectorX orientation = RealVectorX::Zero(3); + orientation(1) = 1.0; + section.y_vector() = orientation; + + // Now initialize the section + section.init(*p_global_init); + + REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional + REQUIRE( section.depends_on(DIM1) ); + REQUIRE( section.depends_on(offset_y) ); + REQUIRE( section.depends_on(offset_z) ); + REQUIRE( section.depends_on(k) ); + REQUIRE( section.depends_on(cp) ); + REQUIRE( section.depends_on(rho) ); + + REQUIRE( section.if_isotropic() ); + + // True values + const Real area_true = 2.6241000000000039e+00; + const Real torsion_constant_true = 3.4912416307463445e-02; + const Real first_area_moment_z_true = -2.0651667000000016e+00; + const Real first_area_moment_y_true = 1.8027567000000015e+00; + const Real second_area_moment_zz_true = 1.7639240550400139e+01; + const Real second_area_moment_yy_true = 3.4324069553999919e+00; + const Real second_area_moment_zy_true = -1.4187695228999926e+00; + const Real second_area_moment_polar_true = 2.1071647505800129e+01; + const Real Izzc_true = 1.6013954357500140e+01; + const Real Iyyc_true = 2.1939131024999914e+00; + const Real Izyc_true = 7.5495165674510645e-15; + const Real Ipc_true = 1.8207867460000131e+01; + const Real warping_constant_true = 1.7690289289249652e+01; + const Real kappa_z_true = 5.4403106725573769e-01; + const Real kappa_y_true = 3.5065087923352467e-01; + const Real xs_true = 6.8699874537432160e-01; + const Real ys_true = -7.8699671905199586e-01; + const Real xst_true = 6.8699874537432160e-01; + const Real yst_true = -7.8699671905199586e-01; + const Real xc_true = 6.8699999999999961e-01; + const Real yc_true = -7.8699999999999948e-01; + const libMesh::Point centroid_true(xc_true, yc_true); + const libMesh::Point shear_center_true(xs_true, ys_true); + + const libMesh::Point point(4.3, -3.5, -6.7); + const Real time = 8.22; + + Real area; + const MAST::FieldFunction& Area = section.A(); + Area(point, time, area); + REQUIRE( area == Approx(area_true) ); + + + SECTION("1D section thermal conductance matrix") + { + /** + * As of Dec. 17, 2019, inertia_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * inertia_matrix to be obtained without any input arguments. + */ + std::unique_ptr> conduct_mat = section.thermal_conductance_matrix(); + + const libMesh::Point point(2.3, 3.1, 5.2); + const Real time = 2.34; + RealMatrixX D_sec_conduc; + conduct_mat->operator()(point, time, D_sec_conduc); + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_conduc_true = RealMatrixX::Zero(1,1); + D_sec_conduc_true(0,0) = k() * area_true; + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_conduc); + std::vector truth = eigen_matrix_to_std_vector(D_sec_conduc_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } + + SECTION("1D section thermal capacitance matrix") + { + /** + * As of Dec. 17, 2019, inertia_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * inertia_matrix to be obtained without any input arguments. + */ + std::unique_ptr> capaci_mat = section.thermal_capacitance_matrix(); + + const libMesh::Point point(2.3, 3.1, 5.2); + const Real time = 2.34; + RealMatrixX D_sec_capac; + capaci_mat->operator()(point, time, D_sec_capac); + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_capac_true = RealMatrixX::Zero(1,1); + D_sec_capac_true(0,0) = rho() * cp() * area_true; + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_capac); + std::vector truth = eigen_matrix_to_std_vector(D_sec_capac_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } +} + + +TEST_CASE("I1_element_property_card_constant_thermoelastic_1d", + "[thermoelastic],[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + + // Define Material Properties as MAST Parameters + MAST::Parameter rho("rho_param", 1420.5); // Density + MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity + MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio + MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity + MAST::Parameter k("k_param", 237.0); // Thermal Conductivity + MAST::Parameter alpha("alpha_parm", 5.23e-05); // Coeff. of Thermal Exp. + + const Real G = E() / (2. * (1. + nu())); + + // Define Section Properties as MAST Parameters + MAST::Parameter DIM1("DIM1", 3.770); + MAST::Parameter DIM2("DIM2", 0.170); + MAST::Parameter DIM3("DIM3", 5.470); + MAST::Parameter DIM4("DIM4", 5.900); + + MAST::Parameter offset_y("offy_param", -0.787); // Section offset in y-direction + MAST::Parameter offset_z("offz_param", 0.687); // Section offset in z-direction + + // Define Sensitivity Parameters + std::vector sens_params = {&DIM1}; + uint n_s = sens_params.size(); + + // Create field functions to dsitribute these constant parameters throughout the model + // Section Property Field Functions + MAST::ConstantFieldFunction DIM1_f("DIM1", DIM1); + MAST::ConstantFieldFunction DIM2_f("DIM2", DIM2); + MAST::ConstantFieldFunction DIM3_f("DIM3", DIM3); + MAST::ConstantFieldFunction DIM4_f("DIM4", DIM4); + MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); + MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); + // Material Property Field Functions + MAST::ConstantFieldFunction rho_f("rho", rho); + MAST::ConstantFieldFunction E_f("E", E); + MAST::ConstantFieldFunction nu_f("nu", nu); + MAST::ConstantFieldFunction cp_f("cp", cp); + MAST::ConstantFieldFunction k_f("k_th", k); + MAST::ConstantFieldFunction alpha_f("alpha_expansion", alpha); + + // Initialize the material + MAST::IsotropicMaterialPropertyCard material; + + // Add the material property constant field functions to the material card + material.add(rho_f); + material.add(k_f); + material.add(cp_f); + material.add(E_f); + material.add(nu_f); + material.add(alpha_f); + + // Initialize the section + MAST::Solid1DI1SectionElementPropertyCard section; + + // Add the section property constant field functions to the section card + section.add(DIM1_f); + section.add(DIM2_f); + section.add(DIM3_f); + section.add(DIM4_f); + + section.add(offsety_f); + section.add(offsetz_f); + + // Add the material card to the section card + section.set_material(material); + + // Specify a section orientation point and add it to the section. + RealVectorX orientation = RealVectorX::Zero(3); + orientation(1) = 1.0; + section.y_vector() = orientation; + + // Now initialize the section + section.init(*p_global_init); + + REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional + REQUIRE( section.depends_on(DIM1) ); + REQUIRE( section.depends_on(offset_y) ); + REQUIRE( section.depends_on(offset_z) ); + REQUIRE( section.depends_on(k) ); + REQUIRE( section.depends_on(cp) ); + REQUIRE( section.depends_on(rho) ); + + REQUIRE( section.if_isotropic() ); + + // True values + const Real area_true = 2.6241000000000039e+00; + const Real torsion_constant_true = 3.4912416307463445e-02; + const Real first_area_moment_z_true = -2.0651667000000016e+00; + const Real first_area_moment_y_true = 1.8027567000000015e+00; + const Real second_area_moment_zz_true = 1.7639240550400139e+01; + const Real second_area_moment_yy_true = 3.4324069553999919e+00; + const Real second_area_moment_zy_true = -1.4187695228999926e+00; + const Real second_area_moment_polar_true = 2.1071647505800129e+01; + const Real Izzc_true = 1.6013954357500140e+01; + const Real Iyyc_true = 2.1939131024999914e+00; + const Real Izyc_true = 7.5495165674510645e-15; + const Real Ipc_true = 1.8207867460000131e+01; + const Real warping_constant_true = 1.7690289289249652e+01; + const Real kappa_z_true = 5.4403106725573769e-01; + const Real kappa_y_true = 3.5065087923352467e-01; + const Real xs_true = 6.8699874537432160e-01; + const Real ys_true = -7.8699671905199586e-01; + const Real xst_true = 6.8699874537432160e-01; + const Real yst_true = -7.8699671905199586e-01; + const Real xc_true = 6.8699999999999961e-01; + const Real yc_true = -7.8699999999999948e-01; + const libMesh::Point centroid_true(xc_true, yc_true); + const libMesh::Point shear_center_true(xs_true, ys_true); + + const libMesh::Point point(4.3, -3.5, -6.7); + const Real time = 8.22; + + SECTION("1D thermal expansion A matrix") + { + /** + * As of Dec. 17, 2019, thermal_expansion_A_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * thermal_expansion_A_matrix to be obtained without any input arguments. + */ + + Real area; + const MAST::FieldFunction& Area = section.A(); + Area(point, time, area); + CHECK( area == Approx(area_true) ); + + std::unique_ptr> texp_A_mat = section.thermal_expansion_A_matrix(); + + const libMesh::Point point(2.3, 3.1, 5.2); + const Real time = 2.34; + RealMatrixX D_sec_texpA; + texp_A_mat->operator()(point, time, D_sec_texpA); + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_texpA_true = RealMatrixX::Zero(2,1); + D_sec_texpA_true(0,0) = E() * alpha() * area_true; + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_texpA); + std::vector truth = eigen_matrix_to_std_vector(D_sec_texpA_true); + + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } + + SECTION("1D thermal expansion B matrix") + { + /** + * As of Dec. 17, 2019, thermal_expansion_B_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * thermal_expansion_B_matrix to be obtained without any input arguments. + */ + + Real first_area_moment_y; + const MAST::FieldFunction& Ay = section.Ay(); + Ay(point, time, first_area_moment_y); + CHECK( first_area_moment_y == Approx(first_area_moment_y_true) ); + + Real first_area_moment_z; + const MAST::FieldFunction& Az = section.Az(); + Az(point, time, first_area_moment_z); + CHECK( first_area_moment_z == Approx(first_area_moment_z_true) ); + + std::unique_ptr> texp_B_mat = section.thermal_expansion_B_matrix(); + + const libMesh::Point point(2.3, 3.1, 5.2); + const Real time = 2.34; + RealMatrixX D_sec_texpB; + texp_B_mat->operator()(point, time, D_sec_texpB); + + libMesh::out << "texp_B_mat =\n" << D_sec_texpB << std::endl; + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_texpB_true = RealMatrixX::Zero(2,1); + D_sec_texpB_true(0,0) = E() * alpha() * first_area_moment_z_true; + D_sec_texpB_true(1,0) = E() * alpha() * first_area_moment_y_true; + + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_texpB); + std::vector truth = eigen_matrix_to_std_vector(D_sec_texpB_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } +} + +// FIXME: I don't think this one is being run. +TEST_CASE("I1_element_property_card_constant_dynamic_1d", + "[dynamic],[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + + // Define Material Properties as MAST Parameters + MAST::Parameter rho("rho_param", 1420.5); // Density + MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity + MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio + MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity + MAST::Parameter k("k_param", 237.0); // Thermal Conductivity + + const Real G = E() / (2. * (1. + nu())); + + // Define Section Properties as MAST Parameters + MAST::Parameter DIM1("DIM1", 3.770); + MAST::Parameter DIM2("DIM2", 0.170); + MAST::Parameter DIM3("DIM3", 5.470); + MAST::Parameter DIM4("DIM4", 5.900); + + MAST::Parameter offset_y("offy_param", -0.787); // Section offset in y-direction + MAST::Parameter offset_z("offz_param", 0.687); // Section offset in z-direction + + // Define Sensitivity Parameters + std::vector sens_params = {&DIM1}; + uint n_s = sens_params.size(); + + // Create field functions to dsitribute these constant parameters throughout the model + // Section Property Field Functions + MAST::ConstantFieldFunction DIM1_f("DIM1", DIM1); + MAST::ConstantFieldFunction DIM2_f("DIM2", DIM2); + MAST::ConstantFieldFunction DIM3_f("DIM3", DIM3); + MAST::ConstantFieldFunction DIM4_f("DIM4", DIM4); + MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); + MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); + // Material Property Field Functions + MAST::ConstantFieldFunction rho_f("rho", rho); + MAST::ConstantFieldFunction E_f("E", E); + MAST::ConstantFieldFunction nu_f("nu", nu); + MAST::ConstantFieldFunction cp_f("cp", cp); + MAST::ConstantFieldFunction k_f("k_th", k); + + // Initialize the material + MAST::IsotropicMaterialPropertyCard material; + + // Add the material property constant field functions to the material card + material.add(rho_f); + material.add(k_f); + material.add(cp_f); + material.add(E_f); + material.add(nu_f); + + // Initialize the section + MAST::Solid1DI1SectionElementPropertyCard section; + + // Add the section property constant field functions to the section card + section.add(DIM1_f); + section.add(DIM2_f); + section.add(DIM3_f); + section.add(DIM4_f); + + section.add(offsety_f); + section.add(offsetz_f); + + // Add the material card to the section card + section.set_material(material); + + // Specify a section orientation point and add it to the section. + RealVectorX orientation = RealVectorX::Zero(3); + orientation(1) = 1.0; + section.y_vector() = orientation; + + // Now initialize the section + section.init(*p_global_init); + + REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional + REQUIRE( section.depends_on(DIM1) ); + REQUIRE( section.depends_on(offset_y) ); + REQUIRE( section.depends_on(offset_z) ); + REQUIRE( section.depends_on(k) ); + REQUIRE( section.depends_on(cp) ); + REQUIRE( section.depends_on(rho) ); + + REQUIRE( section.if_isotropic() ); + + // True values + const Real area_true = 2.6241000000000039e+00; + const Real torsion_constant_true = 3.4912416307463445e-02; + const Real first_area_moment_z_true = -2.0651667000000016e+00; + const Real first_area_moment_y_true = 1.8027567000000015e+00; + const Real second_area_moment_zz_true = 1.7639240550400139e+01; + const Real second_area_moment_yy_true = 3.4324069553999919e+00; + const Real second_area_moment_zy_true = -1.4187695228999926e+00; + const Real second_area_moment_polar_true = 2.1071647505800129e+01; + const Real Izzc_true = 1.6013954357500140e+01; + const Real Iyyc_true = 2.1939131024999914e+00; + const Real Izyc_true = 7.5495165674510645e-15; + const Real Ipc_true = 1.8207867460000131e+01; + const Real warping_constant_true = 1.7690289289249652e+01; + const Real kappa_z_true = 5.4403106725573769e-01; + const Real kappa_y_true = 3.5065087923352467e-01; + const Real xs_true = 6.8699874537432160e-01; + const Real ys_true = -7.8699671905199586e-01; + const Real xst_true = 6.8699874537432160e-01; + const Real yst_true = -7.8699671905199586e-01; + const Real xc_true = 6.8699999999999961e-01; + const Real yc_true = -7.8699999999999948e-01; + const libMesh::Point centroid_true(xc_true, yc_true); + const libMesh::Point shear_center_true(xs_true, ys_true); + + const libMesh::Point point(4.3, -3.5, -6.7); + const Real time = 8.22; + + SECTION("1D section inertia matrix") + { + /** + * As of Dec. 17, 2019, inertia_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * inertia_matrix to be obtained without any input arguments. + */ + std::unique_ptr> inertia_mat = section.inertia_matrix(); + + const libMesh::Point point(2.3, 3.1, 5.2); + const Real time = 2.34; + RealMatrixX D_sec_iner; + inertia_mat->operator()(point, time, D_sec_iner); + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_iner_true = RealMatrixX::Zero(6,6); + + Real area; + const MAST::FieldFunction& Area = section.A(); + Area(point, time, area); + REQUIRE( area == Approx(area_true) ); + D_sec_iner_true(0,0) = D_sec_iner_true(1,1) = D_sec_iner_true(2,2) = area_true; + + Real Ip; + const MAST::FieldFunction& PolarInertia = section.Ip(); + PolarInertia(point, time, Ip); + CHECK( Ip == Approx(second_area_moment_polar_true) ); + D_sec_iner_true(3,3) = second_area_moment_polar_true; + + Real first_area_moment_y; + const MAST::FieldFunction& Ay = section.Ay(); + Ay(point, time, first_area_moment_y); + CHECK( first_area_moment_y == Approx(first_area_moment_y_true) ); + D_sec_iner_true(0,4) = D_sec_iner_true(4,0) = first_area_moment_y_true; + + Real first_area_moment_z; + const MAST::FieldFunction& Az = section.Az(); + Az(point, time, first_area_moment_z); + CHECK( first_area_moment_z == Approx(first_area_moment_z_true) ); + D_sec_iner_true(0,5) = D_sec_iner_true(5,0) = first_area_moment_z_true; + + RealMatrixX I; + const MAST::FieldFunction& Inertias = section.I(); + Inertias(point, time, I); + REQUIRE( I(0,1) == I(1,0) ); + Real Iyy = I(1,1); + Real Izz = I(0,0); + Real Izy = I(0,1); + REQUIRE( Izz == Approx(second_area_moment_zz_true) ); + REQUIRE( Iyy == Approx(second_area_moment_yy_true) ); + REQUIRE( Izy == Approx(second_area_moment_zy_true) ); + + D_sec_iner_true(4,4) = Iyy; + D_sec_iner_true(4,5) = Izy; + D_sec_iner_true(5,4) = Izy; + D_sec_iner_true(5,5) = Izz; + + D_sec_iner_true *= rho(); + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_iner); + std::vector truth = eigen_matrix_to_std_vector(D_sec_iner_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } +} + + +TEST_CASE("I1_element_property_card_constant_structural_1d", + "[structural],[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + + // Define Material Properties as MAST Parameters + MAST::Parameter rho("rho_param", 1420.5); // Density + MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity + MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio + MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity + MAST::Parameter k("k_param", 237.0); // Thermal Conductivity + + const Real G = E() / (2. * (1. + nu())); + + // Define Section Properties as MAST Parameters + MAST::Parameter DIM1("DIM1", 3.770); + MAST::Parameter DIM2("DIM2", 0.170); + MAST::Parameter DIM3("DIM3", 5.470); + MAST::Parameter DIM4("DIM4", 5.900); + + MAST::Parameter offset_y("offy_param", -0.787); // Section offset in y-direction + MAST::Parameter offset_z("offz_param", 0.687); // Section offset in z-direction + + // Define Sensitivity Parameters + std::vector sens_params = {&DIM1}; + uint n_s = sens_params.size(); + + // Create field functions to dsitribute these constant parameters throughout the model + // Section Property Field Functions + MAST::ConstantFieldFunction DIM1_f("DIM1", DIM1); + MAST::ConstantFieldFunction DIM2_f("DIM2", DIM2); + MAST::ConstantFieldFunction DIM3_f("DIM3", DIM3); + MAST::ConstantFieldFunction DIM4_f("DIM4", DIM4); + MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); + MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); + // Material Property Field Functions + MAST::ConstantFieldFunction rho_f("rho", rho); + MAST::ConstantFieldFunction E_f("E", E); + MAST::ConstantFieldFunction nu_f("nu", nu); + MAST::ConstantFieldFunction cp_f("cp", cp); + MAST::ConstantFieldFunction k_f("k_th", k); + + // Initialize the material + MAST::IsotropicMaterialPropertyCard material; + + // Add the material property constant field functions to the material card + material.add(rho_f); + material.add(k_f); + material.add(cp_f); + material.add(E_f); + material.add(nu_f); + + // Initialize the section + MAST::Solid1DI1SectionElementPropertyCard section; + + // Add the section property constant field functions to the section card + section.add(DIM1_f); + section.add(DIM2_f); + section.add(DIM3_f); + section.add(DIM4_f); + + section.add(offsety_f); + section.add(offsetz_f); + + // Add the material card to the section card + section.set_material(material); + + // Specify a section orientation point and add it to the section. + RealVectorX orientation = RealVectorX::Zero(3); + orientation(1) = 1.0; + section.y_vector() = orientation; + + // Now initialize the section + section.init(*p_global_init); + + REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional + REQUIRE( section.depends_on(DIM1) ); + REQUIRE( section.depends_on(offset_y) ); + REQUIRE( section.depends_on(offset_z) ); + REQUIRE( section.depends_on(k) ); + REQUIRE( section.depends_on(cp) ); + REQUIRE( section.depends_on(rho) ); + + REQUIRE( section.if_isotropic() ); + + // True values + const Real area_true = 2.6241000000000039e+00; + const Real torsion_constant_true = 3.4912416307463445e-02; + const Real first_area_moment_z_true = -2.0651667000000016e+00; + const Real first_area_moment_y_true = 1.8027567000000015e+00; + const Real second_area_moment_zz_true = 1.7639240550400139e+01; + const Real second_area_moment_yy_true = 3.4324069553999919e+00; + const Real second_area_moment_zy_true = -1.4187695228999926e+00; + const Real second_area_moment_polar_true = 2.1071647505800129e+01; + const Real Izzc_true = 1.6013954357500140e+01; + const Real Iyyc_true = 2.1939131024999914e+00; + const Real Izyc_true = 7.5495165674510645e-15; + const Real Ipc_true = 1.8207867460000131e+01; + const Real warping_constant_true = 1.7690289289249652e+01; + const Real kappa_z_true = 5.4403106725573769e-01; + const Real kappa_y_true = 3.5065087923352467e-01; + const Real xs_true = 6.8699874537432160e-01; + const Real ys_true = -7.8699671905199586e-01; + const Real xst_true = 6.8699874537432160e-01; + const Real yst_true = -7.8699671905199586e-01; + const Real xc_true = 6.8699999999999961e-01; + const Real yc_true = -7.8699999999999948e-01; + const libMesh::Point centroid_true(xc_true, yc_true); + const libMesh::Point shear_center_true(xs_true, ys_true); + + const libMesh::Point point(4.3, -3.5, -6.7); + const Real time = 8.22; + + SECTION("set_get_bending_model") + { + // NOTE: MAST::DKT and MAST::MINDLIN are not valid options for 1D sections, even though their input is accepted. + section.set_bending_model(MAST::BERNOULLI); + section.set_bending_model(MAST::DEFAULT_BENDING); + section.set_bending_model(MAST::NO_BENDING); + section.set_bending_model(MAST::TIMOSHENKO); + + // TODO: Implement element creation for testing of getting bending_model and checking default + //REQUIRE( section.bending_model() + } + +// SECTION("quadrature_order") +// { +// section.set_bending_model(MAST::MINDLIN); +// REQUIRE( section.extra_quadrature_order(elem) == 0 ); +// +// section.set_bending_model(MAST::DKT); +// REQUIRE( section.extra_quadrature_order(elem) == 2 ); +// } + + SECTION("1D extension stiffness matrix") + { + /** + * As of Dec. 17, 2019, stiffness_A_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * stiffness_A_matrix to be obtained without any input arguments. + */ + Real area; + const MAST::FieldFunction& Area = section.A(); + Area(point, time, area); + REQUIRE( area == Approx(area_true) ); + + Real torsion_constant; + const MAST::FieldFunction& TorsionConstant = section.J(); + TorsionConstant(point, time, torsion_constant); + REQUIRE( torsion_constant == Approx(torsion_constant_true).epsilon(0.05) ); + + std::unique_ptr> extension_stiffness_mat = section.stiffness_A_matrix(); + + const libMesh::Point point(2.3, 3.1, 5.2); + const Real time = 2.34; + RealMatrixX D_sec_ext; + extension_stiffness_mat->operator()(point, time, D_sec_ext); + + libMesh::out << "D_sec_ext\n" << D_sec_ext << std::endl; + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_ext_true = RealMatrixX::Zero(2,2); + D_sec_ext_true(0,0) = E() * area_true; + D_sec_ext_true(1,1) = G * torsion_constant_true; + + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_ext); + std::vector truth = eigen_matrix_to_std_vector(D_sec_ext_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth).epsilon(0.05) ); + } + + + SECTION("1D bending section stiffness matrix") + { + /** + * As of Dec. 17, 2019, stiffness_D_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * stiffness_D_matrix to be obtained without any input arguments. + */ + RealMatrixX I; + const MAST::FieldFunction& Inertias = section.I(); + Inertias(point, time, I); + REQUIRE( I(0,1) == I(1,0) ); + Real Izz = I(0,0); + Real Iyy = I(1,1); + Real Izy = I(0,1); + REQUIRE( Izz == Approx(second_area_moment_zz_true) ); + REQUIRE( Iyy == Approx(second_area_moment_yy_true) ); + REQUIRE( Izy == Approx(second_area_moment_zy_true) ); + + std::unique_ptr> bending_stiffness_mat = section.stiffness_D_matrix(); + + const libMesh::Point point(2.3, 3.1, 5.2); + const Real time = 2.34; + RealMatrixX D_sec_bnd; + bending_stiffness_mat->operator()(point, time, D_sec_bnd); + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_bnd_true = RealMatrixX::Zero(2,2); + D_sec_bnd_true(0,0) = E() * second_area_moment_zz_true; + D_sec_bnd_true(1,1) = E() * second_area_moment_yy_true; + D_sec_bnd_true(0,1) = E() * second_area_moment_zy_true; + D_sec_bnd_true(1,0) = E() * second_area_moment_zy_true; + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_bnd); + std::vector truth = eigen_matrix_to_std_vector(D_sec_bnd_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } + + SECTION("1D extension-bending section stiffness matrix") + { + /** + * As of Dec. 17, 2019, stiffness_B_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * stiffness_B_matrix to be obtained without any input arguments. + */ + Real first_area_moment_y; + const MAST::FieldFunction& Ay = section.Ay(); + Ay(point, time, first_area_moment_y); + CHECK( first_area_moment_y == Approx(first_area_moment_y_true) ); + + Real first_area_moment_z; + const MAST::FieldFunction& Az = section.Az(); + Az(point, time, first_area_moment_z); + CHECK( first_area_moment_z == Approx(first_area_moment_z_true) ); + + std::unique_ptr> bndext_stiffness_mat = section.stiffness_B_matrix(); + + const libMesh::Point point(2.3, 3.1, 5.2); + const Real time = 2.34; + RealMatrixX D_sec_bndext; + bndext_stiffness_mat->operator()(point, time, D_sec_bndext); + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_bndext_true = RealMatrixX::Zero(2,2); + D_sec_bndext_true(0,0) = E() * first_area_moment_z_true; + D_sec_bndext_true(0,1) = E() * first_area_moment_y_true; + // TODO: Add checks for torsion bending coupling when added to MAST. + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_bndext); + std::vector truth = eigen_matrix_to_std_vector(D_sec_bndext_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } + + SECTION("1D transverse shear section stiffness matrix") + { + /** + * As of Dec. 17, 2019, transverse_shear_stiffness_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * transverse_shear_stiffness_matrix to be obtained without any input arguments. + */ + Real area; + const MAST::FieldFunction& Area = section.A(); + Area(point, time, area); + REQUIRE( area == Approx(area_true) ); + + std::unique_ptr> trans_shear_stiffness_mat = section.transverse_shear_stiffness_matrix(); + + const libMesh::Point point(2.3, 3.1, 5.2); + const Real time = 2.34; + RealMatrixX D_sec_shr; + trans_shear_stiffness_mat->operator()(point, time, D_sec_shr); + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_shr_true = RealMatrixX::Zero(2,2); + D_sec_shr_true(0,0) = G*area_true*kappa_z_true; + D_sec_shr_true(1,1) = G*area_true*kappa_y_true; + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_shr); + std::vector truth = eigen_matrix_to_std_vector(D_sec_shr_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth).epsilon(0.005) ); + } + + +// SECTION("1D spring section stiffness matrix") +// { +// /** +// * As of Dec. 17, 2019, spring_stiffness_matrix requires the input of an +// * MAST::ElementBase object, but does not actually use it. To get +// * around requiring the creation of such an object (and therefore +// * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, +// * and MAST::GeomElem objects as well). +// * +// * To remedy this, an additional method was added to MAST which allows +// * transverse_shear_stiffness_matrix to be obtained without any input arguments. +// */ +// std::unique_ptr> spring_stiffness_mat = section.stiffness_S_matrix(); +// +// const libMesh::Point point(2.3, 3.1, 5.2); +// const Real time = 2.34; +// RealMatrixX D_sec_spring; +// spring_stiffness_mat->operator()(point, time, D_sec_spring); +// +// // Hard-coded value of the section's extension stiffness +// // NOTE: Should be all zero's for non-bushing sections +// RealMatrixX D_sec_spring_true = RealMatrixX::Zero(4,6); +// +// // Convert the test and truth Eigen::Matrix objects to std::vector +// // since Catch2 has built in methods to compare vectors +// std::vector test = eigen_matrix_to_std_vector(D_sec_spring); +// std::vector truth = eigen_matrix_to_std_vector(D_sec_spring_true); +// +// // Floating point approximations are diffcult to compare since the +// // values typically aren't exactly equal due to numerical error. +// // Therefore, we use the Approx comparison instead of Equals +// CHECK_THAT( test, Catch::Approx(truth) ); +// } +} diff --git a/tests/property/mast_solid_1d_tube2_section_element_property_card.cpp b/tests/property/mast_solid_1d_tube2_section_element_property_card.cpp new file mode 100644 index 00000000..76998228 --- /dev/null +++ b/tests/property/mast_solid_1d_tube2_section_element_property_card.cpp @@ -0,0 +1,1510 @@ +// Catch2 includes +#include "catch.hpp" + +// libMesh includes +#include "libmesh/point.h" + +// MAST includes +#include "base/parameter.h" +#include "base/constant_field_function.h" +#include "property_cards/isotropic_material_property_card.h" +#include "property_cards/solid_1d_tube2_section_element_property_card.h" + +// Custom includes +#include "test_helpers.h" + +extern libMesh::LibMeshInit* p_global_init; + +#define PI 3.1415926535897932 + + +TEST_CASE("tube2_element_property_card_constant_base_1d", + "[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + + const Real cE = 72.0e9; + const Real cnu = 0.33; + const Real cG = cE / (2.0 * (1.0+cnu) ); + const Real calpha = 5.43e-05; + const Real crho = 1420.5; + const Real ccp = 908.0; + const Real ck = 237.0; + const Real ckappa = 5.3284279639775167e-01; + + const Real coff_y = 0.35; + const Real coff_z = 0.26; + + // Define Material Properties as MAST Parameters + MAST::Parameter E("E_param", cE); // Modulus of Elasticity + MAST::Parameter nu("nu_param", cnu); // Poisson's ratio + MAST::Parameter alpha("alpha_param", calpha); // Coefficient of thermal expansion + MAST::Parameter rho("rho_param", crho); // Density + MAST::Parameter cp("cp_param", ccp); // Specific Heat Capacity + MAST::Parameter k("k_param", ck); // Thermal Conductivity + + // Define Section Properties as MAST Parameters + MAST::Parameter r_o("DIM1", 1.125); // Outer radius + MAST::Parameter tth("DIM2", 0.375); // Inner radius + MAST::Parameter offset_y("offy_param", coff_y); // Section offset in y-direction + MAST::Parameter offset_z("offz_param", coff_z); // Section offset in z-direction + + // Create field functions to dsitribute these constant parameters throughout the model + // Section Property Field Functions + MAST::ConstantFieldFunction DIM1_f("DIM1", r_o); + MAST::ConstantFieldFunction DIM2_f("DIM2", tth); + MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); + MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); + // Material Property Field Functions + MAST::ConstantFieldFunction E_f("E", E); + MAST::ConstantFieldFunction nu_f("nu", nu); + MAST::ConstantFieldFunction alpha_f("alpha_expansion", alpha); + MAST::ConstantFieldFunction rho_f("rho", rho); + MAST::ConstantFieldFunction cp_f("cp", cp); + MAST::ConstantFieldFunction k_f("k_th", k); + + // Initialize the material + MAST::IsotropicMaterialPropertyCard material; + + // Add the material property constant field functions to the material card + material.add(rho_f); + material.add(k_f); + material.add(cp_f); + material.add(E_f); + material.add(nu_f); + material.add(alpha_f); + + // Initialize the section + MAST::Solid1DTube2SectionElementPropertyCard section; + + + // Add the section property constant field functions to the section card + section.add(DIM1_f); + section.add(DIM2_f); + section.add(offsety_f); + section.add(offsetz_f); + + // Add the material card to the section card + section.set_material(material); + + // Specify a section orientation point and add it to the section. + RealVectorX orientation = RealVectorX::Zero(3); + orientation(1) = 1.0; + section.y_vector() = orientation; + + // Now initialize the section + section.init(*p_global_init); + + // True values + const Real ro = r_o(); + const Real ri = ro - tth(); + const Real area_true = PI*(pow(ro,2.0) - pow(ri,2.0)); + const Real first_area_moment_z_true = area_true * coff_y; + const Real first_area_moment_y_true = area_true * coff_z; + const Real Izzc_true = PI*(pow(ro,4.0) - pow(ri,4.0))/4.0; + const Real Iyyc_true = PI*(pow(ro,4.0) - pow(ri,4.0))/4.0; + const Real Izyc_true = 0.0; + const Real Ipc_true = PI*(pow(ro,4.0) - pow(ri,4.0))/2.0; + const Real second_area_moment_zz_true = Izzc_true + area_true * coff_y * coff_y; + const Real second_area_moment_yy_true = Iyyc_true + area_true * coff_z * coff_z; + const Real second_area_moment_zy_true = Izyc_true + area_true * coff_y * coff_z; + const Real second_area_moment_polar_true = second_area_moment_zz_true + second_area_moment_yy_true; + + const Real torsion_constant_true = 2.0184430643017226e+00; + const Real warping_constant_true = 2.7224768298299495e-11; + const Real kappa_z_true = 5.3284267813657360e-01; + const Real kappa_y_true = 5.3284267085782810e-01; + const Real xs_true = coff_z; + const Real ys_true = coff_y; + const Real xc_true = coff_z; + const Real yc_true = coff_y; + + const libMesh::Point point(4.3, -3.5, -6.7); + const Real time = 8.22; + + REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional + REQUIRE( section.depends_on(r_o) ); + REQUIRE( section.depends_on(offset_y) ); + REQUIRE( section.depends_on(tth) ); + REQUIRE( section.depends_on(offset_z) ); + REQUIRE( section.depends_on(k) ); + REQUIRE( section.depends_on(cp) ); + REQUIRE( section.depends_on(rho) ); + REQUIRE( section.if_isotropic() ); + + REQUIRE_FALSE( section.if_diagonal_mass_matrix() ); + + section.set_diagonal_mass_matrix(true); + REQUIRE( section.if_diagonal_mass_matrix() ); +} + + +TEST_CASE("tube2_element_property_card_constant_base_sensitivity_1d", + "[1D],[isotropic],[constant],[property],[sensitivity]") +{ + const uint dim = 1; + + const Real cE = 72.0e9; + const Real cnu = 0.33; + const Real cG = cE / (2.0 * (1.0+cnu) ); + const Real calpha = 5.43e-05; + const Real crho = 1420.5; + const Real ccp = 908.0; + const Real ck = 237.0; + const Real ckappa = 5.3284279639775167e-01; + + const Real coff_y = 0.35; + const Real coff_z = 0.26; + + // Define Material Properties as MAST Parameters + MAST::Parameter E("E_param", cE); // Modulus of Elasticity + MAST::Parameter nu("nu_param", cnu); // Poisson's ratio + MAST::Parameter alpha("alpha_param", calpha); // Coefficient of thermal expansion + MAST::Parameter rho("rho_param", crho); // Density + MAST::Parameter cp("cp_param", ccp); // Specific Heat Capacity + MAST::Parameter k("k_param", ck); // Thermal Conductivity + + // Define Section Properties as MAST Parameters + MAST::Parameter r_o("DIM1", 1.125); // Outer radius + MAST::Parameter tth("DIM2", 0.375); // Inner radius + MAST::Parameter offset_y("offy_param", coff_y); // Section offset in y-direction + MAST::Parameter offset_z("offz_param", coff_z); // Section offset in z-direction + + // Define Sensitivity Parameters + std::vector sens_params = {&r_o, &tth}; + uint n_s = sens_params.size(); + + // Create field functions to dsitribute these constant parameters throughout the model + // Section Property Field Functions + MAST::ConstantFieldFunction DIM1_f("DIM1", r_o); + MAST::ConstantFieldFunction DIM2_f("DIM2", tth); + MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); + MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); + // Material Property Field Functions + MAST::ConstantFieldFunction E_f("E", E); + MAST::ConstantFieldFunction nu_f("nu", nu); + MAST::ConstantFieldFunction alpha_f("alpha_expansion", alpha); + MAST::ConstantFieldFunction rho_f("rho", rho); + MAST::ConstantFieldFunction cp_f("cp", cp); + MAST::ConstantFieldFunction k_f("k_th", k); + + // Initialize the material + MAST::IsotropicMaterialPropertyCard material; + + // Add the material property constant field functions to the material card + material.add(rho_f); + material.add(k_f); + material.add(cp_f); + material.add(E_f); + material.add(nu_f); + material.add(alpha_f); + + // Initialize the section + MAST::Solid1DTube2SectionElementPropertyCard section; + + + // Add the section property constant field functions to the section card + section.add(DIM1_f); + section.add(DIM2_f); + section.add(offsety_f); + section.add(offsetz_f); + + // Add the material card to the section card + section.set_material(material); + + // Specify a section orientation point and add it to the section. + RealVectorX orientation = RealVectorX::Zero(3); + orientation(1) = 1.0; + section.y_vector() = orientation; + + // Now initialize the section + section.init(*p_global_init); + + // True values + const Real ro = r_o(); + const Real ri = ro - tth(); + const Real area_true = PI*(pow(ro,2.0) - pow(ri,2.0)); + const Real first_area_moment_z_true = area_true * coff_y; + const Real first_area_moment_y_true = area_true * coff_z; + const Real Izzc_true = PI*(pow(ro,4.0) - pow(ri,4.0))/4.0; + const Real Iyyc_true = PI*(pow(ro,4.0) - pow(ri,4.0))/4.0; + const Real Izyc_true = 0.0; + const Real Ipc_true = PI*(pow(ro,4.0) - pow(ri,4.0))/2.0; + const Real second_area_moment_zz_true = Izzc_true + area_true * coff_y * coff_y; + const Real second_area_moment_yy_true = Iyyc_true + area_true * coff_z * coff_z; + const Real second_area_moment_zy_true = Izyc_true + area_true * coff_y * coff_z; + const Real second_area_moment_polar_true = second_area_moment_zz_true + second_area_moment_yy_true; + + const Real torsion_constant_true = 2.0184430643017226e+00; + const Real warping_constant_true = 2.7224768298299495e-11; + const Real kappa_z_true = 5.3284267813657360e-01; + const Real kappa_y_true = 5.3284267085782810e-01; + const Real xs_true = coff_z; + const Real ys_true = coff_y; + const Real xc_true = coff_z; + const Real yc_true = coff_y; + + const libMesh::Point point(4.3, -3.5, -6.7); + const Real time = 8.22; + + Real dA_dDIM1, dA_dDIM2; + Real dCz_dDIM1, dCz_dDIM2; + Real dCy_dDIM1, dCy_dDIM2; + Real dQz_dDIM1, dQz_dDIM2; + Real dQy_dDIM1, dQy_dDIM2; + Real dIzz_dDIM1, dIzz_dDIM2; + Real dIyy_dDIM1, dIyy_dDIM2; + Real dIzy_dDIM1, dIzy_dDIM2; + Real dIp_dDIM1, dIp_dDIM2; + Real dIzzc_dDIM1, dIzzc_dDIM2; + Real dIyyc_dDIM1, dIyyc_dDIM2; + Real dIzyc_dDIM1, dIzyc_dDIM2; + Real dIpc_dDIM1, dIpc_dDIM2; + Real dJ_dDIM1, dJ_dDIM2; + Real dxs_dDIM1, dxs_dDIM2; + Real dys_dDIM1, dys_dDIM2; + Real dW_dDIM1, dW_dDIM2; + + Real f_h, f_2h, f_n, f_2n; + RealVectorX fv_h, fv_2h, fv_n, fv_2n; + RealMatrixX fm_h, fm_2h, fm_n, fm_2n; + + const Real delta = 1.220703125e-04; // (np.spacing(1))**(0.25) + + // Area Sensitivity Check + const MAST::FieldFunction& Area = section.A(); + std::vector dA(n_s); + for (uint i=0; i dA_cd(n_s); + for (uint i=0; iname() << " = " << dA[i] << "\tdA_cd = " << dA_cd[i] << std::endl; + REQUIRE(dA[i] == Approx(dA_cd[i])); + } + + + // Centroid Sensitivity Check + std::vector dC(n_s); + for (uint i=0; i dC_cd(n_s); + for (uint i=0; iname() << " = " << dC[i] << "\tdC_cd = " << dC_cd[i] << std::endl; + REQUIRE(dC[i](0) == Approx(dC_cd[i](0)).margin(1.49e-08) ); + REQUIRE(dC[i](1) == Approx(dC_cd[i](1)).margin(1.49e-08) ); + } + + // First Area Moments Sensitivity Check + const MAST::FieldFunction& Area_y = section.Ay(); + std::vector dAy(n_s); + for (uint i=0; i dAy_cd(n_s); + for (uint i=0; iname() << " = " << dAy[i] << "\tdAy_cd = " << dAy_cd[i] << std::endl; + REQUIRE(dAy[i] == Approx(dAy_cd[i])); + } + + + const MAST::FieldFunction& Area_z = section.Az(); + std::vector dAz(n_s); + for (uint i=0; i dAz_cd(n_s); + for (uint i=0; iname() << " = " << dAz[i] << "\tdAz_cd = " << dAz_cd[i] << std::endl; + REQUIRE(dAz[i] == Approx(dAz_cd[i])); + } + + + // Second Area Moments Sensitivity Check + const MAST::FieldFunction& Inertia = section.I(); + std::vector dI(n_s); + for (uint i=0; i dI_cd(n_s); + for (uint i=0; iname() << " =\n" << dI[i] << "\ndI_cd = \n" << dI_cd[i] << std::endl; + + Real dIzz = dI[i](0,0); + Real dIyy = dI[i](1,1); + Real dIyz = dI[i](1,0); + Real dIzy = dI[i](0,1); + + Real dIzz_cd = dI_cd[i](0,0); + Real dIyy_cd = dI_cd[i](1,1); + Real dIyz_cd = dI_cd[i](1,0); + Real dIzy_cd = dI_cd[i](0,1); + + REQUIRE(dIzz == Approx(dIzz_cd)); + REQUIRE(dIyy == Approx(dIyy_cd)); + REQUIRE(dIyz == Approx(dIyz_cd)); + REQUIRE(dIzy == Approx(dIzy_cd)); + REQUIRE(dIyz == dIzy); // symmetry check + } + + + // Second Area Polar Moment Sensitivity Check + const MAST::FieldFunction& PolarInertia = section.Ip(); + std::vector dIp(n_s); + for (uint i=0; i dIp_cd(n_s); + for (uint i=0; iname() << " = " << dIp[i] << "\tdIp_cd = " << dIp_cd[i] << std::endl; + REQUIRE(dIp[i] == Approx(dIp_cd[i])); + } + + +// // Shear Center Sensitivity Check +// std::vector dCs(n_s); +// for (uint i=0; i dCs_cd(n_s); +// for (uint i=0; iname() << " = " << dCs[i] << "\tdCs_cd = " << dCs_cd[i] << std::endl; +// REQUIRE(dCs[i](0) == Approx(dCs_cd[i](0)) ); +// REQUIRE(dCs[i](1) == Approx(dCs_cd[i](1)) ); +// } + + + // Torsion Constant Sensitivity Check + // NOTE: The field function below is not made constant because currently a finite difference is used to calculate sensitivity. + const MAST::FieldFunction& TorsionConstant = section.J(); + std::vector dJ(n_s); + for (uint i=0; i dJ_cd(n_s); + for (uint i=0; iname() << " = " << dJ[i] << "\tdJ_cd = " << dJ_cd[i] << std::endl; + REQUIRE(dJ[i] == Approx(dJ_cd[i]).epsilon(0.1) ); + // NOTE: 10% error margin due to 'exact' sensitivity being calculated using finite difference + } + + + // Shear Coefficient Sensitivity Check + // NOTE: The field function below is not made constant because currently a finite difference is used to calculate sensitivity. + MAST::FieldFunction& Kappa = section.Kap(); + std::vector dK(n_s); + for (uint i=0; i dK_cd(n_s); + for (uint i=0; iname() << " =\n" << dK[i] << "\ndK_cd = \n" << dK_cd[i] << std::endl; + + Real dKzz = dK[i](0,0); + Real dKyy = dK[i](1,1); + Real dKyz = dK[i](1,0); + Real dKzy = dK[i](0,1); + + Real dKzz_cd = dK_cd[i](0,0); + Real dKyy_cd = dK_cd[i](1,1); + Real dKyz_cd = dK_cd[i](1,0); + Real dKzy_cd = dK_cd[i](0,1); + + REQUIRE(dKzz == Approx(dKzz_cd).epsilon(0.1)); + REQUIRE(dKyy == Approx(dKyy_cd).epsilon(0.1)); + //REQUIRE(dKyz == Approx(dKyz_cd).epsilon(0.1)); // Comparison can be hard when this is nearly infinite (~1e+13) + //REQUIRE(dKzy == Approx(dKzy_cd).epsilon(0.1)); // Comparison can be hard when this is nearly infinite (~1e+13) + // NOTE: 10% error margin due to 'exact' sensitivity being calculated using finite difference + REQUIRE(dKyz == dKzy); // symmetry check + } + + + // Warping Constant Sensitivity Check + // NOTE: The field function below is not made constant because currently a finite difference is used to calculate sensitivity. + MAST::FieldFunction& WarpingConstant = section.Gam(); + std::vector dW(n_s); + for (uint i=0; i dW_cd(n_s); + for (uint i=0; iname() << " = " << dW[i] << "\tdW_cd = " << dW_cd[i] << std::endl; + REQUIRE(dW[i] == Approx(dW_cd[i]).epsilon(0.1).margin(1e-07) ); + // NOTE: 10% error margin due to 'exact' sensitivity being calculated using finite difference + } +} + + +TEST_CASE("tube2_element_property_card_constant_heat_transfer_1d", + "[heat_transfer],[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + + const Real cE = 72.0e9; + const Real cnu = 0.33; + const Real cG = cE / (2.0 * (1.0+cnu) ); + const Real calpha = 5.43e-05; + const Real crho = 1420.5; + const Real ccp = 908.0; + const Real ck = 237.0; + const Real ckappa = 5.3284279639775167e-01; + + const Real coff_y = 0.35; + const Real coff_z = 0.26; + + // Define Material Properties as MAST Parameters + MAST::Parameter E("E_param", cE); // Modulus of Elasticity + MAST::Parameter nu("nu_param", cnu); // Poisson's ratio + MAST::Parameter alpha("alpha_param", calpha); // Coefficient of thermal expansion + MAST::Parameter rho("rho_param", crho); // Density + MAST::Parameter cp("cp_param", ccp); // Specific Heat Capacity + MAST::Parameter k("k_param", ck); // Thermal Conductivity + + // Define Section Properties as MAST Parameters + MAST::Parameter r_o("DIM1", 1.125); // Outer radius + MAST::Parameter tth("DIM2", 0.375); // Inner radius + MAST::Parameter offset_y("offy_param", coff_y); // Section offset in y-direction + MAST::Parameter offset_z("offz_param", coff_z); // Section offset in z-direction + + // Create field functions to dsitribute these constant parameters throughout the model + // Section Property Field Functions + MAST::ConstantFieldFunction DIM1_f("DIM1", r_o); + MAST::ConstantFieldFunction DIM2_f("DIM2", tth); + MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); + MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); + // Material Property Field Functions + MAST::ConstantFieldFunction E_f("E", E); + MAST::ConstantFieldFunction nu_f("nu", nu); + MAST::ConstantFieldFunction alpha_f("alpha_expansion", alpha); + MAST::ConstantFieldFunction rho_f("rho", rho); + MAST::ConstantFieldFunction cp_f("cp", cp); + MAST::ConstantFieldFunction k_f("k_th", k); + + // Initialize the material + MAST::IsotropicMaterialPropertyCard material; + + // Add the material property constant field functions to the material card + material.add(rho_f); + material.add(k_f); + material.add(cp_f); + material.add(E_f); + material.add(nu_f); + material.add(alpha_f); + + // Initialize the section + MAST::Solid1DTube2SectionElementPropertyCard section; + + + // Add the section property constant field functions to the section card + section.add(DIM1_f); + section.add(DIM2_f); + section.add(offsety_f); + section.add(offsetz_f); + + // Add the material card to the section card + section.set_material(material); + + // Specify a section orientation point and add it to the section. + RealVectorX orientation = RealVectorX::Zero(3); + orientation(1) = 1.0; + section.y_vector() = orientation; + + // Now initialize the section + section.init(*p_global_init); + + // True values + const Real ro = r_o(); + const Real ri = ro - tth(); + const Real area_true = PI*(pow(ro,2.0) - pow(ri,2.0)); + const Real first_area_moment_z_true = area_true * coff_y; + const Real first_area_moment_y_true = area_true * coff_z; + const Real Izzc_true = PI*(pow(ro,4.0) - pow(ri,4.0))/4.0; + const Real Iyyc_true = PI*(pow(ro,4.0) - pow(ri,4.0))/4.0; + const Real Izyc_true = 0.0; + const Real Ipc_true = PI*(pow(ro,4.0) - pow(ri,4.0))/2.0; + const Real second_area_moment_zz_true = Izzc_true + area_true * coff_y * coff_y; + const Real second_area_moment_yy_true = Iyyc_true + area_true * coff_z * coff_z; + const Real second_area_moment_zy_true = Izyc_true + area_true * coff_y * coff_z; + const Real second_area_moment_polar_true = second_area_moment_zz_true + second_area_moment_yy_true; + + const Real torsion_constant_true = 2.0184430643017226e+00; + const Real warping_constant_true = 2.7224768298299495e-11; + const Real kappa_z_true = 5.3284267813657360e-01; + const Real kappa_y_true = 5.3284267085782810e-01; + const Real xs_true = coff_z; + const Real ys_true = coff_y; + const Real xc_true = coff_z; + const Real yc_true = coff_y; + + const libMesh::Point point(4.3, -3.5, -6.7); + const Real time = 8.22; + + Real area; + const MAST::FieldFunction& Area = section.A(); + Area(point, time, area); + REQUIRE( area == Approx(area_true) ); + + + SECTION("1D section thermal conductance matrix") + { + /** + * As of Dec. 17, 2019, inertia_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * inertia_matrix to be obtained without any input arguments. + */ + std::unique_ptr> conduct_mat = section.thermal_conductance_matrix(); + + RealMatrixX D_sec_conduc; + conduct_mat->operator()(point, time, D_sec_conduc); + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_conduc_true = RealMatrixX::Zero(1,1); + D_sec_conduc_true(0,0) = ck * area_true; + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_conduc); + std::vector truth = eigen_matrix_to_std_vector(D_sec_conduc_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } + + SECTION("1D section thermal capacitance matrix") + { + /** + * As of Dec. 17, 2019, inertia_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * inertia_matrix to be obtained without any input arguments. + */ + std::unique_ptr> capaci_mat = section.thermal_capacitance_matrix(); + + RealMatrixX D_sec_capac; + capaci_mat->operator()(point, time, D_sec_capac); + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_capac_true = RealMatrixX::Zero(1,1); + D_sec_capac_true(0,0) = ccp * crho * area_true; + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_capac); + std::vector truth = eigen_matrix_to_std_vector(D_sec_capac_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } +} + + +TEST_CASE("tube2_element_property_card_constant_thermoelastic_1d", + "[thermoelastic],[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + + const Real cE = 72.0e9; + const Real cnu = 0.33; + const Real cG = cE / (2.0 * (1.0+cnu) ); + const Real calpha = 5.43e-05; + const Real crho = 1420.5; + const Real ccp = 908.0; + const Real ck = 237.0; + const Real ckappa = 5.3284279639775167e-01; + + const Real coff_y = 0.35; + const Real coff_z = 0.26; + + // Define Material Properties as MAST Parameters + MAST::Parameter E("E_param", cE); // Modulus of Elasticity + MAST::Parameter nu("nu_param", cnu); // Poisson's ratio + MAST::Parameter alpha("alpha_param", calpha); // Coefficient of thermal expansion + MAST::Parameter rho("rho_param", crho); // Density + MAST::Parameter cp("cp_param", ccp); // Specific Heat Capacity + MAST::Parameter k("k_param", ck); // Thermal Conductivity + + // Define Section Properties as MAST Parameters + MAST::Parameter r_o("DIM1", 1.125); // Outer radius + MAST::Parameter tth("DIM2", 0.375); // Inner radius + MAST::Parameter offset_y("offy_param", coff_y); // Section offset in y-direction + MAST::Parameter offset_z("offz_param", coff_z); // Section offset in z-direction + + // Create field functions to dsitribute these constant parameters throughout the model + // Section Property Field Functions + MAST::ConstantFieldFunction DIM1_f("DIM1", r_o); + MAST::ConstantFieldFunction DIM2_f("DIM2", tth); + MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); + MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); + // Material Property Field Functions + MAST::ConstantFieldFunction E_f("E", E); + MAST::ConstantFieldFunction nu_f("nu", nu); + MAST::ConstantFieldFunction alpha_f("alpha_expansion", alpha); + MAST::ConstantFieldFunction rho_f("rho", rho); + MAST::ConstantFieldFunction cp_f("cp", cp); + MAST::ConstantFieldFunction k_f("k_th", k); + + // Initialize the material + MAST::IsotropicMaterialPropertyCard material; + + // Add the material property constant field functions to the material card + material.add(rho_f); + material.add(k_f); + material.add(cp_f); + material.add(E_f); + material.add(nu_f); + material.add(alpha_f); + + // Initialize the section + MAST::Solid1DTube2SectionElementPropertyCard section; + + + // Add the section property constant field functions to the section card + section.add(DIM1_f); + section.add(DIM2_f); + section.add(offsety_f); + section.add(offsetz_f); + + // Add the material card to the section card + section.set_material(material); + + // Specify a section orientation point and add it to the section. + RealVectorX orientation = RealVectorX::Zero(3); + orientation(1) = 1.0; + section.y_vector() = orientation; + + // Now initialize the section + section.init(*p_global_init); + + // True values + const Real ro = r_o(); + const Real ri = ro - tth(); + const Real area_true = PI*(pow(ro,2.0) - pow(ri,2.0)); + const Real first_area_moment_z_true = area_true * coff_y; + const Real first_area_moment_y_true = area_true * coff_z; + const Real Izzc_true = PI*(pow(ro,4.0) - pow(ri,4.0))/4.0; + const Real Iyyc_true = PI*(pow(ro,4.0) - pow(ri,4.0))/4.0; + const Real Izyc_true = 0.0; + const Real Ipc_true = PI*(pow(ro,4.0) - pow(ri,4.0))/2.0; + const Real second_area_moment_zz_true = Izzc_true + area_true * coff_y * coff_y; + const Real second_area_moment_yy_true = Iyyc_true + area_true * coff_z * coff_z; + const Real second_area_moment_zy_true = Izyc_true + area_true * coff_y * coff_z; + const Real second_area_moment_polar_true = second_area_moment_zz_true + second_area_moment_yy_true; + + const Real torsion_constant_true = 2.0184430643017226e+00; + const Real warping_constant_true = 2.7224768298299495e-11; + const Real kappa_z_true = 5.3284267813657360e-01; + const Real kappa_y_true = 5.3284267085782810e-01; + const Real xs_true = coff_z; + const Real ys_true = coff_y; + const Real xc_true = coff_z; + const Real yc_true = coff_y; + + const libMesh::Point point(4.3, -3.5, -6.7); + const Real time = 8.22; + + SECTION("1D thermal expansion A matrix") + { + /** + * As of Dec. 17, 2019, thermal_expansion_A_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * thermal_expansion_A_matrix to be obtained without any input arguments. + */ + + Real area; + const MAST::FieldFunction& Area = section.A(); + Area(point, time, area); + CHECK( area == Approx(area_true) ); + + std::unique_ptr> texp_A_mat = section.thermal_expansion_A_matrix(); + + RealMatrixX D_sec_texpA; + texp_A_mat->operator()(point, time, D_sec_texpA); + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_texpA_true = RealMatrixX::Zero(2,1); + D_sec_texpA_true(0,0) = cE * calpha * area_true; + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_texpA); + std::vector truth = eigen_matrix_to_std_vector(D_sec_texpA_true); + + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } + + SECTION("1D thermal expansion B matrix") + { + /** + * As of Dec. 17, 2019, thermal_expansion_B_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * thermal_expansion_B_matrix to be obtained without any input arguments. + */ + + Real first_area_moment_y; + const MAST::FieldFunction& Ay = section.Ay(); + Ay(point, time, first_area_moment_y); + CHECK( first_area_moment_y == Approx(first_area_moment_y_true) ); + + Real first_area_moment_z; + const MAST::FieldFunction& Az = section.Az(); + Az(point, time, first_area_moment_z); + CHECK( first_area_moment_z == Approx(first_area_moment_z_true) ); + + std::unique_ptr> texp_B_mat = section.thermal_expansion_B_matrix(); + + RealMatrixX D_sec_texpB; + texp_B_mat->operator()(point, time, D_sec_texpB); + + libMesh::out << "texp_B_mat =\n" << D_sec_texpB << std::endl; + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_texpB_true = RealMatrixX::Zero(2,1); + D_sec_texpB_true(0,0) = cE * calpha * first_area_moment_z; + D_sec_texpB_true(1,0) = cE * calpha * first_area_moment_y; + + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_texpB); + std::vector truth = eigen_matrix_to_std_vector(D_sec_texpB_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } +} + + +TEST_CASE("tube2_element_property_card_constant_dynamic_1d", + "[dynamic],[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + + const Real cE = 72.0e9; + const Real cnu = 0.33; + const Real cG = cE / (2.0 * (1.0+cnu) ); + const Real calpha = 5.43e-05; + const Real crho = 1420.5; + const Real ccp = 908.0; + const Real ck = 237.0; + const Real ckappa = 5.3284279639775167e-01; + + const Real coff_y = 0.35; + const Real coff_z = 0.26; + + // Define Material Properties as MAST Parameters + MAST::Parameter E("E_param", cE); // Modulus of Elasticity + MAST::Parameter nu("nu_param", cnu); // Poisson's ratio + MAST::Parameter alpha("alpha_param", calpha); // Coefficient of thermal expansion + MAST::Parameter rho("rho_param", crho); // Density + MAST::Parameter cp("cp_param", ccp); // Specific Heat Capacity + MAST::Parameter k("k_param", ck); // Thermal Conductivity + + // Define Section Properties as MAST Parameters + MAST::Parameter r_o("DIM1", 1.125); // Outer radius + MAST::Parameter tth("DIM2", 0.375); // Inner radius + MAST::Parameter offset_y("offy_param", coff_y); // Section offset in y-direction + MAST::Parameter offset_z("offz_param", coff_z); // Section offset in z-direction + + // Create field functions to dsitribute these constant parameters throughout the model + // Section Property Field Functions + MAST::ConstantFieldFunction DIM1_f("DIM1", r_o); + MAST::ConstantFieldFunction DIM2_f("DIM2", tth); + MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); + MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); + // Material Property Field Functions + MAST::ConstantFieldFunction E_f("E", E); + MAST::ConstantFieldFunction nu_f("nu", nu); + MAST::ConstantFieldFunction alpha_f("alpha_expansion", alpha); + MAST::ConstantFieldFunction rho_f("rho", rho); + MAST::ConstantFieldFunction cp_f("cp", cp); + MAST::ConstantFieldFunction k_f("k_th", k); + + // Initialize the material + MAST::IsotropicMaterialPropertyCard material; + + // Add the material property constant field functions to the material card + material.add(rho_f); + material.add(k_f); + material.add(cp_f); + material.add(E_f); + material.add(nu_f); + material.add(alpha_f); + + // Initialize the section + MAST::Solid1DTube2SectionElementPropertyCard section; + + + // Add the section property constant field functions to the section card + section.add(DIM1_f); + section.add(DIM2_f); + section.add(offsety_f); + section.add(offsetz_f); + + // Add the material card to the section card + section.set_material(material); + + // Specify a section orientation point and add it to the section. + RealVectorX orientation = RealVectorX::Zero(3); + orientation(1) = 1.0; + section.y_vector() = orientation; + + // Now initialize the section + section.init(*p_global_init); + + // True values + const Real ro = r_o(); + const Real ri = ro - tth(); + const Real area_true = PI*(pow(ro,2.0) - pow(ri,2.0)); + const Real first_area_moment_z_true = area_true * coff_y; + const Real first_area_moment_y_true = area_true * coff_z; + const Real Izzc_true = PI*(pow(ro,4.0) - pow(ri,4.0))/4.0; + const Real Iyyc_true = PI*(pow(ro,4.0) - pow(ri,4.0))/4.0; + const Real Izyc_true = 0.0; + const Real Ipc_true = PI*(pow(ro,4.0) - pow(ri,4.0))/2.0; + const Real second_area_moment_zz_true = Izzc_true + area_true * coff_y * coff_y; + const Real second_area_moment_yy_true = Iyyc_true + area_true * coff_z * coff_z; + const Real second_area_moment_zy_true = Izyc_true + area_true * coff_y * coff_z; + const Real second_area_moment_polar_true = second_area_moment_zz_true + second_area_moment_yy_true; + + const Real torsion_constant_true = 2.0184430643017226e+00; + const Real warping_constant_true = 2.7224768298299495e-11; + const Real kappa_z_true = 5.3284267813657360e-01; + const Real kappa_y_true = 5.3284267085782810e-01; + const Real xs_true = coff_z; + const Real ys_true = coff_y; + const Real xc_true = coff_z; + const Real yc_true = coff_y; + + const libMesh::Point point(4.3, -3.5, -6.7); + const Real time = 8.22; + + SECTION("1D section inertia matrix") + { + /** + * As of Dec. 17, 2019, inertia_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * inertia_matrix to be obtained without any input arguments. + */ + std::unique_ptr> inertia_mat = section.inertia_matrix(); + + RealMatrixX D_sec_iner; + inertia_mat->operator()(point, time, D_sec_iner); + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_iner_true = RealMatrixX::Zero(6,6); + + + Real area; + const MAST::FieldFunction& Area = section.A(); + Area(point, time, area); + REQUIRE( area == Approx(area_true) ); + D_sec_iner_true(0,0) = D_sec_iner_true(1,1) = D_sec_iner_true(2,2) = area_true; + + Real Ip; + const MAST::FieldFunction& PolarInertia = section.Ip(); + PolarInertia(point, time, Ip); + CHECK( Ip == Approx(second_area_moment_polar_true) ); + D_sec_iner_true(3,3) = second_area_moment_polar_true; + + Real first_area_moment_y; + const MAST::FieldFunction& Ay = section.Ay(); + Ay(point, time, first_area_moment_y); + CHECK( first_area_moment_y == Approx(first_area_moment_y_true) ); + D_sec_iner_true(0,4) = D_sec_iner_true(4,0) = first_area_moment_y_true; + + Real first_area_moment_z; + const MAST::FieldFunction& Az = section.Az(); + Az(point, time, first_area_moment_z); + CHECK( first_area_moment_z == Approx(first_area_moment_z_true) ); + D_sec_iner_true(0,5) = D_sec_iner_true(5,0) = first_area_moment_z_true; + + RealMatrixX I; + const MAST::FieldFunction& Inertias = section.I(); + Inertias(point, time, I); + REQUIRE( I(0,1) == I(1,0) ); + Real Iyy = I(1,1); + Real Izz = I(0,0); + Real Izy = I(0,1); + REQUIRE( Izz == Approx(second_area_moment_zz_true) ); + REQUIRE( Iyy == Approx(second_area_moment_yy_true) ); + REQUIRE( Izy == Approx(second_area_moment_zy_true) ); + + D_sec_iner_true(4,4) = Iyy; // TODO: Should this be Izz? + D_sec_iner_true(4,5) = Izy; + D_sec_iner_true(5,4) = Izy; + D_sec_iner_true(5,5) = Izz; // TODO: Should this be Iyy?? + + D_sec_iner_true *= rho(); + + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_iner); + std::vector truth = eigen_matrix_to_std_vector(D_sec_iner_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } +} + + +TEST_CASE("tube2_element_property_card_constant_structural_1d", + "[structural],[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + + const Real cE = 72.0e9; + const Real cnu = 0.33; + const Real cG = cE / (2.0 * (1.0+cnu) ); + const Real calpha = 5.43e-05; + const Real crho = 1420.5; + const Real ccp = 908.0; + const Real ck = 237.0; + const Real ckappa = 5.3284279639775167e-01; + + const Real coff_y = 0.35; + const Real coff_z = 0.26; + + // Define Material Properties as MAST Parameters + MAST::Parameter E("E_param", cE); // Modulus of Elasticity + MAST::Parameter nu("nu_param", cnu); // Poisson's ratio + MAST::Parameter alpha("alpha_param", calpha); // Coefficient of thermal expansion + MAST::Parameter rho("rho_param", crho); // Density + MAST::Parameter cp("cp_param", ccp); // Specific Heat Capacity + MAST::Parameter k("k_param", ck); // Thermal Conductivity + + // Define Section Properties as MAST Parameters + MAST::Parameter r_o("DIM1", 1.125); // Outer radius + MAST::Parameter tth("DIM2", 0.375); // Inner radius + MAST::Parameter offset_y("offy_param", coff_y); // Section offset in y-direction + MAST::Parameter offset_z("offz_param", coff_z); // Section offset in z-direction + + // Create field functions to dsitribute these constant parameters throughout the model + // Section Property Field Functions + MAST::ConstantFieldFunction DIM1_f("DIM1", r_o); + MAST::ConstantFieldFunction DIM2_f("DIM2", tth); + MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); + MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); + // Material Property Field Functions + MAST::ConstantFieldFunction E_f("E", E); + MAST::ConstantFieldFunction nu_f("nu", nu); + MAST::ConstantFieldFunction alpha_f("alpha_expansion", alpha); + MAST::ConstantFieldFunction rho_f("rho", rho); + MAST::ConstantFieldFunction cp_f("cp", cp); + MAST::ConstantFieldFunction k_f("k_th", k); + + // Initialize the material + MAST::IsotropicMaterialPropertyCard material; + + // Add the material property constant field functions to the material card + material.add(rho_f); + material.add(k_f); + material.add(cp_f); + material.add(E_f); + material.add(nu_f); + material.add(alpha_f); + + // Initialize the section + MAST::Solid1DTube2SectionElementPropertyCard section; + + + // Add the section property constant field functions to the section card + section.add(DIM1_f); + section.add(DIM2_f); + section.add(offsety_f); + section.add(offsetz_f); + + // Add the material card to the section card + section.set_material(material); + + // Specify a section orientation point and add it to the section. + RealVectorX orientation = RealVectorX::Zero(3); + orientation(1) = 1.0; + section.y_vector() = orientation; + + // Now initialize the section + section.init(*p_global_init); + + // True values + const Real ro = r_o(); + const Real ri = ro - tth(); + const Real area_true = PI*(pow(ro,2.0) - pow(ri,2.0)); + const Real first_area_moment_z_true = area_true * coff_y; + const Real first_area_moment_y_true = area_true * coff_z; + const Real Izzc_true = PI*(pow(ro,4.0) - pow(ri,4.0))/4.0; + const Real Iyyc_true = PI*(pow(ro,4.0) - pow(ri,4.0))/4.0; + const Real Izyc_true = 0.0; + const Real Ipc_true = PI*(pow(ro,4.0) - pow(ri,4.0))/2.0; + const Real second_area_moment_zz_true = Izzc_true + area_true * coff_y * coff_y; + const Real second_area_moment_yy_true = Iyyc_true + area_true * coff_z * coff_z; + const Real second_area_moment_zy_true = Izyc_true + area_true * coff_y * coff_z; + const Real second_area_moment_polar_true = second_area_moment_zz_true + second_area_moment_yy_true; + + const Real torsion_constant_true = 2.0184430643017226e+00; + const Real warping_constant_true = 2.7224768298299495e-11; + const Real kappa_z_true = 5.3284267813657360e-01; + const Real kappa_y_true = 5.3284267085782810e-01; + const Real xs_true = coff_z; + const Real ys_true = coff_y; + const Real xc_true = coff_z; + const Real yc_true = coff_y; + + const libMesh::Point point(4.3, -3.5, -6.7); + const Real time = 8.22; + + SECTION("set_get_bending_model") + { + // NOTE: MAST::DKT and MAST::MINDLIN are not valid options for 1D sections, even though their input is accepted. + section.set_bending_model(MAST::BERNOULLI); + section.set_bending_model(MAST::DEFAULT_BENDING); + section.set_bending_model(MAST::NO_BENDING); + section.set_bending_model(MAST::TIMOSHENKO); + + // TODO: Implement element creation for testing of getting bending_model and checking default + //REQUIRE( section.bending_model() + } + +// SECTION("quadrature_order") +// { +// section.set_bending_model(MAST::MINDLIN); +// REQUIRE( section.extra_quadrature_order(elem) == 0 ); +// +// section.set_bending_model(MAST::DKT); +// REQUIRE( section.extra_quadrature_order(elem) == 2 ); +// } + + SECTION("1D extension stiffness matrix") + { + /** + * As of Dec. 17, 2019, stiffness_A_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * stiffness_A_matrix to be obtained without any input arguments. + */ + Real area; + const MAST::FieldFunction& Area = section.A(); + Area(point, time, area); + REQUIRE( area == Approx(area_true) ); + + Real torsion_constant; + const MAST::FieldFunction& TorsionConstant = section.J(); + TorsionConstant(point, time, torsion_constant); + REQUIRE( torsion_constant == Approx(torsion_constant_true).epsilon(0.05) ); + + std::unique_ptr> extension_stiffness_mat = section.stiffness_A_matrix(); + + RealMatrixX D_sec_ext; + extension_stiffness_mat->operator()(point, time, D_sec_ext); + + libMesh::out << "D_sec_ext\n" << D_sec_ext << std::endl; + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_ext_true = RealMatrixX::Zero(2,2); + D_sec_ext_true(0,0) = cE * area_true; + D_sec_ext_true(1,1) = cG * torsion_constant_true; + + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_ext); + std::vector truth = eigen_matrix_to_std_vector(D_sec_ext_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth).epsilon(0.05) ); + } + + + SECTION("1D bending section stiffness matrix") + { + /** + * As of Dec. 17, 2019, stiffness_D_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * stiffness_D_matrix to be obtained without any input arguments. + */ + RealMatrixX I; + const MAST::FieldFunction& Inertias = section.I(); + Inertias(point, time, I); + REQUIRE( I(0,1) == I(1,0) ); + Real Iyy = I(1,1); + Real Izz = I(0,0); + Real Izy = I(0,1); + REQUIRE( Izz == Approx(second_area_moment_zz_true) ); + REQUIRE( Iyy == Approx(second_area_moment_yy_true) ); + REQUIRE( Izy == Approx(second_area_moment_zy_true) ); + + std::unique_ptr> bending_stiffness_mat = section.stiffness_D_matrix(); + + RealMatrixX D_sec_bnd; + bending_stiffness_mat->operator()(point, time, D_sec_bnd); + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_bnd_true = RealMatrixX::Zero(2,2); + D_sec_bnd_true(0,0) = cE * second_area_moment_zz_true; + D_sec_bnd_true(1,1) = cE * second_area_moment_yy_true; + D_sec_bnd_true(0,1) = cE * second_area_moment_zy_true; + D_sec_bnd_true(1,0) = cE * second_area_moment_zy_true; + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_bnd); + std::vector truth = eigen_matrix_to_std_vector(D_sec_bnd_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } + + SECTION("1D extension-bending section stiffness matrix") + { + /** + * As of Dec. 17, 2019, stiffness_B_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * stiffness_B_matrix to be obtained without any input arguments. + */ + Real first_area_moment_y; + const MAST::FieldFunction& Ay = section.Ay(); + Ay(point, time, first_area_moment_y); + CHECK( first_area_moment_y == Approx(first_area_moment_y_true) ); + + Real first_area_moment_z; + const MAST::FieldFunction& Az = section.Az(); + Az(point, time, first_area_moment_z); + CHECK( first_area_moment_z == Approx(first_area_moment_z_true) ); + + std::unique_ptr> bndext_stiffness_mat = section.stiffness_B_matrix(); + + RealMatrixX D_sec_bndext; + bndext_stiffness_mat->operator()(point, time, D_sec_bndext); + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_bndext_true = RealMatrixX::Zero(2,2); + D_sec_bndext_true(0,0) = cE * first_area_moment_z_true; + D_sec_bndext_true(0,1) = cE * first_area_moment_y_true; + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_bndext); + std::vector truth = eigen_matrix_to_std_vector(D_sec_bndext_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } + + SECTION("1D transverse shear section stiffness matrix") + { + /** + * As of Dec. 17, 2019, transverse_shear_stiffness_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * transverse_shear_stiffness_matrix to be obtained without any input arguments. + */ + Real area; + const MAST::FieldFunction& Area = section.A(); + Area(point, time, area); + REQUIRE( area == Approx(area_true) ); + + std::unique_ptr> trans_shear_stiffness_mat = section.transverse_shear_stiffness_matrix(); + + RealMatrixX D_sec_shr; + trans_shear_stiffness_mat->operator()(point, time, D_sec_shr); + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_shr_true = RealMatrixX::Zero(2,2); + D_sec_shr_true(0,0) = cG * kappa_z_true * area_true; + D_sec_shr_true(1,1) = cG * kappa_y_true * area_true; + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_shr); + std::vector truth = eigen_matrix_to_std_vector(D_sec_shr_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth).epsilon(0.01) ); + } + + +// SECTION("1D spring section stiffness matrix") +// { +// /** +// * As of Dec. 17, 2019, spring_stiffness_matrix requires the input of an +// * MAST::ElementBase object, but does not actually use it. To get +// * around requiring the creation of such an object (and therefore +// * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, +// * and MAST::GeomElem objects as well). +// * +// * To remedy this, an additional method was added to MAST which allows +// * transverse_shear_stiffness_matrix to be obtained without any input arguments. +// */ +// std::unique_ptr> spring_stiffness_mat = section.stiffness_S_matrix(); +// +// RealMatrixX D_sec_spring; +// spring_stiffness_mat->operator()(point, time, D_sec_spring); +// +// // Hard-coded value of the section's extension stiffness +// // NOTE: Should be all zero's for non-bushing sections +// RealMatrixX D_sec_spring_true = RealMatrixX::Zero(4,6); +// +// // Convert the test and truth Eigen::Matrix objects to std::vector +// // since Catch2 has built in methods to compare vectors +// std::vector test = eigen_matrix_to_std_vector(D_sec_spring); +// std::vector truth = eigen_matrix_to_std_vector(D_sec_spring_true); +// +// // Floating point approximations are diffcult to compare since the +// // values typically aren't exactly equal due to numerical error. +// // Therefore, we use the Approx comparison instead of Equals +// CHECK_THAT( test, Catch::Approx(truth) ); +// } +} diff --git a/tests/property/mast_solid_1d_tube_section_element_property_card.cpp b/tests/property/mast_solid_1d_tube_section_element_property_card.cpp index ba5f02cf..72a44e25 100644 --- a/tests/property/mast_solid_1d_tube_section_element_property_card.cpp +++ b/tests/property/mast_solid_1d_tube_section_element_property_card.cpp @@ -139,6 +139,494 @@ TEST_CASE("tube_element_property_card_constant_base_1d", } +TEST_CASE("tube_element_property_card_constant_base_sensitivity_1d", + "[1D],[isotropic],[constant],[property],[sensitivity]") +{ + const uint dim = 1; + + const Real cE = 72.0e9; + const Real cnu = 0.33; + const Real cG = cE / (2.0 * (1.0+cnu) ); + const Real calpha = 5.43e-05; + const Real crho = 1420.5; + const Real ccp = 908.0; + const Real ck = 237.0; + const Real ckappa = 5.3284279639775167e-01; + + const Real coff_y = 0.35; + const Real coff_z = 0.26; + + // Define Material Properties as MAST Parameters + MAST::Parameter E("E_param", cE); // Modulus of Elasticity + MAST::Parameter nu("nu_param", cnu); // Poisson's ratio + MAST::Parameter alpha("alpha_param", calpha); // Coefficient of thermal expansion + MAST::Parameter rho("rho_param", crho); // Density + MAST::Parameter cp("cp_param", ccp); // Specific Heat Capacity + MAST::Parameter k("k_param", ck); // Thermal Conductivity + + // Define Section Properties as MAST Parameters + MAST::Parameter r_o("DIM1", 1.125); // Outer radius + MAST::Parameter r_i("DIM2", 0.750); // Inner radius + MAST::Parameter offset_y("offy_param", coff_y); // Section offset in y-direction + MAST::Parameter offset_z("offz_param", coff_z); // Section offset in z-direction + + // Define Sensitivity Parameters + std::vector sens_params = {&r_o, &r_i}; + uint n_s = sens_params.size(); + + // Create field functions to dsitribute these constant parameters throughout the model + // Section Property Field Functions + MAST::ConstantFieldFunction DIM1_f("DIM1", r_o); + MAST::ConstantFieldFunction DIM2_f("DIM2", r_i); + MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); + MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); + // Material Property Field Functions + MAST::ConstantFieldFunction E_f("E", E); + MAST::ConstantFieldFunction nu_f("nu", nu); + MAST::ConstantFieldFunction alpha_f("alpha_expansion", alpha); + MAST::ConstantFieldFunction rho_f("rho", rho); + MAST::ConstantFieldFunction cp_f("cp", cp); + MAST::ConstantFieldFunction k_f("k_th", k); + + // Initialize the material + MAST::IsotropicMaterialPropertyCard material; + + // Add the material property constant field functions to the material card + material.add(rho_f); + material.add(k_f); + material.add(cp_f); + material.add(E_f); + material.add(nu_f); + material.add(alpha_f); + + // Initialize the section + MAST::Solid1DTubeSectionElementPropertyCard section; + + + // Add the section property constant field functions to the section card + section.add(DIM1_f); + section.add(DIM2_f); + section.add(offsety_f); + section.add(offsetz_f); + + // Add the material card to the section card + section.set_material(material); + + // Specify a section orientation point and add it to the section. + RealVectorX orientation = RealVectorX::Zero(3); + orientation(1) = 1.0; + section.y_vector() = orientation; + + // Now initialize the section + section.init(*p_global_init); + + // True values + const Real ro = r_o(); + const Real ri = r_i(); + const Real area_true = PI*(pow(ro,2.0) - pow(ri,2.0)); + const Real first_area_moment_z_true = area_true * coff_y; + const Real first_area_moment_y_true = area_true * coff_z; + const Real Izzc_true = PI*(pow(ro,4.0) - pow(ri,4.0))/4.0; + const Real Iyyc_true = PI*(pow(ro,4.0) - pow(ri,4.0))/4.0; + const Real Izyc_true = 0.0; + const Real Ipc_true = PI*(pow(ro,4.0) - pow(ri,4.0))/2.0; + const Real second_area_moment_zz_true = Izzc_true + area_true * coff_y * coff_y; + const Real second_area_moment_yy_true = Iyyc_true + area_true * coff_z * coff_z; + const Real second_area_moment_zy_true = Izyc_true + area_true * coff_y * coff_z; + const Real second_area_moment_polar_true = second_area_moment_zz_true + second_area_moment_yy_true; + + const Real torsion_constant_true = 2.0184430643017226e+00; + const Real warping_constant_true = 2.7224768298299495e-11; + const Real kappa_z_true = 5.3284267813657360e-01; + const Real kappa_y_true = 5.3284267085782810e-01; + const Real xs_true = coff_z; + const Real ys_true = coff_y; + const Real xc_true = coff_z; + const Real yc_true = coff_y; + + const libMesh::Point point(4.3, -3.5, -6.7); + const Real time = 8.22; + + Real dA_dDIM1, dA_dDIM2; + Real dCz_dDIM1, dCz_dDIM2; + Real dCy_dDIM1, dCy_dDIM2; + Real dQz_dDIM1, dQz_dDIM2; + Real dQy_dDIM1, dQy_dDIM2; + Real dIzz_dDIM1, dIzz_dDIM2; + Real dIyy_dDIM1, dIyy_dDIM2; + Real dIzy_dDIM1, dIzy_dDIM2; + Real dIp_dDIM1, dIp_dDIM2; + Real dIzzc_dDIM1, dIzzc_dDIM2; + Real dIyyc_dDIM1, dIyyc_dDIM2; + Real dIzyc_dDIM1, dIzyc_dDIM2; + Real dIpc_dDIM1, dIpc_dDIM2; + Real dJ_dDIM1, dJ_dDIM2; + Real dxs_dDIM1, dxs_dDIM2; + Real dys_dDIM1, dys_dDIM2; + Real dW_dDIM1, dW_dDIM2; + + Real f_h, f_2h, f_n, f_2n; + RealVectorX fv_h, fv_2h, fv_n, fv_2n; + RealMatrixX fm_h, fm_2h, fm_n, fm_2n; + + const Real delta = 1.220703125e-04; // (np.spacing(1))**(0.25) + + // Area Sensitivity Check + const MAST::FieldFunction& Area = section.A(); + std::vector dA(n_s); + for (uint i=0; i dA_cd(n_s); + for (uint i=0; iname() << " = " << dA[i] << "\tdA_cd = " << dA_cd[i] << std::endl; + REQUIRE(dA[i] == Approx(dA_cd[i])); + } + + + // Centroid Sensitivity Check + std::vector dC(n_s); + for (uint i=0; i dC_cd(n_s); + for (uint i=0; iname() << " = " << dC[i] << "\tdC_cd = " << dC_cd[i] << std::endl; + REQUIRE(dC[i](0) == Approx(dC_cd[i](0)).margin(1.49e-08) ); + REQUIRE(dC[i](1) == Approx(dC_cd[i](1)).margin(1.49e-08) ); + } + + // First Area Moments Sensitivity Check + const MAST::FieldFunction& Area_y = section.Ay(); + std::vector dAy(n_s); + for (uint i=0; i dAy_cd(n_s); + for (uint i=0; iname() << " = " << dAy[i] << "\tdAy_cd = " << dAy_cd[i] << std::endl; + REQUIRE(dAy[i] == Approx(dAy_cd[i])); + } + + + const MAST::FieldFunction& Area_z = section.Az(); + std::vector dAz(n_s); + for (uint i=0; i dAz_cd(n_s); + for (uint i=0; iname() << " = " << dAz[i] << "\tdAz_cd = " << dAz_cd[i] << std::endl; + REQUIRE(dAz[i] == Approx(dAz_cd[i])); + } + + + // Second Area Moments Sensitivity Check + const MAST::FieldFunction& Inertia = section.I(); + std::vector dI(n_s); + for (uint i=0; i dI_cd(n_s); + for (uint i=0; iname() << " =\n" << dI[i] << "\ndI_cd = \n" << dI_cd[i] << std::endl; + + Real dIzz = dI[i](0,0); + Real dIyy = dI[i](1,1); + Real dIyz = dI[i](1,0); + Real dIzy = dI[i](0,1); + + Real dIzz_cd = dI_cd[i](0,0); + Real dIyy_cd = dI_cd[i](1,1); + Real dIyz_cd = dI_cd[i](1,0); + Real dIzy_cd = dI_cd[i](0,1); + + REQUIRE(dIzz == Approx(dIzz_cd)); + REQUIRE(dIyy == Approx(dIyy_cd)); + REQUIRE(dIyz == Approx(dIyz_cd)); + REQUIRE(dIzy == Approx(dIzy_cd)); + REQUIRE(dIyz == dIzy); // symmetry check + } + + + // Second Area Polar Moment Sensitivity Check + const MAST::FieldFunction& PolarInertia = section.Ip(); + std::vector dIp(n_s); + for (uint i=0; i dIp_cd(n_s); + for (uint i=0; iname() << " = " << dIp[i] << "\tdIp_cd = " << dIp_cd[i] << std::endl; + REQUIRE(dIp[i] == Approx(dIp_cd[i])); + } + + +// // Shear Center Sensitivity Check +// std::vector dCs(n_s); +// for (uint i=0; i dCs_cd(n_s); +// for (uint i=0; iname() << " = " << dCs[i] << "\tdCs_cd = " << dCs_cd[i] << std::endl; +// REQUIRE(dCs[i](0) == Approx(dCs_cd[i](0)) ); +// REQUIRE(dCs[i](1) == Approx(dCs_cd[i](1)) ); +// } + + + // Torsion Constant Sensitivity Check + // NOTE: The field function below is not made constant because currently a finite difference is used to calculate sensitivity. + const MAST::FieldFunction& TorsionConstant = section.J(); + std::vector dJ(n_s); + for (uint i=0; i dJ_cd(n_s); + for (uint i=0; iname() << " = " << dJ[i] << "\tdJ_cd = " << dJ_cd[i] << std::endl; + REQUIRE(dJ[i] == Approx(dJ_cd[i]).epsilon(0.1) ); + // NOTE: 10% error margin due to 'exact' sensitivity being calculated using finite difference + } + + + // Shear Coefficient Sensitivity Check + // NOTE: The field function below is not made constant because currently a finite difference is used to calculate sensitivity. + MAST::FieldFunction& Kappa = section.Kap(); + std::vector dK(n_s); + for (uint i=0; i dK_cd(n_s); + for (uint i=0; iname() << " =\n" << dK[i] << "\ndK_cd = \n" << dK_cd[i] << std::endl; + + Real dKzz = dK[i](0,0); + Real dKyy = dK[i](1,1); + Real dKyz = dK[i](1,0); + Real dKzy = dK[i](0,1); + + Real dKzz_cd = dK_cd[i](0,0); + Real dKyy_cd = dK_cd[i](1,1); + Real dKyz_cd = dK_cd[i](1,0); + Real dKzy_cd = dK_cd[i](0,1); + + REQUIRE(dKzz == Approx(dKzz_cd).epsilon(0.1)); + REQUIRE(dKyy == Approx(dKyy_cd).epsilon(0.1)); + //REQUIRE(dKyz == Approx(dKyz_cd).epsilon(0.1)); // Comparison can be hard when this is nearly infinite (~1e+13) + //REQUIRE(dKzy == Approx(dKzy_cd).epsilon(0.1)); // Comparison can be hard when this is nearly infinite (~1e+13) + // NOTE: 10% error margin due to 'exact' sensitivity being calculated using finite difference + REQUIRE(dKyz == dKzy); // symmetry check + } + + + // Warping Constant Sensitivity Check + // NOTE: The field function below is not made constant because currently a finite difference is used to calculate sensitivity. + MAST::FieldFunction& WarpingConstant = section.Gam(); + std::vector dW(n_s); + for (uint i=0; i dW_cd(n_s); + for (uint i=0; iname() << " = " << dW[i] << "\tdW_cd = " << dW_cd[i] << std::endl; + REQUIRE(dW[i] == Approx(dW_cd[i]).epsilon(0.1).margin(1e-07) ); + // NOTE: 10% error margin due to 'exact' sensitivity being calculated using finite difference + } +} + + TEST_CASE("tube_element_property_card_constant_heat_transfer_1d", "[heat_transfer],[1D],[isotropic],[constant],[property]") { From 15f4c774d15adcff4c4c84740fa971dd15a62c3d Mon Sep 17 00:00:00 2001 From: David John Neiferd <13425967+JohnDN90@users.noreply.github.com> Date: Tue, 25 Feb 2020 11:43:54 -0500 Subject: [PATCH 10/27] Added example demonstrating calculation of cross sectional properties and derivatives. --- examples/structural/CMakeLists.txt | 1 + examples/structural/example_9/CMakeLists.txt | 22 +++ examples/structural/example_9/example_9.cpp | 195 +++++++++++++++++++ 3 files changed, 218 insertions(+) create mode 100644 examples/structural/example_9/CMakeLists.txt create mode 100644 examples/structural/example_9/example_9.cpp diff --git a/examples/structural/CMakeLists.txt b/examples/structural/CMakeLists.txt index ece23aa2..8f3d71e9 100644 --- a/examples/structural/CMakeLists.txt +++ b/examples/structural/CMakeLists.txt @@ -6,3 +6,4 @@ add_subdirectory(example_5) # topology optimization add_subdirectory(example_6) # SIMP topology optimization add_subdirectory(example_7) # NastranIO input for Nastran BDF mesh add_subdirectory(example_8) # Homogenized level-set topology optimization +add_subdirectory(example_9) # Cross section property analysis diff --git a/examples/structural/example_9/CMakeLists.txt b/examples/structural/example_9/CMakeLists.txt new file mode 100644 index 00000000..c9cb941c --- /dev/null +++ b/examples/structural/example_9/CMakeLists.txt @@ -0,0 +1,22 @@ +add_executable(structural_example_9 + example_9.cpp) + +target_link_libraries(structural_example_9 mast) + +install(TARGETS structural_example_9 + RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/examples) + +# Test on single processor, PETSc built-in LU direct linear solver (sequential). +add_test(NAME structural_example_9 + COMMAND $ -ksp_type preonly -pc_type lu -options_view) +set_tests_properties(structural_example_9 + PROPERTIES + LABELS "SEQ") + +# Test multiple processors, parallel direct solver using external MUMPS package. +add_test(NAME structural_example_9_mpi + COMMAND ${MPIEXEC_EXECUTABLE} -np 2 $ + -ksp_type preonly -pc_type lu -pc_factor_mat_solver_package mumps -options_view) +set_tests_properties(structural_example_9_mpi + PROPERTIES + LABELS "MPI") diff --git a/examples/structural/example_9/example_9.cpp b/examples/structural/example_9/example_9.cpp new file mode 100644 index 00000000..78ee74d4 --- /dev/null +++ b/examples/structural/example_9/example_9.cpp @@ -0,0 +1,195 @@ +// C/C++ Includes +#include + +// libMesh Includes +#include "libmesh/libmesh.h" +#include "libmesh/replicated_mesh.h" +#include "libmesh/mesh_generation.h" +#include "libmesh/point.h" +#include "libmesh/edge_edge2.h" +#include "libmesh/equation_systems.h" +#include "libmesh/exodusII_io.h" + +// MAST Includes +#include "base/nonlinear_system.h" +#include "elasticity/structural_system_initialization.h" +#include "base/physics_discipline_base.h" +#include "boundary_condition/dirichlet_boundary_condition.h" +#include "base/parameter.h" +#include "base/constant_field_function.h" +#include "property_cards/isotropic_material_property_card.h" +#include "property_cards/solid_1d_section_element_property_card.h" +#include "base/nonlinear_implicit_assembly.h" +#include "elasticity/structural_nonlinear_assembly.h" + +#include "elasticity/structural_buckling_eigenproblem_assembly.h" +#include "elasticity/structural_buckling_eigenproblem_elem_operations.h" +#include "solver/slepc_eigen_solver.h" +#include + +#include "property_cards/solid_1d_bar_section_element_property_card.h" + +#include "property_cards/cross_section_property_pilkey.h" + +#include "libfort/fort.hpp" + + +// This is the main function which runs when the compiled code is called. +int main(int argc, const char** argv) +{ + // Initialize llibMesh Library + libMesh::LibMeshInit init(argc, argv); + + const uint dim = 1; + + // Define Material Properties as MAST Parameters + MAST::Parameter rho("rho_param", 1420.5); // Density + MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity + MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio + MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity + MAST::Parameter k("k_param", 237.0); // Thermal Conductivity + + const Real G = E() / (2. * (1. + nu())); + + // Define Section Properties as MAST Parameters + MAST::Parameter DIM1("DIM1", 3.234); + MAST::Parameter DIM2("DIM2", 1.422); + MAST::Parameter offset_y("offy_param", 0.587); // Section offset in y-direction + MAST::Parameter offset_z("offz_param", -1.054); // Section offset in z-direction + + // Define Sensitivity Parameters + std::vector sens_params = {&DIM1, &DIM2}; + uint n_s = sens_params.size(); + + // Create field functions to dsitribute these constant parameters throughout the model + // Section Property Field Functions + MAST::ConstantFieldFunction DIM1_f("DIM1", DIM1); + MAST::ConstantFieldFunction DIM2_f("DIM2", DIM2); + MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); + MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); + // Material Property Field Functions + MAST::ConstantFieldFunction rho_f("rho", rho); + MAST::ConstantFieldFunction E_f("E", E); + MAST::ConstantFieldFunction nu_f("nu", nu); + MAST::ConstantFieldFunction cp_f("cp", cp); + MAST::ConstantFieldFunction k_f("k_th", k); + + // Initialize the material + MAST::IsotropicMaterialPropertyCard material; + + // Add the material property constant field functions to the material card + material.add(rho_f); + material.add(k_f); + material.add(cp_f); + material.add(E_f); + material.add(nu_f); + + // Initialize the section + MAST::Solid1DBarSectionElementPropertyCard section; + + // Add the section property constant field functions to the section card + section.add(DIM1_f); + section.add(DIM2_f); + section.add(offsety_f); + section.add(offsetz_f); + + // Add the material card to the section card + section.set_material(material); + + // Specify a section orientation point and add it to the section. + RealVectorX orientation = RealVectorX::Zero(3); + orientation(1) = 1.0; + section.y_vector() = orientation; + + // Now initialize the section + section.init(init); + + const libMesh::Point point(4.3, -3.5, -6.7); + const Real time = 8.22; + + // Setup the table for section property console output + fort::table properties_out; + properties_out << fort::header << "Name" << "Property" << "Value" << fort::endr; + + fort::table dproperties_out; + dproperties_out << fort::header << "Property" << "Value" << fort::endr; + + // Get Area + const MAST::FieldFunction& Area = section.A(); + Real A, dA; + Area(point, time, A); + Area.derivative(DIM1, point, time, dA); + properties_out << "Area" << "A" << std::to_string(A) << fort::endr; + dproperties_out << "dA" << std::to_string(dA) << fort::endr; + + // Get Second Area Moments + const MAST::FieldFunction& SecondAreaMoments = section.I(); + Real Izz, Iyy, Izy; + RealMatrixX I, dI; + SecondAreaMoments(point, time, I); + SecondAreaMoments.derivative(DIM1, point, time, dI); + Izz = I(0,0); + Iyy = I(1,1); + Izy = I(0,1); + properties_out << "Inertia" << "I_zz" << std::to_string(Izz) << fort::endr; + properties_out << "Inertia" << "I_yy" << std::to_string(Iyy) << fort::endr; + properties_out << "Inertia" << "I_zy" << std::to_string(Izy) << fort::endr; + dproperties_out << "dI_zz" << std::to_string(dI(0,0)) << fort::endr; + dproperties_out << "dI_yy" << std::to_string(dI(1,1)) << fort::endr; + dproperties_out << "dI_zy" << std::to_string(dI(0,1)) << fort::endr; + + // Get Second Area Polar Moment + const MAST::FieldFunction& PolarInteria = section.Ip(); + Real Ip, dIp; + PolarInteria(point, time, Ip); + PolarInteria.derivative(DIM1, point, time, dIp); + properties_out << "Polar Inertia" << "I_xx" << std::to_string(Ip) << fort::endr; + dproperties_out << "dI_xx" << std::to_string(dIp) << fort::endr; + + // Get Torsion Constant + MAST::FieldFunction& TorsionConstant = section.J(); + Real J, dJ; + TorsionConstant(point, time, J); + TorsionConstant.derivative(DIM1, point, time, dJ); + properties_out << "Torsion Constant" << "J" << std::to_string(J) << fort::endr; + dproperties_out << "dJ" << std::to_string(dJ) << fort::endr; + + // Get first area moments + const MAST::FieldFunction& AreaMomentY = section.Ay(); + const MAST::FieldFunction& AreaMomentZ = section.Az(); + Real Az, Ay, dAy, dAz; + AreaMomentY(point, time, Ay); + AreaMomentY.derivative(DIM1, point, time, dAy); + AreaMomentZ(point, time, Az); + AreaMomentZ.derivative(DIM1, point, time, dAz); + properties_out << "First Area Moment" << "A_z" << std::to_string(Ay) << fort::endr; + dproperties_out << "dA_z" << std::to_string(dAz) << fort::endr; + properties_out << "First Area Moment" << "A_y" << std::to_string(Az) << fort::endr; + dproperties_out << "dA_y" << std::to_string(dAy) << fort::endr; + + // Shear Coefficeints + MAST::FieldFunction& ShearCoefficients = section.Kap(); + RealMatrixX Kappa, dKappa; + ShearCoefficients(point, time, Kappa); + ShearCoefficients.derivative(DIM1, point, time, dKappa); + properties_out << "Shear Coefficient" << "kappa_zz" << std::to_string(Kappa(0,0)) << fort::endr; + properties_out << "Shear Coefficient" << "kappa_yy" << std::to_string(Kappa(1,1)) << fort::endr; + properties_out << "Shear Coefficient" << "kappa_zy" << std::to_string(Kappa(0,1)) << fort::endr; + dproperties_out << "dkappa_zz" << std::to_string(dKappa(0,0)) << fort::endr; + dproperties_out << "dkappa_yy" << std::to_string(dKappa(1,1)) << fort::endr; + dproperties_out << "dkappa_zy" << std::to_string(dKappa(0,1)) << fort::endr; + + // Get warping constant + MAST::FieldFunction& WarpingConstant = section.Gam(); + Real W, dW; + WarpingConstant(point, time, W); + WarpingConstant.derivative(DIM1, point, time, dW); + properties_out << "Warping Constant" << "W" << std::to_string(W) << fort::endr; + dproperties_out << "dW" << std::to_string(dW) << fort::endr; + + libMesh::out << "\nProperty Values:\n" << properties_out.to_string() << std::endl; + + libMesh::out << "Property Derivative w.r.t. DIM1\n" << dproperties_out.to_string() << std::endl; + + return 0; +} From 932cace795ec205862b82ccbaec646e091686f58 Mon Sep 17 00:00:00 2001 From: David John Neiferd <13425967+JohnDN90@users.noreply.github.com> Date: Wed, 4 Mar 2020 10:40:43 -0500 Subject: [PATCH 11/27] Fixed multiple bugs in cross sectional property analysis. Fixed bug which resulted in errors when run with MPI. Fixed bug which resulted in 1 extra (unused) DOF was added to global system. --- examples/structural/example_9/example_9.cpp | 31 ++-- src/base/warping_assembly.cpp | 140 ++++++++++++------ src/base/warping_assembly.h | 6 +- .../warping_system_initialization.cpp | 2 +- .../cross_section_property_pilkey.cpp | 31 +++- ...d_1d_bar_section_element_property_card.cpp | 8 +- ...lid_1d_bar_section_element_property_card.h | 4 +- 7 files changed, 150 insertions(+), 72 deletions(-) diff --git a/examples/structural/example_9/example_9.cpp b/examples/structural/example_9/example_9.cpp index 78ee74d4..dd7b2058 100644 --- a/examples/structural/example_9/example_9.cpp +++ b/examples/structural/example_9/example_9.cpp @@ -40,16 +40,18 @@ int main(int argc, const char** argv) // Initialize llibMesh Library libMesh::LibMeshInit init(argc, argv); - const uint dim = 1; + // The target number of elements to be used in the mesh of the cross + // section. The section is meshed with triangle which only allows you to + // specified a desired area for an individual element and not a number of + // elements, so the number of elements in the section mesh won't match this + // exactly. + const uint n_target_elements = 3000; // Define Material Properties as MAST Parameters - MAST::Parameter rho("rho_param", 1420.5); // Density - MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity + // For a cross section property analysis, only Poisson's ratio is required, + // although this could change if a cross section has different properties + // throughout the section (i.e. a composite section). MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio - MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity - MAST::Parameter k("k_param", 237.0); // Thermal Conductivity - - const Real G = E() / (2. * (1. + nu())); // Define Section Properties as MAST Parameters MAST::Parameter DIM1("DIM1", 3.234); @@ -68,20 +70,12 @@ int main(int argc, const char** argv) MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); // Material Property Field Functions - MAST::ConstantFieldFunction rho_f("rho", rho); - MAST::ConstantFieldFunction E_f("E", E); MAST::ConstantFieldFunction nu_f("nu", nu); - MAST::ConstantFieldFunction cp_f("cp", cp); - MAST::ConstantFieldFunction k_f("k_th", k); // Initialize the material MAST::IsotropicMaterialPropertyCard material; // Add the material property constant field functions to the material card - material.add(rho_f); - material.add(k_f); - material.add(cp_f); - material.add(E_f); material.add(nu_f); // Initialize the section @@ -102,7 +96,7 @@ int main(int argc, const char** argv) section.y_vector() = orientation; // Now initialize the section - section.init(init); + section.init(init, n_target_elements); const libMesh::Point point(4.3, -3.5, -6.7); const Real time = 8.22; @@ -187,6 +181,11 @@ int main(int argc, const char** argv) properties_out << "Warping Constant" << "W" << std::to_string(W) << fort::endr; dproperties_out << "dW" << std::to_string(dW) << fort::endr; + // Get shear center + const libMesh::Point shear_center = section.get_shear_center(point, time); + properties_out << "Shear Center" << "z_sc" << std::to_string(shear_center(0)) << fort::endr; + properties_out << "Shear Center" << "y_sc" << std::to_string(shear_center(1)) << fort::endr; + libMesh::out << "\nProperty Values:\n" << properties_out.to_string() << std::endl; libMesh::out << "Property Derivative w.r.t. DIM1\n" << dproperties_out.to_string() << std::endl; diff --git a/src/base/warping_assembly.cpp b/src/base/warping_assembly.cpp index 46db96b4..79d0fff9 100644 --- a/src/base/warping_assembly.cpp +++ b/src/base/warping_assembly.cpp @@ -39,7 +39,6 @@ #include "libmesh/petsc_matrix.h" - MAST::WarpingAssembly:: WarpingAssembly():MAST::AssemblyBase(), _post_assembly (nullptr), @@ -49,13 +48,11 @@ _first_iter_res_l2_norm (-1.) { } - MAST::WarpingAssembly::~WarpingAssembly() { } - void MAST::WarpingAssembly:: set_post_assembly_operation(MAST::WarpingAssembly::PostAssemblyOperation& post) { @@ -81,10 +78,16 @@ const geometric_properties MAST::WarpingAssembly::calculate_geometric_properties geometric_properties gp; MAST::NonlinearSystem& nonlin_sys = _system->system(); + + /** + * NOTE: Looping over only the local elements results in inncorrect + * properties because the properties are only calculated for the processors + * share of the mesh, instead of the total mesh. I wasn't sure how to sum + * the separate parts together, so I loop over all elements instead. + */ + libMesh::MeshBase::const_element_iterator el = nonlin_sys.get_mesh().elements_begin(); - libMesh::MeshBase::const_element_iterator el = nonlin_sys.get_mesh().active_local_elements_begin(); - - const libMesh::MeshBase::const_element_iterator end_el = nonlin_sys.get_mesh().active_local_elements_end(); + const libMesh::MeshBase::const_element_iterator end_el = nonlin_sys.get_mesh().elements_end(); for ( ; el != end_el; ++el) { @@ -144,7 +147,7 @@ const geometric_properties MAST::WarpingAssembly::calculate_geometric_properties gp.Ixy += JxW[qp] * Nye * Nxe; } // end loop over quadrature points } // end loop over elements - + gp.xc = gp.Qy/gp.A; gp.yc = gp.Qx/gp.A; @@ -184,9 +187,21 @@ const warping_properties MAST::WarpingAssembly::calculate_warping_properties( const uint w_var = _system->system().variable_number("warping_w"); const uint lambda_var = _system->system().variable_number("warping_lambda"); - libMesh::MeshBase::const_element_iterator el = nonlin_sys.get_mesh().active_local_elements_begin(); + std::unique_ptr> localized_F_warp; + localized_F_warp.reset(build_localized_vector(nonlin_sys, F_warp).release()); + + std::unique_ptr> localized_Omega; + localized_Omega.reset(build_localized_vector(nonlin_sys, Omega).release()); + + std::unique_ptr> localized_Psi; + localized_Psi.reset(build_localized_vector(nonlin_sys, Psi).release()); + + std::unique_ptr> localized_Phi; + localized_Phi.reset(build_localized_vector(nonlin_sys, Phi).release()); + + libMesh::MeshBase::const_element_iterator el = nonlin_sys.get_mesh().elements_begin(); - const libMesh::MeshBase::const_element_iterator end_el = nonlin_sys.get_mesh().active_local_elements_end(); + const libMesh::MeshBase::const_element_iterator end_el = nonlin_sys.get_mesh().elements_end(); Real kappa_x = 0.0; Real kappa_y = 0.0; @@ -232,13 +247,17 @@ const warping_properties MAST::WarpingAssembly::calculate_warping_properties( RealVectorX we = RealVectorX::Zero(n_nodes); RealVectorX psie = RealVectorX::Zero(n_nodes); RealVectorX phie = RealVectorX::Zero(n_nodes); + for (uint i=0; ipoint(i)(0); // ye(i) = elem->point(i)(1); - we(i) = Omega(dof_indices[i]); - psie(i) = Psi(dof_indices[i]); - phie(i) = Phi(dof_indices[i]); + //we(i) = Omega(dof_indices[i]); + //psie(i) = Psi(dof_indices[i]); + //phie(i) = Phi(dof_indices[i]); + we(i) = (*localized_Omega)(dof_indices[i]); + psie(i) = (*localized_Psi)(dof_indices[i]); + phie(i) = (*localized_Phi)(dof_indices[i]); } // Loop over quadrature points @@ -295,6 +314,9 @@ const warping_properties MAST::WarpingAssembly::calculate_warping_properties( // and quadrature points. wp.xs -= F_warp.dot(Phi)/delta_s; wp.ys += F_warp.dot(Psi)/delta_s; + //wp.xs -= localized_F_warp->dot(*localized_Phi)/delta_s; + //wp.ys += localized_F_warp->dot(*localized_Psi)/delta_s; + // std::unique_ptr> scaled_F_warp = F_warp.clone(); // uint i=0; // for (const auto node_ptr : nonlin_sys.get_mesh().node_ptr_range()) @@ -352,10 +374,16 @@ get_loads(libMesh::NumericVector& F_warp, const uint w_var = _system->system().variable_number("warping_w"); const uint lambda_var = _system->system().variable_number("warping_lambda"); + F_warp.zero(); + F_shearx.zero(); + F_sheary.zero(); + for ( ; el != end_el; ++el) { const libMesh::Elem* elem = *el; + dof_map.dof_indices(elem, dof_indices, w_var); + MAST::GeomElem geom_elem; geom_elem.init(*elem, *_system); @@ -364,8 +392,6 @@ get_loads(libMesh::NumericVector& F_warp, const MAST::FieldFunction& nu_f = property.get_material().get>("nu"); - dof_map.dof_indices(elem, dof_indices, w_var); - /** Default number of quadrature points for second order triangular * elements is 7. We only need six for full integration of section * properties. So, we set the number of extra quadrature points to -1 @@ -432,16 +458,20 @@ get_loads(libMesh::NumericVector& F_warp, f_shear_y_e += JxW[qp] * ( nu/2. * B.transpose() * h + 2.0*(1.0+nu) * N * (Iyyc*Nye - Ixyc*Nxe) ); } // end loop over quadrature points - DenseRealVector v; + DenseRealVector vec; + vec.zero(); - MAST::copy(v, -f_warp_e); - F_warp.add_vector(v, dof_indices); + MAST::copy(vec, -f_warp_e); + F_warp.add_vector(vec, dof_indices); + vec.zero(); - MAST::copy(v, f_shear_x_e); - F_shearx.add_vector(v, dof_indices); + MAST::copy(vec, f_shear_x_e); + F_shearx.add_vector(vec, dof_indices); + vec.zero(); - MAST::copy(v, f_shear_y_e); - F_sheary.add_vector(v, dof_indices); + MAST::copy(vec, f_shear_y_e); + F_sheary.add_vector(vec, dof_indices); + vec.zero(); dof_indices.clear(); } // end loop over elements @@ -452,7 +482,6 @@ get_loads(libMesh::NumericVector& F_warp, } // end get_loads() function - // /** // * Need w (omega) to calculate: // * Jt, Ixw, Iyw, xs_t, ys_t, Qw, Iw, Gamma_t @@ -460,7 +489,6 @@ get_loads(libMesh::NumericVector& F_warp, // * Need Psi and Theta to calculate: // * xs, ys, Gamma, kappa_x, kappa_y, kappa_xy // */ - void MAST::WarpingAssembly:: residual_and_jacobian (const libMesh::NumericVector& X, @@ -541,8 +569,7 @@ residual_and_jacobian (const libMesh::NumericVector& X, //_check_element_numerical_jacobian(*physics_elem, sol); // perform the element level calculations - ops.elem_calculations(J!=nullptr?true:false, - vec, mat); + ops.elem_calculations(J!=nullptr?true:false, vec, mat); // physics_elem->detach_active_solution_function(); @@ -556,14 +583,14 @@ residual_and_jacobian (const libMesh::NumericVector& X, if (J) MAST::copy(m, mat); - // constrain the quantities to account for hanging dofs, - // Dirichlet constraints, etc. - if (R && J) - dof_map.constrain_element_matrix_and_vector(m, v, dof_indices); - else if (R) - dof_map.constrain_element_vector(v, dof_indices); - else - dof_map.constrain_element_matrix(m, dof_indices); +// // constrain the quantities to account for hanging dofs, +// // Dirichlet constraints, etc. +// if (R && J) +// dof_map.constrain_element_matrix_and_vector(m, v, dof_indices); +// else if (R) +// dof_map.constrain_element_vector(v, dof_indices); +// else +// dof_map.constrain_element_matrix(m, dof_indices); // add to the global matrices if (R) R->add_vector(v, dof_indices); @@ -571,13 +598,14 @@ residual_and_jacobian (const libMesh::NumericVector& X, dof_indices.clear(); } - if (J) + if ((J)) { uint n = J->n(); for (uint i=0; iadd(n-1,i,1.0); - J->add(i,n-1,1.0); + Real val = 1.0/_system->system().comm().size(); + J->add(n-1,i,val); + J->add(i,n-1,val); } //J->add(J->m()-1, J->n()-1, 1.5e-08); } @@ -605,10 +633,16 @@ residual_and_jacobian (const libMesh::NumericVector& X, } if (J && close_matrix) J->close(); + + //if (J) + //{ + // libMesh::out << std::endl; + // J->print(libMesh::out, true); + // J->print_matlab("/home/neiferd/Kwarp.mat"); + // libMesh::out << std::endl; + //} } - - - +// void MAST::WarpingAssembly:: @@ -617,11 +651,10 @@ linearized_jacobian_solution_product (const libMesh::NumericVector& X, libMesh::NumericVector& JdX, libMesh::NonlinearImplicitSystem& S) { - libmesh_error_msg("linearized_jacobian_solution_product not implemented in warping_assembly.cpp"); + libmesh_error_msg("Not implemented.; " << __PRETTY_FUNCTION__ << " in " << __FILE__ << " at line " << __LINE__); } - void MAST::WarpingAssembly:: second_derivative_dot_solution_assembly (const libMesh::NumericVector& X, @@ -629,19 +662,16 @@ second_derivative_dot_solution_assembly (const libMesh::NumericVector& X, libMesh::SparseMatrix& d_JdX_dX, libMesh::NonlinearImplicitSystem& S) { - libmesh_error_msg("second_derivative_dot_solution_assembly not implemented in warping_assembly.cpp"); + libmesh_error_msg("Not implemented.; " << __PRETTY_FUNCTION__ << " in " << __FILE__ << " at line " << __LINE__); } - - - bool MAST::WarpingAssembly:: sensitivity_assemble (const MAST::FunctionBase& f, libMesh::NumericVector& sensitivity_rhs) { - libmesh_error_msg("sensitivity_assemble not implemented in warping_assembly.cpp"); + libmesh_error_msg("Not implemented.; " << __PRETTY_FUNCTION__ << " in " << __FILE__ << " at line " << __LINE__); libmesh_assert(_system); libmesh_assert(_discipline); @@ -791,11 +821,29 @@ sensitivity_assemble (const MAST::FunctionBase& f, return true; } + +std::unique_ptr> +MAST::WarpingAssembly::build_localized_vector(const libMesh::System& sys, + const libMesh::NumericVector& global) const +{ + + libMesh::NumericVector* local = + libMesh::NumericVector::build(sys.comm()).release(); + + local->init(sys.n_dofs(), + sys.n_dofs()); + global.localize(*local); + + return std::unique_ptr >(local); +} + + void MAST::WarpingAssembly::set_force_jacobian_symmetry(bool tf) { _force_jacobian_symmetry = tf; } + const bool MAST::WarpingAssembly::get_force_jacobian_symmetry() const { return _force_jacobian_symmetry; diff --git a/src/base/warping_assembly.h b/src/base/warping_assembly.h index 37fd2331..cac5738a 100644 --- a/src/base/warping_assembly.h +++ b/src/base/warping_assembly.h @@ -209,11 +209,13 @@ namespace MAST { const libMesh::NumericVector& Phi, const Real A, const Real Ixxc, const Real Iyyc, const Real Ixyc, const Real xc, const Real yc) const; + + std::unique_ptr> build_localized_vector( + const libMesh::System& sys, + const libMesh::NumericVector& global) const; protected: - - /*! * this object, if non-NULL is user-provided to perform actions * after assembly and before returning to the solver diff --git a/src/elasticity/warping_system_initialization.cpp b/src/elasticity/warping_system_initialization.cpp index 0e5824a8..e35e77f4 100644 --- a/src/elasticity/warping_system_initialization.cpp +++ b/src/elasticity/warping_system_initialization.cpp @@ -39,7 +39,7 @@ MAST::SystemInitialization(sys, prefix) _vars[0] = sys.add_variable(nm, fe_type); nm = prefix + "_lambda"; - _vars[1] = sys.add_variable(nm, fe_type.order, libMesh::SCALAR); + _vars[1] = sys.add_variable(nm, libMesh::FIRST, libMesh::SCALAR); } diff --git a/src/property_cards/cross_section_property_pilkey.cpp b/src/property_cards/cross_section_property_pilkey.cpp index 5bb9651d..7867e538 100644 --- a/src/property_cards/cross_section_property_pilkey.cpp +++ b/src/property_cards/cross_section_property_pilkey.cpp @@ -129,6 +129,11 @@ class PetscNonlinearSolverConfiguration : public libMesh::SolverConfiguration ierr = SNESLineSearchSetDamping(linesearch, 1.0); CHKERRABORT(_petsc_nonlinear_solver.comm().get(), ierr); + // Disable the SNES monitor to prevent information about this solve + // being printed to screen + ierr = SNESMonitorCancel(_petsc_nonlinear_solver.snes()); + CHKERRABORT(_petsc_nonlinear_solver.comm().get(), ierr); + /** * Recall that a nonlinear solver essentially linearizes a nonlinear * system and does iterative linear solves until it converges to the @@ -153,6 +158,17 @@ class PetscNonlinearSolverConfiguration : public libMesh::SolverConfiguration ierr = PCFactorSetMatSolverType(pc, MATSOLVERMUMPS); CHKERRABORT(_petsc_nonlinear_solver.comm().get(), ierr); + + // Now set these values from options in case the user wants to override + // any of this from the command line + ierr = SNESSetFromOptions(_petsc_nonlinear_solver.snes()); + CHKERRABORT(_petsc_nonlinear_solver.comm().get(), ierr); + + ierr = KSPSetFromOptions(ksp); + CHKERRABORT(_petsc_nonlinear_solver.comm().get(), ierr); + + ierr = PCSetFromOptions(pc); + CHKERRABORT(_petsc_nonlinear_solver.comm().get(), ierr); } libMesh::PetscNonlinearSolver& _petsc_nonlinear_solver; @@ -458,11 +474,11 @@ void MAST::CrossSection::_update_warping_geometry(const libMesh::Point& p, const if ((geometry_points == _geometry_points) and (hole_list == _hole_list) and (_warping_calculated)) { // Geometry did not change, no need to redo calculations. - libMesh::out << "Geometry the same. SKIPPING warping update." << std::endl; + //libMesh::out << "Geometry the same. SKIPPING warping update." << std::endl; } else { - libMesh::out << "Geometry is different. UPDATING warping." << std::endl; + //libMesh::out << "Geometry is different. UPDATING warping." << std::endl; // Geometry did change, need to re-run calculations _warping_calculated = false; _geometry_points = geometry_points; @@ -474,7 +490,6 @@ void MAST::CrossSection::_update_warping_geometry(const libMesh::Point& p, const *_Phi, _A, _Ixxc, _Iyyc, _Ixyc, _Cx, _Cy); _warping_calculated = true; - libMesh::out << "Done updating warping." << std::endl; } } @@ -1052,6 +1067,7 @@ void MAST::CrossSection::_build_model(const libMesh::Point& p, const Real t) _discipline.reset(new MAST::PhysicsDisciplineBase(*_equation_systems)); _equation_systems->init(); + //_equation_systems->print_info(); _parameters["th"].reset(new MAST::Parameter("th", 1.0)); _parameters["zero"].reset(new MAST::Parameter("zero", 0.0)); @@ -1088,9 +1104,18 @@ void MAST::CrossSection::_build_model(const libMesh::Point& p, const Real t) // Shift the mesh so that the global axis lies on the centroid. libMesh::Point centroid(_gp.xc, _gp.yc, 0.0); + + /** + * NOTE: Looping over only the local nodes results an incocrrect shift + * because the mesh is only shifted for the processors share of the mesh, + * instead of the total mesh. + */ for (auto& node_ptr : _mesh->node_ptr_range()) { +// libMesh::out << "NID: " << node_ptr->id() << " PID: " << node_ptr->processor_id() << " Before\n" << *node_ptr << std::endl; +// libMesh::out << "centroid = " << centroid << std::endl; node_ptr->subtract(centroid); +// libMesh::out << "NID: " << node_ptr->id() << " PID: " << node_ptr->processor_id() << " After\n" << *node_ptr << std::endl; } // Zero the solution before solving diff --git a/src/property_cards/solid_1d_bar_section_element_property_card.cpp b/src/property_cards/solid_1d_bar_section_element_property_card.cpp index a8077dd7..6f1ace01 100644 --- a/src/property_cards/solid_1d_bar_section_element_property_card.cpp +++ b/src/property_cards/solid_1d_bar_section_element_property_card.cpp @@ -262,8 +262,10 @@ MAST::Solid1DBarSectionElementPropertyCard::get_stress_points_derivative(const M }; -void MAST::Solid1DBarSectionElementPropertyCard::init(const libMesh::LibMeshInit& init) { - +void MAST::Solid1DBarSectionElementPropertyCard::init(const libMesh::LibMeshInit& init, + const uint n_target_elems, + const libMesh::ElemType element_type) +{ libmesh_assert(!_initialized); MAST::FieldFunction @@ -283,7 +285,7 @@ void MAST::Solid1DBarSectionElementPropertyCard::init(const libMesh::LibMeshInit } // Create a cross section model of this section - cross_section.reset(new MAST::CrossSection(init, 3500, *this, libMesh::TRI6)); + cross_section.reset(new MAST::CrossSection(init, n_target_elems, *this, element_type)); _A.reset(new MAST::Solid1DnParameterSectionProperty::Area(*cross_section)); diff --git a/src/property_cards/solid_1d_bar_section_element_property_card.h b/src/property_cards/solid_1d_bar_section_element_property_card.h index b58e673d..e641e8eb 100644 --- a/src/property_cards/solid_1d_bar_section_element_property_card.h +++ b/src/property_cards/solid_1d_bar_section_element_property_card.h @@ -71,7 +71,9 @@ namespace MAST { */ virtual ~Solid1DBarSectionElementPropertyCard() { } - virtual void init(const libMesh::LibMeshInit& init); + virtual void init(const libMesh::LibMeshInit& init, + const uint n_target_elems=3500, + const libMesh::ElemType element_type=libMesh::TRI6); virtual void create_cross_section( const libMesh::LibMeshInit& init, From 1a9412894f41d172c16ab7ce37747e71d43e0a4b Mon Sep 17 00:00:00 2001 From: David John Neiferd <13425967+JohnDN90@users.noreply.github.com> Date: Wed, 4 Mar 2020 12:03:14 -0500 Subject: [PATCH 12/27] Added ability to specify target number of elements and element type in section initialization. --- .../solid_1d_I1_section_element_property_card.cpp | 8 +++++--- .../solid_1d_I1_section_element_property_card.h | 4 +++- .../solid_1d_rod_section_element_property_card.cpp | 6 ++++-- .../solid_1d_rod_section_element_property_card.h | 4 +++- .../solid_1d_tube2_section_element_property_card.cpp | 8 +++++--- .../solid_1d_tube2_section_element_property_card.h | 4 +++- .../solid_1d_tube_section_element_property_card.cpp | 6 ++++-- .../solid_1d_tube_section_element_property_card.h | 4 +++- 8 files changed, 30 insertions(+), 14 deletions(-) diff --git a/src/property_cards/solid_1d_I1_section_element_property_card.cpp b/src/property_cards/solid_1d_I1_section_element_property_card.cpp index 087727ae..18ffc598 100644 --- a/src/property_cards/solid_1d_I1_section_element_property_card.cpp +++ b/src/property_cards/solid_1d_I1_section_element_property_card.cpp @@ -482,8 +482,10 @@ MAST::Solid1DI1SectionElementPropertyCard::get_stress_points_derivative(const MA }; } -void MAST::Solid1DI1SectionElementPropertyCard::init(const libMesh::LibMeshInit& init) { - +void MAST::Solid1DI1SectionElementPropertyCard::init(const libMesh::LibMeshInit& init, + const uint n_target_elems, + const libMesh::ElemType element_type) +{ libmesh_assert(!_initialized); MAST::FieldFunction @@ -514,7 +516,7 @@ void MAST::Solid1DI1SectionElementPropertyCard::init(const libMesh::LibMeshInit& } // Create a cross section model of this section - cross_section.reset(new MAST::CrossSection(init, 3500, *this, libMesh::TRI6)); + cross_section.reset(new MAST::CrossSection(init, n_target_elems, *this, element_type)); // _A.reset(new MAST::Solid1D4ParameterSectionProperty::Area(MAST::Solid1DI1SectionProperty::calcA, // MAST::Solid1DI1SectionProperty::calcdA, diff --git a/src/property_cards/solid_1d_I1_section_element_property_card.h b/src/property_cards/solid_1d_I1_section_element_property_card.h index a70406d7..7f75b28d 100644 --- a/src/property_cards/solid_1d_I1_section_element_property_card.h +++ b/src/property_cards/solid_1d_I1_section_element_property_card.h @@ -103,7 +103,9 @@ namespace MAST { */ virtual ~Solid1DI1SectionElementPropertyCard() { } - virtual void init(const libMesh::LibMeshInit& init); + virtual void init(const libMesh::LibMeshInit& init, + const uint n_target_elems=3500, + const libMesh::ElemType element_type=libMesh::TRI6); virtual void create_cross_section( const libMesh::LibMeshInit& init, diff --git a/src/property_cards/solid_1d_rod_section_element_property_card.cpp b/src/property_cards/solid_1d_rod_section_element_property_card.cpp index f3eca5a7..2c82d4ad 100644 --- a/src/property_cards/solid_1d_rod_section_element_property_card.cpp +++ b/src/property_cards/solid_1d_rod_section_element_property_card.cpp @@ -262,7 +262,9 @@ MAST::Solid1DRodSectionElementPropertyCard::get_stress_points_derivative(const M } -void MAST::Solid1DRodSectionElementPropertyCard::init(const libMesh::LibMeshInit& init) { +void MAST::Solid1DRodSectionElementPropertyCard::init(const libMesh::LibMeshInit& init, + const uint n_target_elems, + const libMesh::ElemType element_type) { libmesh_assert(!_initialized); @@ -278,7 +280,7 @@ void MAST::Solid1DRodSectionElementPropertyCard::init(const libMesh::LibMeshInit } // Create a cross section model of this section - cross_section.reset(new MAST::CrossSection(init, 3500, *this, libMesh::TRI6)); + cross_section.reset(new MAST::CrossSection(init, n_target_elems, *this, element_type)); _A.reset(new MAST::Solid1D1ParameterSectionProperty::Area(MAST::Solid1DRodSectionProperty::calcA, MAST::Solid1DRodSectionProperty::calcdA, diff --git a/src/property_cards/solid_1d_rod_section_element_property_card.h b/src/property_cards/solid_1d_rod_section_element_property_card.h index ae048c4a..20100630 100644 --- a/src/property_cards/solid_1d_rod_section_element_property_card.h +++ b/src/property_cards/solid_1d_rod_section_element_property_card.h @@ -91,7 +91,9 @@ namespace MAST { */ virtual ~Solid1DRodSectionElementPropertyCard() { } - virtual void init(const libMesh::LibMeshInit& init); + virtual void init(const libMesh::LibMeshInit& init, + const uint n_target_elems=3500, + const libMesh::ElemType element_type=libMesh::TRI6); virtual void create_cross_section( const libMesh::LibMeshInit& init, diff --git a/src/property_cards/solid_1d_tube2_section_element_property_card.cpp b/src/property_cards/solid_1d_tube2_section_element_property_card.cpp index c4accdb1..a96db0db 100644 --- a/src/property_cards/solid_1d_tube2_section_element_property_card.cpp +++ b/src/property_cards/solid_1d_tube2_section_element_property_card.cpp @@ -297,8 +297,10 @@ MAST::Solid1DTube2SectionElementPropertyCard::get_stress_points_derivative(const } -void MAST::Solid1DTube2SectionElementPropertyCard::init(const libMesh::LibMeshInit& init) { - +void MAST::Solid1DTube2SectionElementPropertyCard::init(const libMesh::LibMeshInit& init, + const uint n_target_elems, + const libMesh::ElemType element_type) +{ libmesh_assert(!_initialized); MAST::FieldFunction @@ -321,7 +323,7 @@ void MAST::Solid1DTube2SectionElementPropertyCard::init(const libMesh::LibMeshIn } // Create a cross section model of this section - cross_section.reset(new MAST::CrossSection(init, 3500, *this, libMesh::TRI6)); + cross_section.reset(new MAST::CrossSection(init, n_target_elems, *this, element_type)); _A.reset(new MAST::Solid1D2ParameterSectionProperty::Area(MAST::Solid1DTube2SectionProperty::calcA, MAST::Solid1DTube2SectionProperty::calcdA, diff --git a/src/property_cards/solid_1d_tube2_section_element_property_card.h b/src/property_cards/solid_1d_tube2_section_element_property_card.h index 55e4f8f8..08edbd9f 100644 --- a/src/property_cards/solid_1d_tube2_section_element_property_card.h +++ b/src/property_cards/solid_1d_tube2_section_element_property_card.h @@ -65,7 +65,9 @@ namespace MAST { */ virtual ~Solid1DTube2SectionElementPropertyCard() { } - virtual void init(const libMesh::LibMeshInit& init); + virtual void init(const libMesh::LibMeshInit& init, + const uint n_target_elems=3500, + const libMesh::ElemType element_type=libMesh::TRI6); virtual void create_cross_section( const libMesh::LibMeshInit& init, diff --git a/src/property_cards/solid_1d_tube_section_element_property_card.cpp b/src/property_cards/solid_1d_tube_section_element_property_card.cpp index 7673de37..80ab326d 100644 --- a/src/property_cards/solid_1d_tube_section_element_property_card.cpp +++ b/src/property_cards/solid_1d_tube_section_element_property_card.cpp @@ -307,7 +307,9 @@ MAST::Solid1DTubeSectionElementPropertyCard::get_stress_points_derivative(const } -void MAST::Solid1DTubeSectionElementPropertyCard::init(const libMesh::LibMeshInit& init) +void MAST::Solid1DTubeSectionElementPropertyCard::init( + const libMesh::LibMeshInit& init, const uint n_target_elems, + const libMesh::ElemType element_type) { libmesh_assert(!_initialized); @@ -331,7 +333,7 @@ void MAST::Solid1DTubeSectionElementPropertyCard::init(const libMesh::LibMeshIni } // Create a cross section model of this section - cross_section.reset(new MAST::CrossSection(init, 3500, *this, libMesh::TRI6)); + cross_section.reset(new MAST::CrossSection(init, n_target_elems, *this, element_type)); // _A.reset(new MAST::Solid1DnParameterSectionProperty::Area(*cross_section)); // diff --git a/src/property_cards/solid_1d_tube_section_element_property_card.h b/src/property_cards/solid_1d_tube_section_element_property_card.h index 5b3a3648..fda7f790 100644 --- a/src/property_cards/solid_1d_tube_section_element_property_card.h +++ b/src/property_cards/solid_1d_tube_section_element_property_card.h @@ -65,7 +65,9 @@ namespace MAST { */ virtual ~Solid1DTubeSectionElementPropertyCard() { } - virtual void init(const libMesh::LibMeshInit& init); + virtual void init(const libMesh::LibMeshInit& init, + const uint n_target_elems=3500, + const libMesh::ElemType element_type=libMesh::TRI6); virtual void create_cross_section( const libMesh::LibMeshInit& init, From 40b0213c90e0c038395a256889ef6bfde1208470 Mon Sep 17 00:00:00 2001 From: David John Neiferd <13425967+JohnDN90@users.noreply.github.com> Date: Wed, 4 Mar 2020 15:37:06 -0500 Subject: [PATCH 13/27] Fixed bug in calculations of warping properties. This bug seemed to only affect non-symmetric cross sections. --- src/base/warping_assembly.cpp | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/src/base/warping_assembly.cpp b/src/base/warping_assembly.cpp index 79d0fff9..59510a0a 100644 --- a/src/base/warping_assembly.cpp +++ b/src/base/warping_assembly.cpp @@ -203,9 +203,9 @@ const warping_properties MAST::WarpingAssembly::calculate_warping_properties( const libMesh::MeshBase::const_element_iterator end_el = nonlin_sys.get_mesh().elements_end(); - Real kappa_x = 0.0; - Real kappa_y = 0.0; - Real kappa_xy = 0.0; + Real k_x = 0.0; + Real k_y = 0.0; + Real k_xy = 0.0; Real inv_kappa_x = 0.0; Real inv_kappa_y = 0.0; @@ -255,9 +255,9 @@ const warping_properties MAST::WarpingAssembly::calculate_warping_properties( //we(i) = Omega(dof_indices[i]); //psie(i) = Psi(dof_indices[i]); //phie(i) = Phi(dof_indices[i]); - we(i) = (*localized_Omega)(dof_indices[i]); - psie(i) = (*localized_Psi)(dof_indices[i]); - phie(i) = (*localized_Phi)(dof_indices[i]); + we(i) = -(*localized_Omega)(dof_indices[i]); + psie(i) = -(*localized_Psi)(dof_indices[i]); + phie(i) = -(*localized_Phi)(dof_indices[i]); } // Loop over quadrature points @@ -302,6 +302,7 @@ const warping_properties MAST::WarpingAssembly::calculate_warping_properties( RealVectorX v = B*psie - nu/2.0 * d; RealVectorX w = B*phie - nu/2.0 * h; + inv_kappa_x += JxW[qp] * v.transpose().dot(v) / (delta_s*delta_s); inv_kappa_y += JxW[qp] * w.transpose().dot(w) / (delta_s*delta_s); inv_kappa_xy += JxW[qp] * v.transpose().dot(w) / (delta_s*delta_s); @@ -312,8 +313,16 @@ const warping_properties MAST::WarpingAssembly::calculate_warping_properties( // TODO: This isn't quite correct below because it doesn't account for a // changing value of nu like is done above when looping through elements // and quadrature points. - wp.xs -= F_warp.dot(Phi)/delta_s; - wp.ys += F_warp.dot(Psi)/delta_s; + libMesh::out << "Ixxc = " << Ixxc << std::endl; + libMesh::out << "Iyyc = " << Iyyc << std::endl; + libMesh::out << "Ixyc = " << Ixyc << std::endl; + libMesh::out << "delta_s = " << delta_s << std::endl; + libMesh::out << "x_se_1 = " << wp.xs << std::endl; + libMesh::out << "y_se_1 = " << wp.ys << std::endl; + wp.xs += -F_warp.dot(Phi)/delta_s; + wp.ys += F_warp.dot(Psi)/delta_s; + libMesh::out << "x_se_2 = " << (-F_warp.dot(Phi)/delta_s) << std::endl; + libMesh::out << "y_se_2 = " << (F_warp.dot(Psi)/delta_s) << std::endl; //wp.xs -= localized_F_warp->dot(*localized_Phi)/delta_s; //wp.ys += localized_F_warp->dot(*localized_Psi)/delta_s; @@ -333,6 +342,7 @@ const warping_properties MAST::WarpingAssembly::calculate_warping_properties( Real denom = Ixxc*Iyyc - Ixyc*Ixyc; wp.xs_t = (Ixyc * wp.Ixw - Iyyc * wp.Iyw) / denom; wp.ys_t = (Ixxc * wp.Ixw - Ixyc * wp.Iyw) / denom; + wp.gamma = wp.Iw - wp.Qw * wp.Qw / A - wp.ys * wp.Ixw + wp.xs * wp.Iyw; wp.kappa_x = 1.0/(A*inv_kappa_x); @@ -347,6 +357,8 @@ const warping_properties MAST::WarpingAssembly::calculate_warping_properties( wp.ys_t += yc; wp.xs += xc; wp.ys += yc; + libMesh::out << "wp.xs = " << wp.xs << std::endl; + libMesh::out << "wp.ys = " << wp.ys << std::endl; return wp; } @@ -465,11 +477,11 @@ get_loads(libMesh::NumericVector& F_warp, F_warp.add_vector(vec, dof_indices); vec.zero(); - MAST::copy(vec, f_shear_x_e); + MAST::copy(vec, -f_shear_x_e); F_shearx.add_vector(vec, dof_indices); vec.zero(); - MAST::copy(vec, f_shear_y_e); + MAST::copy(vec, -f_shear_y_e); F_sheary.add_vector(vec, dof_indices); vec.zero(); From 29265e782004523833029d54ca5011827483a95e Mon Sep 17 00:00:00 2001 From: David John Neiferd <13425967+JohnDN90@users.noreply.github.com> Date: Wed, 4 Mar 2020 15:38:44 -0500 Subject: [PATCH 14/27] Added "L" cross section along with catch2 tests. --- src/property_cards/CMakeLists.txt | 2 + ...lid_1d_L_section_element_property_card.cpp | 402 ++++ ...solid_1d_L_section_element_property_card.h | 122 ++ tests/property/CMakeLists.txt | 66 +- ...lid_1d_L_section_element_property_card.cpp | 1710 +++++++++++++++++ 5 files changed, 2272 insertions(+), 30 deletions(-) create mode 100644 src/property_cards/solid_1d_L_section_element_property_card.cpp create mode 100644 src/property_cards/solid_1d_L_section_element_property_card.h create mode 100644 tests/property/mast_solid_1d_L_section_element_property_card.cpp diff --git a/src/property_cards/CMakeLists.txt b/src/property_cards/CMakeLists.txt index e53801dc..e798123b 100644 --- a/src/property_cards/CMakeLists.txt +++ b/src/property_cards/CMakeLists.txt @@ -32,6 +32,8 @@ target_sources(mast ${CMAKE_CURRENT_LIST_DIR}/solid_1d_bar_section_element_property_card.h ${CMAKE_CURRENT_LIST_DIR}/solid_1d_I1_section_element_property_card.cpp ${CMAKE_CURRENT_LIST_DIR}/solid_1d_I1_section_element_property_card.h + ${CMAKE_CURRENT_LIST_DIR}/solid_1d_L_section_element_property_card.cpp + ${CMAKE_CURRENT_LIST_DIR}/solid_1d_L_section_element_property_card.h ${CMAKE_CURRENT_LIST_DIR}/solid_1d_rod_section_element_property_card.cpp ${CMAKE_CURRENT_LIST_DIR}/solid_1d_rod_section_element_property_card.h ${CMAKE_CURRENT_LIST_DIR}/solid_1d_tube_section_element_property_card.cpp diff --git a/src/property_cards/solid_1d_L_section_element_property_card.cpp b/src/property_cards/solid_1d_L_section_element_property_card.cpp new file mode 100644 index 00000000..d9eaa3d3 --- /dev/null +++ b/src/property_cards/solid_1d_L_section_element_property_card.cpp @@ -0,0 +1,402 @@ +/* + * MAST: Multidisciplinary-design Adaptation and Sensitivity Toolkit + * Copyright (C) 2013-2019 Manav Bhatia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +// MAST includes +#include "property_cards/solid_1d_L_section_element_property_card.h" + + +// Unequal Angle (T in Siemens NX Nastran) +void MAST::Solid1DLSectionProperty::calcA(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& A){ + A = DIM1*DIM3+DIM4*(DIM2-DIM3); +} + +void MAST::Solid1DLSectionProperty::calcdA(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dA){ + dA = DIM3*dDIM1+DIM4*dDIM2+dDIM3*(DIM1-DIM4)+dDIM4*(DIM2-DIM3); +} + +void MAST::Solid1DLSectionProperty::calcIz(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& Iz){ + Iz = (DIM1*(DIM3*DIM3*DIM3))/1.2E+1+(DIM4*pow(DIM2-DIM3,3.0))/1.2E+1+DIM4*(DIM2-DIM3)*pow(DIM2/2.0-(DIM2*DIM4*(DIM2-DIM3))/(DIM1*DIM3*2.0+DIM4*(DIM2-DIM3)*2.0),2.0)+DIM1*(DIM2*DIM2)*DIM3*(DIM4*DIM4)*1.0/pow(DIM1*DIM3*2.0+DIM4*(DIM2-DIM3)*2.0,2.0)*pow(DIM2-DIM3,2.0); +} + +void MAST::Solid1DLSectionProperty::calcdIz(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dIz){ + dIz = (dDIM3*(DIM1-DIM4)*1.0/pow(DIM1*DIM3+DIM2*DIM4-DIM3*DIM4,2.0)*pow(DIM1*(DIM3*DIM3)-(DIM2*DIM2)*DIM4-(DIM3*DIM3)*DIM4+DIM2*DIM3*DIM4*2.0,2.0))/4.0+(DIM3*dDIM1*1.0/pow(DIM1*DIM3+DIM2*DIM4-DIM3*DIM4,2.0)*((DIM1*DIM1)*(DIM3*DIM3*DIM3*DIM3)+(DIM2*DIM2*DIM2*DIM2)*(DIM4*DIM4)*3.0+(DIM3*DIM3*DIM3*DIM3)*(DIM4*DIM4)+(DIM2*DIM2)*(DIM3*DIM3)*(DIM4*DIM4)*4.0-DIM1*(DIM3*DIM3*DIM3*DIM3)*DIM4*2.0-DIM2*(DIM3*DIM3*DIM3)*(DIM4*DIM4)*2.0-(DIM2*DIM2*DIM2)*DIM3*(DIM4*DIM4)*6.0+DIM1*DIM2*(DIM3*DIM3*DIM3)*DIM4*2.0))/1.2E+1+(DIM4*dDIM2*1.0/pow(DIM1*DIM3+DIM2*DIM4-DIM3*DIM4,2.0)*pow(-DIM1*(DIM3*DIM3)+(DIM2*DIM2)*DIM4+(DIM3*DIM3)*DIM4+DIM1*DIM2*DIM3*2.0-DIM2*DIM3*DIM4*2.0,2.0))/4.0+(dDIM4*(DIM2-DIM3)*1.0/pow(DIM1*DIM3+DIM2*DIM4-DIM3*DIM4,2.0)*((DIM1*DIM1)*(DIM3*DIM3*DIM3*DIM3)+(DIM2*DIM2*DIM2*DIM2)*(DIM4*DIM4)+(DIM3*DIM3*DIM3*DIM3)*(DIM4*DIM4)+(DIM1*DIM1)*(DIM2*DIM2)*(DIM3*DIM3)*4.0+(DIM2*DIM2)*(DIM3*DIM3)*(DIM4*DIM4)*6.0-DIM1*(DIM3*DIM3*DIM3*DIM3)*DIM4*2.0-(DIM1*DIM1)*DIM2*(DIM3*DIM3*DIM3)*2.0-DIM2*(DIM3*DIM3*DIM3)*(DIM4*DIM4)*4.0-(DIM2*DIM2*DIM2)*DIM3*(DIM4*DIM4)*4.0-DIM1*(DIM2*DIM2)*(DIM3*DIM3)*DIM4*6.0+DIM1*DIM2*(DIM3*DIM3*DIM3)*DIM4*6.0+DIM1*(DIM2*DIM2*DIM2)*DIM3*DIM4*2.0))/1.2E+1; +} + +void MAST::Solid1DLSectionProperty::calcIy(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& Iy){ + Iy = ((DIM1*DIM1*DIM1)*DIM3)/1.2E+1+((DIM4*DIM4*DIM4)*(DIM2-DIM3))/1.2E+1+DIM1*DIM3*pow(DIM1*(-1.0/2.0)+DIM4/2.0+(DIM1*DIM3*(DIM1-DIM4))/(DIM1*DIM3*2.0+DIM4*(DIM2-DIM3)*2.0),2.0)+(DIM1*DIM1)*(DIM3*DIM3)*DIM4*1.0/pow(DIM1*DIM3*2.0+DIM4*(DIM2-DIM3)*2.0,2.0)*pow(DIM1-DIM4,2.0)*(DIM2-DIM3); +} + +void MAST::Solid1DLSectionProperty::calcdIy(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dIy){ + dIy = (dDIM4*(DIM2-DIM3)*1.0/pow(DIM1*DIM3+DIM2*DIM4-DIM3*DIM4,2.0)*pow((DIM1*DIM1)*DIM3-DIM2*(DIM4*DIM4)+DIM3*(DIM4*DIM4)-DIM1*DIM3*DIM4*2.0,2.0))/4.0+(DIM4*dDIM2*1.0/pow(DIM1*DIM3+DIM2*DIM4-DIM3*DIM4,2.0)*((DIM1*DIM1*DIM1*DIM1)*(DIM3*DIM3)*3.0+(DIM2*DIM2)*(DIM4*DIM4*DIM4*DIM4)+(DIM3*DIM3)*(DIM4*DIM4*DIM4*DIM4)+(DIM1*DIM1)*(DIM3*DIM3)*(DIM4*DIM4)*4.0-DIM2*DIM3*(DIM4*DIM4*DIM4*DIM4)*2.0-DIM1*(DIM3*DIM3)*(DIM4*DIM4*DIM4)*2.0-(DIM1*DIM1*DIM1)*(DIM3*DIM3)*DIM4*6.0+DIM1*DIM2*DIM3*(DIM4*DIM4*DIM4)*2.0))/1.2E+1+(DIM3*dDIM1*1.0/pow(DIM1*DIM3+DIM2*DIM4-DIM3*DIM4,2.0)*pow((DIM1*DIM1)*DIM3-DIM2*(DIM4*DIM4)+DIM3*(DIM4*DIM4)+DIM1*DIM2*DIM4*2.0-DIM1*DIM3*DIM4*2.0,2.0))/4.0+(dDIM3*(DIM1-DIM4)*1.0/pow(DIM1*DIM3+DIM2*DIM4-DIM3*DIM4,2.0)*((DIM1*DIM1*DIM1*DIM1)*(DIM3*DIM3)+(DIM2*DIM2)*(DIM4*DIM4*DIM4*DIM4)+(DIM3*DIM3)*(DIM4*DIM4*DIM4*DIM4)+(DIM1*DIM1)*(DIM2*DIM2)*(DIM4*DIM4)*4.0+(DIM1*DIM1)*(DIM3*DIM3)*(DIM4*DIM4)*6.0-DIM2*DIM3*(DIM4*DIM4*DIM4*DIM4)*2.0-DIM1*(DIM2*DIM2)*(DIM4*DIM4*DIM4)*2.0-DIM1*(DIM3*DIM3)*(DIM4*DIM4*DIM4)*4.0-(DIM1*DIM1*DIM1)*(DIM3*DIM3)*DIM4*4.0-(DIM1*DIM1)*DIM2*DIM3*(DIM4*DIM4)*6.0+DIM1*DIM2*DIM3*(DIM4*DIM4*DIM4)*6.0+(DIM1*DIM1*DIM1)*DIM2*DIM3*DIM4*2.0))/1.2E+1; +} + +void MAST::Solid1DLSectionProperty::calcIp(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& Ip){ + Ip = ((DIM1*DIM1)*(DIM3*DIM3*DIM3*DIM3)+(DIM1*DIM1*DIM1*DIM1)*(DIM3*DIM3)+(DIM2*DIM2)*(DIM4*DIM4*DIM4*DIM4)+(DIM2*DIM2*DIM2*DIM2)*(DIM4*DIM4)+(DIM3*DIM3)*(DIM4*DIM4*DIM4*DIM4)+(DIM3*DIM3*DIM3*DIM3)*(DIM4*DIM4)+(DIM1*DIM1)*(DIM3*DIM3)*(DIM4*DIM4)*6.0+(DIM2*DIM2)*(DIM3*DIM3)*(DIM4*DIM4)*6.0-DIM1*(DIM3*DIM3*DIM3*DIM3)*DIM4*2.0-DIM2*DIM3*(DIM4*DIM4*DIM4*DIM4)*2.0-DIM1*(DIM3*DIM3)*(DIM4*DIM4*DIM4)*4.0-(DIM1*DIM1*DIM1)*(DIM3*DIM3)*DIM4*4.0-DIM2*(DIM3*DIM3*DIM3)*(DIM4*DIM4)*4.0-(DIM2*DIM2*DIM2)*DIM3*(DIM4*DIM4)*4.0-DIM1*(DIM2*DIM2)*(DIM3*DIM3)*DIM4*6.0-(DIM1*DIM1)*DIM2*DIM3*(DIM4*DIM4)*6.0+DIM1*DIM2*DIM3*(DIM4*DIM4*DIM4)*4.0+DIM1*DIM2*(DIM3*DIM3*DIM3)*DIM4*4.0+DIM1*(DIM2*DIM2*DIM2)*DIM3*DIM4*4.0+(DIM1*DIM1*DIM1)*DIM2*DIM3*DIM4*4.0)/(DIM1*DIM3*1.2E+1+DIM2*DIM4*1.2E+1-DIM3*DIM4*1.2E+1); +} + +void MAST::Solid1DLSectionProperty::calcdIp(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dIp){ + dIp = (dDIM4*(DIM2-DIM3)*1.0/pow(DIM1*DIM3+DIM2*DIM4-DIM3*DIM4,2.0)*((DIM1*DIM1)*(DIM3*DIM3*DIM3*DIM3)+(DIM1*DIM1*DIM1*DIM1)*(DIM3*DIM3)*3.0+(DIM2*DIM2)*(DIM4*DIM4*DIM4*DIM4)*3.0+(DIM2*DIM2*DIM2*DIM2)*(DIM4*DIM4)+(DIM3*DIM3)*(DIM4*DIM4*DIM4*DIM4)*3.0+(DIM3*DIM3*DIM3*DIM3)*(DIM4*DIM4)+(DIM1*DIM1)*(DIM2*DIM2)*(DIM3*DIM3)*4.0+(DIM1*DIM1)*(DIM3*DIM3)*(DIM4*DIM4)*1.8E+1+(DIM2*DIM2)*(DIM3*DIM3)*(DIM4*DIM4)*6.0-DIM1*(DIM3*DIM3*DIM3*DIM3)*DIM4*2.0-DIM2*DIM3*(DIM4*DIM4*DIM4*DIM4)*6.0-(DIM1*DIM1)*DIM2*(DIM3*DIM3*DIM3)*2.0-DIM1*(DIM3*DIM3)*(DIM4*DIM4*DIM4)*1.2E+1-(DIM1*DIM1*DIM1)*(DIM3*DIM3)*DIM4*1.2E+1-DIM2*(DIM3*DIM3*DIM3)*(DIM4*DIM4)*4.0-(DIM2*DIM2*DIM2)*DIM3*(DIM4*DIM4)*4.0-DIM1*(DIM2*DIM2)*(DIM3*DIM3)*DIM4*6.0-(DIM1*DIM1)*DIM2*DIM3*(DIM4*DIM4)*6.0+DIM1*DIM2*DIM3*(DIM4*DIM4*DIM4)*1.2E+1+DIM1*DIM2*(DIM3*DIM3*DIM3)*DIM4*6.0+DIM1*(DIM2*DIM2*DIM2)*DIM3*DIM4*2.0))/1.2E+1+(dDIM3*(DIM1-DIM4)*1.0/pow(DIM1*DIM3+DIM2*DIM4-DIM3*DIM4,2.0)*((DIM1*DIM1)*(DIM3*DIM3*DIM3*DIM3)*3.0+(DIM1*DIM1*DIM1*DIM1)*(DIM3*DIM3)+(DIM2*DIM2)*(DIM4*DIM4*DIM4*DIM4)+(DIM2*DIM2*DIM2*DIM2)*(DIM4*DIM4)*3.0+(DIM3*DIM3)*(DIM4*DIM4*DIM4*DIM4)+(DIM3*DIM3*DIM3*DIM3)*(DIM4*DIM4)*3.0+(DIM1*DIM1)*(DIM2*DIM2)*(DIM4*DIM4)*4.0+(DIM1*DIM1)*(DIM3*DIM3)*(DIM4*DIM4)*6.0+(DIM2*DIM2)*(DIM3*DIM3)*(DIM4*DIM4)*1.8E+1-DIM1*(DIM3*DIM3*DIM3*DIM3)*DIM4*6.0-DIM2*DIM3*(DIM4*DIM4*DIM4*DIM4)*2.0-DIM1*(DIM2*DIM2)*(DIM4*DIM4*DIM4)*2.0-DIM1*(DIM3*DIM3)*(DIM4*DIM4*DIM4)*4.0-(DIM1*DIM1*DIM1)*(DIM3*DIM3)*DIM4*4.0-DIM2*(DIM3*DIM3*DIM3)*(DIM4*DIM4)*1.2E+1-(DIM2*DIM2*DIM2)*DIM3*(DIM4*DIM4)*1.2E+1-DIM1*(DIM2*DIM2)*(DIM3*DIM3)*DIM4*6.0-(DIM1*DIM1)*DIM2*DIM3*(DIM4*DIM4)*6.0+DIM1*DIM2*DIM3*(DIM4*DIM4*DIM4)*6.0+DIM1*DIM2*(DIM3*DIM3*DIM3)*DIM4*1.2E+1+(DIM1*DIM1*DIM1)*DIM2*DIM3*DIM4*2.0))/1.2E+1+(DIM3*dDIM1*1.0/pow(DIM1*DIM3+DIM2*DIM4-DIM3*DIM4,2.0)*((DIM1*DIM1)*(DIM3*DIM3*DIM3*DIM3)+(DIM1*DIM1*DIM1*DIM1)*(DIM3*DIM3)*3.0+(DIM2*DIM2)*(DIM4*DIM4*DIM4*DIM4)*3.0+(DIM2*DIM2*DIM2*DIM2)*(DIM4*DIM4)*3.0+(DIM3*DIM3)*(DIM4*DIM4*DIM4*DIM4)*3.0+(DIM3*DIM3*DIM3*DIM3)*(DIM4*DIM4)+(DIM1*DIM1)*(DIM2*DIM2)*(DIM4*DIM4)*1.2E+1+(DIM1*DIM1)*(DIM3*DIM3)*(DIM4*DIM4)*1.8E+1+(DIM2*DIM2)*(DIM3*DIM3)*(DIM4*DIM4)*4.0-DIM1*(DIM3*DIM3*DIM3*DIM3)*DIM4*2.0-DIM2*DIM3*(DIM4*DIM4*DIM4*DIM4)*6.0-DIM1*(DIM2*DIM2)*(DIM4*DIM4*DIM4)*1.2E+1-DIM1*(DIM3*DIM3)*(DIM4*DIM4*DIM4)*1.2E+1-(DIM1*DIM1*DIM1)*(DIM3*DIM3)*DIM4*1.2E+1-DIM2*(DIM3*DIM3*DIM3)*(DIM4*DIM4)*2.0-(DIM2*DIM2*DIM2)*DIM3*(DIM4*DIM4)*6.0-(DIM1*DIM1)*DIM2*DIM3*(DIM4*DIM4)*3.0E+1+DIM1*DIM2*DIM3*(DIM4*DIM4*DIM4)*2.4E+1+DIM1*DIM2*(DIM3*DIM3*DIM3)*DIM4*2.0+(DIM1*DIM1*DIM1)*DIM2*DIM3*DIM4*1.2E+1))/1.2E+1+(DIM4*dDIM2*1.0/pow(DIM1*DIM3+DIM2*DIM4-DIM3*DIM4,2.0)*((DIM1*DIM1)*(DIM3*DIM3*DIM3*DIM3)*3.0+(DIM1*DIM1*DIM1*DIM1)*(DIM3*DIM3)*3.0+(DIM2*DIM2)*(DIM4*DIM4*DIM4*DIM4)+(DIM2*DIM2*DIM2*DIM2)*(DIM4*DIM4)*3.0+(DIM3*DIM3)*(DIM4*DIM4*DIM4*DIM4)+(DIM3*DIM3*DIM3*DIM3)*(DIM4*DIM4)*3.0+(DIM1*DIM1)*(DIM2*DIM2)*(DIM3*DIM3)*1.2E+1+(DIM1*DIM1)*(DIM3*DIM3)*(DIM4*DIM4)*4.0+(DIM2*DIM2)*(DIM3*DIM3)*(DIM4*DIM4)*1.8E+1-DIM1*(DIM3*DIM3*DIM3*DIM3)*DIM4*6.0-DIM2*DIM3*(DIM4*DIM4*DIM4*DIM4)*2.0-(DIM1*DIM1)*DIM2*(DIM3*DIM3*DIM3)*1.2E+1-DIM1*(DIM3*DIM3)*(DIM4*DIM4*DIM4)*2.0-(DIM1*DIM1*DIM1)*(DIM3*DIM3)*DIM4*6.0-DIM2*(DIM3*DIM3*DIM3)*(DIM4*DIM4)*1.2E+1-(DIM2*DIM2*DIM2)*DIM3*(DIM4*DIM4)*1.2E+1-DIM1*(DIM2*DIM2)*(DIM3*DIM3)*DIM4*3.0E+1+DIM1*DIM2*DIM3*(DIM4*DIM4*DIM4)*2.0+DIM1*DIM2*(DIM3*DIM3*DIM3)*DIM4*2.4E+1+DIM1*(DIM2*DIM2*DIM2)*DIM3*DIM4*1.2E+1))/1.2E+1; +} + +void MAST::Solid1DLSectionProperty::calcJ1_h(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& J1_h){ + J1_h = (DIM3*DIM3*DIM3)*(DIM1-DIM4/2.0)*((DIM3*((DIM3*DIM3*DIM3*DIM3)*1.0/pow(DIM1*2.0-DIM4,4.0)*(4.0/3.0)-1.0)*(2.1E+1/5.0E+1))/(DIM1*2.0-DIM4)+1.0/3.0); +} + +void MAST::Solid1DLSectionProperty::calcdJ1_h(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dJ1_h){ + dJ1_h = dDIM3*((DIM3*DIM3*DIM3)*((DIM3*DIM3*DIM3*DIM3)*1.0/pow(DIM1*2.0-DIM4,5.0)*(5.6E+1/2.5E+1)+(((DIM3*DIM3*DIM3*DIM3)*1.0/pow(DIM1*2.0-DIM4,4.0)*(4.0/3.0)-1.0)*(2.1E+1/5.0E+1))/(DIM1*2.0-DIM4))*(DIM1-DIM4/2.0)+(DIM3*DIM3)*(DIM1-DIM4/2.0)*((DIM3*((DIM3*DIM3*DIM3*DIM3)*1.0/pow(DIM1*2.0-DIM4,4.0)*(4.0/3.0)-1.0)*(2.1E+1/5.0E+1))/(DIM1*2.0-DIM4)+1.0/3.0)*3.0)-((DIM3*DIM3*DIM3)*dDIM1*1.0/pow(DIM1*2.0-DIM4,5.0)*(DIM1*(DIM4*DIM4*DIM4*DIM4)*-2.5E+2+(DIM1*DIM1*DIM1*DIM1)*DIM4*2.0E+3-(DIM1*DIM1*DIM1*DIM1*DIM1)*8.0E+2+(DIM3*DIM3*DIM3*DIM3*DIM3)*1.68E+2+(DIM4*DIM4*DIM4*DIM4*DIM4)*2.5E+1+(DIM1*DIM1)*(DIM4*DIM4*DIM4)*1.0E+3-(DIM1*DIM1*DIM1)*(DIM4*DIM4)*2.0E+3))/7.5E+1+((DIM3*DIM3*DIM3)*dDIM4*1.0/pow(DIM1*2.0-DIM4,5.0)*(DIM1*(DIM4*DIM4*DIM4*DIM4)*-2.5E+2+(DIM1*DIM1*DIM1*DIM1)*DIM4*2.0E+3-(DIM1*DIM1*DIM1*DIM1*DIM1)*8.0E+2+(DIM3*DIM3*DIM3*DIM3*DIM3)*1.68E+2+(DIM4*DIM4*DIM4*DIM4*DIM4)*2.5E+1+(DIM1*DIM1)*(DIM4*DIM4*DIM4)*1.0E+3-(DIM1*DIM1*DIM1)*(DIM4*DIM4)*2.0E+3))/1.5E+2; +} + +void MAST::Solid1DLSectionProperty::calcJ2_h(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& J2_h){ + J2_h = DIM3*((((1.0/(DIM3*DIM3*DIM3*DIM3)*pow(DIM1-DIM4/2.0,4.0))/1.2E+1-1.0)*(DIM1*(2.1E+1/1.0E+2)-DIM4*(2.1E+1/2.0E+2)))/DIM3+1.0/3.0)*pow(DIM1-DIM4/2.0,3.0); +} + +void MAST::Solid1DLSectionProperty::calcdJ2_h(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dJ2_h){ + dJ2_h = (1.0/(DIM3*DIM3*DIM3*DIM3)*dDIM1*pow(DIM1*2.0-DIM4,2.0)*(DIM1*(DIM3*DIM3*DIM3*DIM3)*-1.344E+3+DIM1*(DIM4*DIM4*DIM4*DIM4)*7.0E+1-(DIM1*DIM1*DIM1*DIM1)*DIM4*5.6E+2+(DIM3*DIM3*DIM3*DIM3)*DIM4*6.72E+2+(DIM1*DIM1*DIM1*DIM1*DIM1)*2.24E+2+(DIM3*DIM3*DIM3*DIM3*DIM3)*1.6E+3-(DIM4*DIM4*DIM4*DIM4*DIM4)*7.0-(DIM1*DIM1)*(DIM4*DIM4*DIM4)*2.8E+2+(DIM1*DIM1*DIM1)*(DIM4*DIM4)*5.6E+2))/6.4E+3-(1.0/(DIM3*DIM3*DIM3*DIM3)*dDIM4*pow(DIM1*2.0-DIM4,2.0)*(DIM1*(DIM3*DIM3*DIM3*DIM3)*-1.344E+3+DIM1*(DIM4*DIM4*DIM4*DIM4)*7.0E+1-(DIM1*DIM1*DIM1*DIM1)*DIM4*5.6E+2+(DIM3*DIM3*DIM3*DIM3)*DIM4*6.72E+2+(DIM1*DIM1*DIM1*DIM1*DIM1)*2.24E+2+(DIM3*DIM3*DIM3*DIM3*DIM3)*1.6E+3-(DIM4*DIM4*DIM4*DIM4*DIM4)*7.0-(DIM1*DIM1)*(DIM4*DIM4*DIM4)*2.8E+2+(DIM1*DIM1*DIM1)*(DIM4*DIM4)*5.6E+2))/1.28E+4+(1.0/(DIM3*DIM3*DIM3*DIM3*DIM3)*dDIM3*pow(DIM1*2.0-DIM4,3.0)*(DIM1*(DIM4*DIM4*DIM4*DIM4)*-2.1E+2+(DIM1*DIM1*DIM1*DIM1)*DIM4*1.68E+3-(DIM1*DIM1*DIM1*DIM1*DIM1)*6.72E+2+(DIM3*DIM3*DIM3*DIM3*DIM3)*3.2E+3+(DIM4*DIM4*DIM4*DIM4*DIM4)*2.1E+1+(DIM1*DIM1)*(DIM4*DIM4*DIM4)*8.4E+2-(DIM1*DIM1*DIM1)*(DIM4*DIM4)*1.68E+3))/7.68E+4; +} + +void MAST::Solid1DLSectionProperty::calcJ1_v(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& J1_v){ + J1_v = (DIM4*DIM4*DIM4)*(DIM2-DIM3/2.0)*((DIM4*((DIM4*DIM4*DIM4*DIM4)*1.0/pow(DIM2*2.0-DIM3,4.0)*(4.0/3.0)-1.0)*(2.1E+1/5.0E+1))/(DIM2*2.0-DIM3)+1.0/3.0); +} + +void MAST::Solid1DLSectionProperty::calcdJ1_v(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dJ1_v){ + dJ1_v = dDIM4*((DIM4*DIM4*DIM4)*((DIM4*DIM4*DIM4*DIM4)*1.0/pow(DIM2*2.0-DIM3,5.0)*(5.6E+1/2.5E+1)+(((DIM4*DIM4*DIM4*DIM4)*1.0/pow(DIM2*2.0-DIM3,4.0)*(4.0/3.0)-1.0)*(2.1E+1/5.0E+1))/(DIM2*2.0-DIM3))*(DIM2-DIM3/2.0)+(DIM4*DIM4)*(DIM2-DIM3/2.0)*((DIM4*((DIM4*DIM4*DIM4*DIM4)*1.0/pow(DIM2*2.0-DIM3,4.0)*(4.0/3.0)-1.0)*(2.1E+1/5.0E+1))/(DIM2*2.0-DIM3)+1.0/3.0)*3.0)-((DIM4*DIM4*DIM4)*dDIM2*1.0/pow(DIM2*2.0-DIM3,5.0)*(DIM2*(DIM3*DIM3*DIM3*DIM3)*-2.5E+2+(DIM2*DIM2*DIM2*DIM2)*DIM3*2.0E+3-(DIM2*DIM2*DIM2*DIM2*DIM2)*8.0E+2+(DIM3*DIM3*DIM3*DIM3*DIM3)*2.5E+1+(DIM4*DIM4*DIM4*DIM4*DIM4)*1.68E+2+(DIM2*DIM2)*(DIM3*DIM3*DIM3)*1.0E+3-(DIM2*DIM2*DIM2)*(DIM3*DIM3)*2.0E+3))/7.5E+1+((DIM4*DIM4*DIM4)*dDIM3*1.0/pow(DIM2*2.0-DIM3,5.0)*(DIM2*(DIM3*DIM3*DIM3*DIM3)*-2.5E+2+(DIM2*DIM2*DIM2*DIM2)*DIM3*2.0E+3-(DIM2*DIM2*DIM2*DIM2*DIM2)*8.0E+2+(DIM3*DIM3*DIM3*DIM3*DIM3)*2.5E+1+(DIM4*DIM4*DIM4*DIM4*DIM4)*1.68E+2+(DIM2*DIM2)*(DIM3*DIM3*DIM3)*1.0E+3-(DIM2*DIM2*DIM2)*(DIM3*DIM3)*2.0E+3))/1.5E+2; +} + +void MAST::Solid1DLSectionProperty::calcJ2_v(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& J2_v){ + J2_v = DIM4*((((1.0/(DIM4*DIM4*DIM4*DIM4)*pow(DIM2-DIM3/2.0,4.0))/1.2E+1-1.0)*(DIM2*(2.1E+1/1.0E+2)-DIM3*(2.1E+1/2.0E+2)))/DIM4+1.0/3.0)*pow(DIM2-DIM3/2.0,3.0); +} + +void MAST::Solid1DLSectionProperty::calcdJ2_v(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dJ2_v){ + dJ2_v = (1.0/(DIM4*DIM4*DIM4*DIM4)*dDIM2*pow(DIM2*2.0-DIM3,2.0)*(DIM2*(DIM3*DIM3*DIM3*DIM3)*7.0E+1-(DIM2*DIM2*DIM2*DIM2)*DIM3*5.6E+2-DIM2*(DIM4*DIM4*DIM4*DIM4)*1.344E+3+DIM3*(DIM4*DIM4*DIM4*DIM4)*6.72E+2+(DIM2*DIM2*DIM2*DIM2*DIM2)*2.24E+2-(DIM3*DIM3*DIM3*DIM3*DIM3)*7.0+(DIM4*DIM4*DIM4*DIM4*DIM4)*1.6E+3-(DIM2*DIM2)*(DIM3*DIM3*DIM3)*2.8E+2+(DIM2*DIM2*DIM2)*(DIM3*DIM3)*5.6E+2))/6.4E+3-(1.0/(DIM4*DIM4*DIM4*DIM4)*dDIM3*pow(DIM2*2.0-DIM3,2.0)*(DIM2*(DIM3*DIM3*DIM3*DIM3)*7.0E+1-(DIM2*DIM2*DIM2*DIM2)*DIM3*5.6E+2-DIM2*(DIM4*DIM4*DIM4*DIM4)*1.344E+3+DIM3*(DIM4*DIM4*DIM4*DIM4)*6.72E+2+(DIM2*DIM2*DIM2*DIM2*DIM2)*2.24E+2-(DIM3*DIM3*DIM3*DIM3*DIM3)*7.0+(DIM4*DIM4*DIM4*DIM4*DIM4)*1.6E+3-(DIM2*DIM2)*(DIM3*DIM3*DIM3)*2.8E+2+(DIM2*DIM2*DIM2)*(DIM3*DIM3)*5.6E+2))/1.28E+4+(1.0/(DIM4*DIM4*DIM4*DIM4*DIM4)*dDIM4*pow(DIM2*2.0-DIM3,3.0)*(DIM2*(DIM3*DIM3*DIM3*DIM3)*-2.1E+2+(DIM2*DIM2*DIM2*DIM2)*DIM3*1.68E+3-(DIM2*DIM2*DIM2*DIM2*DIM2)*6.72E+2+(DIM3*DIM3*DIM3*DIM3*DIM3)*2.1E+1+(DIM4*DIM4*DIM4*DIM4*DIM4)*3.2E+3+(DIM2*DIM2)*(DIM3*DIM3*DIM3)*8.4E+2-(DIM2*DIM2*DIM2)*(DIM3*DIM3)*1.68E+3))/7.68E+4; +} + + +void MAST::Solid1DLSectionProperty::calcJ(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& J) +{ + Real J_h, J_v; + if((DIM1-0.5*DIM4)>DIM3) + { + calcJ1_h(DIM1, DIM2, DIM3, DIM4, J_h); + } + else + { + calcJ2_h(DIM1, DIM2, DIM3, DIM4, J_h); + } + + if((DIM2-0.5*DIM3)>DIM4) + { + calcJ1_v(DIM1, DIM2, DIM3, DIM4, J_v); + } + else + { + calcJ2_v(DIM1, DIM2, DIM3, DIM4, J_v); + } + J = J_h+J_v; +} + +void MAST::Solid1DLSectionProperty::calcdJ(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dJ) +{ + Real dJ_h, dJ_v; + if((DIM1-0.5*DIM4)>DIM3) + { + calcdJ1_h(DIM1, DIM2, DIM3, DIM4, dDIM1, dDIM2, dDIM3, dDIM4, dJ_h); + } + else + { + calcdJ2_h(DIM1, DIM2, DIM3, DIM4, dDIM1, dDIM2, dDIM3, dDIM4, dJ_h); + } + + if((DIM2-0.5*DIM3)>DIM4) + { + calcdJ1_v(DIM1, DIM2, DIM3, DIM4, dDIM1, dDIM2, dDIM3, dDIM4, dJ_v); + } + else + { + calcdJ2_v(DIM1, DIM2, DIM3, DIM4, dDIM1, dDIM2, dDIM3, dDIM4, dJ_v); + } + dJ = dJ_h+dJ_v; +} + + +const std::vector +MAST::Solid1DLSectionElementPropertyCard::get_geom_points(const libMesh::Point& p, const Real t, const uint n) const +{ + const MAST::FieldFunction + &DIM1 = this->get >("DIM1"), + &DIM2 = this->get >("DIM2"), + &DIM3 = this->get >("DIM3"), + &DIM4 = this->get >("DIM4"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + // Check that dimensions are physically correct + Real DIM1v, DIM2v, DIM3v, DIM4v; + DIM1(p, t, DIM1v); DIM2(p, t, DIM2v); DIM3(p, t, DIM3v); DIM4(p, t, DIM4v); + + Real offset_y, offset_z; + hy_off(p, t, offset_y); hz_off(p, t, offset_z); + + libMesh::Point offset(offset_z, offset_y); + libMesh::Point shift(0.5*DIM4v, 0.5*DIM3v); + + std::vector points = { + libMesh::Point(0., 0.) - shift + offset, + libMesh::Point(DIM1v, 0.) - shift + offset, + libMesh::Point(DIM1v, DIM3v) - shift + offset, + libMesh::Point(DIM4v, DIM3v) - shift + offset, + libMesh::Point(DIM4v, DIM2v) - shift + offset, + libMesh::Point(0., DIM2v) - shift + offset + }; + + return points; +} + + +const std::vector +MAST::Solid1DLSectionElementPropertyCard::get_geom_points_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, const uint n) const +{ + const MAST::FieldFunction + &DIM1 = this->get >("DIM1"), + &DIM2 = this->get >("DIM2"), + &DIM3 = this->get >("DIM3"), + &DIM4 = this->get >("DIM4"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + // Check that dimensions are physically correct + Real DIM1v, DIM2v, DIM3v, DIM4v; + DIM1(p, t, DIM1v); DIM2(p, t, DIM2v); DIM3(p, t, DIM3v); DIM4(p, t, DIM4v); + + Real dDIM1v, dDIM2v, dDIM3v, dDIM4v; + DIM1.derivative(f, p, t, dDIM1v); DIM2.derivative(f, p, t, dDIM2v); + DIM3.derivative(f, p, t, dDIM3v); DIM4.derivative(f, p, t, dDIM4v); + + Real offset_y, offset_z, doffset_y, doffset_z; + hy_off(p, t, offset_y); hy_off.derivative(f, p, t, doffset_y); + hz_off(p, t, offset_z); hz_off.derivative(f, p, t, doffset_z); + + libMesh::Point doffset(doffset_z, doffset_y); + libMesh::Point dshift(0.5*dDIM4v, 0.5*dDIM3v); + + std::vector points = { + libMesh::Point(0., 0.) - dshift + doffset, + libMesh::Point(dDIM1v, 0.) - dshift + doffset, + libMesh::Point(dDIM1v, dDIM3v) - dshift + doffset, + libMesh::Point(dDIM4v, dDIM3v) - dshift + doffset, + libMesh::Point(dDIM4v, dDIM2v) - dshift + doffset, + libMesh::Point(0., dDIM2v) - dshift + doffset + }; + + return points; +} + + +const libMesh::Point +MAST::Solid1DLSectionElementPropertyCard::get_centroid(const libMesh::Point& p, const Real t) const +{ + return cross_section->get_centroid(p, t); +} + + +const libMesh::Point +MAST::Solid1DLSectionElementPropertyCard::get_shear_center(const libMesh::Point& p, const Real t) const +{ + return cross_section->get_shear_center(p, t); +} + + +const libMesh::Point +MAST::Solid1DLSectionElementPropertyCard::get_centroid_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t) const +{ + return cross_section->get_centroid_derivative(f, p, t); +} + + +const libMesh::Point +MAST::Solid1DLSectionElementPropertyCard::get_shear_center_derivative(MAST::FunctionBase& f, const libMesh::Point& p, const Real t) +{ + return cross_section->get_shear_center_derivative(f, p, t); +} + + +const std::vector +MAST::Solid1DLSectionElementPropertyCard::get_stress_points(const libMesh::Point& p, const Real t, const libMesh::Point ps) const +{ + // Ordered C, D, E, F as defined in MSC Nastran manual (See PBARL or PBEAML) + const MAST::FieldFunction + &DIM1 = this->get >("DIM1"), + &DIM2 = this->get >("DIM2"), + &DIM3 = this->get >("DIM3"), + &DIM4 = this->get >("DIM4"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + Real DIM1v, DIM2v, DIM3v, DIM4v; + DIM1(p, t, DIM1v); DIM2(p, t, DIM2v); DIM3(p, t, DIM3v); DIM4(p, t, DIM4v); + + Real offset_y, offset_z; + hy_off(p, t, offset_y); hz_off(p, t, offset_z); + + libMesh::Point offset(offset_z, offset_y); + + // Stress Points + std::vector points = { + libMesh::Point(0.5*DIM4v, DIM2v-0.5*DIM3v) - ps, + libMesh::Point(DIM1v-0.5*DIM4v, -0.5*DIM3v) - ps, + libMesh::Point(-0.5*DIM4v, -0.5*DIM3v) - ps, + libMesh::Point(-0.5*DIM4v, DIM2v-0.5*DIM3v) - ps + }; + + return points; +}; + + +const std::vector +MAST::Solid1DLSectionElementPropertyCard::get_stress_points_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, const libMesh::Point dps) const +{ + const MAST::FieldFunction + &DIM1 = this->get >("DIM1"), + &DIM2 = this->get >("DIM2"), + &DIM3 = this->get >("DIM3"), + &DIM4 = this->get >("DIM4"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + // Check that dimensions are physically correct + Real DIM1v, DIM2v, DIM3v, DIM4v; + DIM1(p, t, DIM1v); DIM2(p, t, DIM2v); DIM3(p, t, DIM3v); DIM4(p, t, DIM4v); + + Real dDIM1v, dDIM2v, dDIM3v, dDIM4v; + DIM1.derivative(f, p, t, dDIM1v); DIM2.derivative(f, p, t, dDIM2v); + DIM3.derivative(f, p, t, dDIM3v); DIM4.derivative(f, p, t, dDIM4v); + + Real offset_y, offset_z, doffset_y, doffset_z; + hy_off(p, t, offset_y); hy_off.derivative(f, p, t, doffset_y); + hz_off(p, t, offset_z); hz_off.derivative(f, p, t, doffset_z); + + libMesh::Point doffset(doffset_z, doffset_y); + + // Stress Points + std::vector points = { + libMesh::Point(0.5*dDIM4v, dDIM2v-0.5*dDIM3v) - dps, + libMesh::Point(dDIM1v-0.5*dDIM4v, -0.5*dDIM3v) - dps, + libMesh::Point(-0.5*dDIM4v, -0.5*dDIM3v) - dps, + libMesh::Point(-0.5*dDIM4v, dDIM2v-0.5*dDIM3v) - dps + }; +} + + +void MAST::Solid1DLSectionElementPropertyCard::init(const libMesh::LibMeshInit& init, + const uint n_target_elems, + const libMesh::ElemType element_type) +{ + libmesh_assert(!_initialized); + + MAST::FieldFunction + &DIM1 = this->get >("DIM1"), + &DIM2 = this->get >("DIM2"), + &DIM3 = this->get >("DIM3"), + &DIM4 = this->get >("DIM4"), + &hy_off = this->get >("hy_off"), + &hz_off = this->get >("hz_off"); + + // Create a cross section model of this section + cross_section.reset(new MAST::CrossSection(init, n_target_elems, *this, element_type)); + +// _A.reset(new MAST::Solid1D4ParameterSectionProperty::Area(MAST::Solid1DLSectionProperty::calcA, +// MAST::Solid1DLSectionProperty::calcdA, +// DIM1, DIM2, DIM3, +// DIM4)); +// +// _Ay.reset(new MAST::Solid1D4ParameterSectionProperty::AreaYMoment( +// MAST::Solid1DLSectionProperty::calcA, +// MAST::Solid1DLSectionProperty::calcdA, +// DIM1, DIM2, +// DIM3, DIM4, +// hz_off)); +// +// _Az.reset(new MAST::Solid1D4ParameterSectionProperty::AreaZMoment( +// MAST::Solid1DLSectionProperty::calcA, +// MAST::Solid1DLSectionProperty::calcdA, +// DIM1, DIM2, +// DIM3, DIM4, +// hy_off)); +// +// _J.reset(new MAST::Solid1D4ParameterSectionProperty::TorsionalConstant( +// MAST::Solid1DLSectionProperty::calcJ, +// MAST::Solid1DLSectionProperty::calcdJ, +// DIM1, DIM2, +// DIM3, DIM4)); +// +// _Ip.reset(new MAST::Solid1D4ParameterSectionProperty::PolarInertia( +// MAST::Solid1DLSectionProperty::calcIp, +// MAST::Solid1DLSectionProperty::calcdIp, +// MAST::Solid1DLSectionProperty::calcA, +// MAST::Solid1DLSectionProperty::calcdA, +// DIM1, DIM2, +// DIM3, DIM4, +// hy_off, +// hz_off)); +// +// _AI.reset(new MAST::Solid1D4ParameterSectionProperty::AreaInertiaMatrix( +// MAST::Solid1DLSectionProperty::calcIz, +// MAST::Solid1DLSectionProperty::calcdIz, +// MAST::Solid1DLSectionProperty::calcIy, +// MAST::Solid1DLSectionProperty::calcdIy, +// MAST::Solid1DLSectionProperty::calcA, +// MAST::Solid1DLSectionProperty::calcdA, +// DIM1, DIM2, +// DIM3, DIM4, +// hy_off, +// hz_off)); + + _A.reset(new MAST::Solid1DnParameterSectionProperty::Area(*cross_section)); + + _Ay.reset(new MAST::Solid1DnParameterSectionProperty::AreaYMoment(*cross_section)); + + _Az.reset(new MAST::Solid1DnParameterSectionProperty::AreaZMoment(*cross_section)); + + _AI.reset(new MAST::Solid1DnParameterSectionProperty::AreaInertiaMatrix(*cross_section)); + + _Ip.reset(new MAST::Solid1DnParameterSectionProperty::PolarInertia(*cross_section)); + + _J.reset(new MAST::Solid1DnParameterSectionProperty::TorsionalConstant(*cross_section)); + + _Kappa.reset(new MAST::Solid1DnParameterSectionProperty::ShearCoefficientMatrix(*cross_section)); + + _Gamma.reset(new MAST::Solid1DnParameterSectionProperty::WarpingConstant(*cross_section)); + + _initialized = true; +} + + +void MAST::Solid1DLSectionElementPropertyCard::create_cross_section( + const libMesh::LibMeshInit& init, const uint n_target_elems, + const libMesh::ElemType element_type) +{ + cross_section.reset(new MAST::CrossSection(init, n_target_elems, + *this, element_type)); +} + + +void MAST::Solid1DLSectionElementPropertyCard::calculate_properties_pilkey() +{ + cross_section->calculate_geometric_properties(); + cross_section->calculate_warping_properties(); +} diff --git a/src/property_cards/solid_1d_L_section_element_property_card.h b/src/property_cards/solid_1d_L_section_element_property_card.h new file mode 100644 index 00000000..0be87e1f --- /dev/null +++ b/src/property_cards/solid_1d_L_section_element_property_card.h @@ -0,0 +1,122 @@ +/* + * MAST: Multidisciplinary-design Adaptation and Sensitivity Toolkit + * Copyright (C) 2013-2019 Manav Bhatia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * +// * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __mast__solid_1d_L_section_element_property_card__ +#define __mast__solid_1d_L_section_element_property_card__ + + +// MAST includes +// #include "property_cards/solid_1d_4parameter_section_element_property_card.h" +#include "property_cards/solid_1d_nparameter_section_element_property_card.h" +#include "property_cards/cross_section_property_pilkey.h" + + +// "L" cross section +namespace MAST{ + namespace Solid1DLSectionProperty{ + void calcA(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& A); + + void calcdA(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dA); + + void calcIz(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& Iz); + + void calcdIz(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dIz); + + void calcIy(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& Iy); + + void calcdIy(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dIy); + + void calcIp(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& Ip); + + void calcdIp(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dIp); + + void calcJ1_h(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& J1_h); + + void calcdJ1_h(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dJ1_h); + + void calcJ2_h(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& J2_h); + + void calcdJ2_h(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dJ2_h); + + void calcJ1_v(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& J1_v); + + void calcdJ1_v(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dJ1_v); + + void calcJ2_v(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& J2_v); + + void calcdJ2_v(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dJ2_v); + + void calcJ(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& J); + + void calcdJ(Real& DIM1, Real& DIM2, Real& DIM3, Real& DIM4, Real& dDIM1, Real& dDIM2, Real& dDIM3, Real& dDIM4, Real& dJ); + + } +} + + +namespace MAST { + + class Solid1DLSectionElementPropertyCard : public MAST::Solid1DnParameterSectionElementPropertyCard + { + public: + Solid1DLSectionElementPropertyCard(): + MAST::Solid1DnParameterSectionElementPropertyCard() {} + + /*! + * virtual destructor + */ + virtual ~Solid1DLSectionElementPropertyCard() { } + + virtual void init(const libMesh::LibMeshInit& init, + const uint n_target_elems=3500, + const libMesh::ElemType element_type=libMesh::TRI6); + + virtual void create_cross_section( + const libMesh::LibMeshInit& init, + const uint n_target_elems=3500, + const libMesh::ElemType element_type=libMesh::TRI6); + + virtual void calculate_properties_pilkey(); + + virtual const std::vector get_geom_points(const libMesh::Point& p, const Real t, const uint n=201) const override; + + virtual const std::vector get_geom_points_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, const uint n=201) const override; + + virtual const libMesh::Point get_shear_center(const libMesh::Point& p, const Real t) const override; + + virtual const libMesh::Point get_shear_center_derivative(MAST::FunctionBase& f, const libMesh::Point& p, const Real t) override; + + virtual const libMesh::Point get_centroid(const libMesh::Point& p, const Real t) const override; + + virtual const libMesh::Point get_centroid_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t) const override; + + virtual const std::vector get_stress_points(const libMesh::Point& p, const Real t, const libMesh::Point ps) const override; + + virtual const std::vector get_stress_points_derivative(const MAST::FunctionBase& f, const libMesh::Point& p, const Real t, const libMesh::Point dps) const override; + + std::unique_ptr cross_section; + + const bool bysymmetric = false; + const bool symmetric_z = false; + const bool symmetric_y = false; + }; +} + + +#endif // __mast__solid_1d_L_section_element_property_card__ diff --git a/tests/property/CMakeLists.txt b/tests/property/CMakeLists.txt index 9db05de1..c6645b55 100644 --- a/tests/property/CMakeLists.txt +++ b/tests/property/CMakeLists.txt @@ -4,6 +4,7 @@ target_sources(mast_catch_tests ${CMAKE_CURRENT_LIST_DIR}/mast_solid_1d_arbitrary_section_element_property_card ${CMAKE_CURRENT_LIST_DIR}/mast_solid_1d_bar_section_element_property_card.cpp ${CMAKE_CURRENT_LIST_DIR}/mast_solid_1d_I1_section_element_property_card.cpp + ${CMAKE_CURRENT_LIST_DIR}/mast_solid_1d_L_section_element_property_card.cpp ${CMAKE_CURRENT_LIST_DIR}/mast_solid_1d_rod_section_element_property_card.cpp ${CMAKE_CURRENT_LIST_DIR}/mast_solid_1d_tube_section_element_property_card.cpp ${CMAKE_CURRENT_LIST_DIR}/mast_solid_1d_tube2_section_element_property_card.cpp @@ -749,34 +750,39 @@ set_tests_properties(I1_Element_Property_Card_1D_Dynamic_mpi # ## ============================================================================ -# # 1D L Cross Section -# add_test(NAME L_Element_Property_Card_1D_Base -# COMMAND mast_catch_tests "L_element_property_card_constant_base_1d") -# set_tests_properties(L_Element_Property_Card_1D_Base -# PROPERTIES -# FIXTURES_REQUIRED Isotropic_Material_1D_Structural) -# -# add_test(NAME L_Element_Property_Card_1D_Heat_Transfer -# COMMAND mast_catch_tests "L_element_property_card_constant_heat_transfer_1d") -# set_tests_properties(L_Element_Property_Card_1D_Heat_Transfer -# PROPERTIES -# FIXTURES_REQUIRED Isotropic_Material_1D_Heat_Transfer) -# -# add_test(NAME L_Element_Property_Card_1D_Thermoelastic -# COMMAND mast_catch_tests "L_element_property_card_constant_thermoelastic_1d") -# set_tests_properties(L_Element_Property_Card_1D_Thermoelastic -# PROPERTIES -# FIXTURES_REQUIRED Isotropic_Material_1D_Thermoelastic) -# -# add_test(NAME L_Element_Property_Card_1D_Structural -# COMMAND mast_catch_tests "L_element_property_card_constant_structural_1d") -# set_tests_properties(L_Element_Property_Card_1D_Structural -# PROPERTIES -# FIXTURES_REQUIRED Isotropic_Material_1D_Structural) -# -# add_test(NAME L_Element_Property_Card_1D_Dynamic -# COMMAND mast_catch_tests "L_element_property_card_constant_dynamic_1d") -# set_tests_properties(L_Element_Property_Card_1D_Dynamic -# PROPERTIES -# FIXTURES_REQUIRED Isotropic_Material_1D_Dynamic) +# 1D L Cross Section +add_test(NAME L_Element_Property_Card_1D_Base + COMMAND $ -w NoTests "L_element_property_card_constant_base_1d") +set_tests_properties(L_Element_Property_Card_1D_Base + PROPERTIES + LABELS "SEQ" + FIXTURES_REQUIRED Isotropic_Material_1D_Structural) + +add_test(NAME L_Element_Property_Card_1D_Heat_Transfer + COMMAND $ -w NoTests "L_element_property_card_constant_heat_transfer_1d") +set_tests_properties(L_Element_Property_Card_1D_Heat_Transfer + PROPERTIES + LABELS "SEQ" + FIXTURES_REQUIRED Isotropic_Material_1D_Heat_Transfer) + +add_test(NAME L_Element_Property_Card_1D_Thermoelastic + COMMAND $ -w NoTests "L_element_property_card_constant_thermoelastic_1d") +set_tests_properties(L_Element_Property_Card_1D_Thermoelastic + PROPERTIES + LABELS "SEQ" + FIXTURES_REQUIRED Isotropic_Material_1D_Thermoelastic) + +add_test(NAME L_Element_Property_Card_1D_Structural + COMMAND $ -w NoTests "L_element_property_card_constant_structural_1d") +set_tests_properties(L_Element_Property_Card_1D_Structural + PROPERTIES + LABELS "SEQ" + FIXTURES_REQUIRED Isotropic_Material_1D_Structural) + +add_test(NAME L_Element_Property_Card_1D_Dynamic + COMMAND $ -w NoTests "L_element_property_card_constant_dynamic_1d") +set_tests_properties(L_Element_Property_Card_1D_Dynamic + PROPERTIES + LABELS "SEQ" + FIXTURES_REQUIRED Isotropic_Material_1D_Dynamic) # ## ============================================================================ diff --git a/tests/property/mast_solid_1d_L_section_element_property_card.cpp b/tests/property/mast_solid_1d_L_section_element_property_card.cpp new file mode 100644 index 00000000..3f50d99e --- /dev/null +++ b/tests/property/mast_solid_1d_L_section_element_property_card.cpp @@ -0,0 +1,1710 @@ +// Catch2 includes +#include "catch.hpp" + +// libMesh includes +#include "libmesh/point.h" + +// MAST includes +#include "base/parameter.h" +#include "base/constant_field_function.h" +#include "property_cards/isotropic_material_property_card.h" +#include "property_cards/solid_1d_L_section_element_property_card.h" + +// Custom includes +#include "test_helpers.h" + +extern libMesh::LibMeshInit* p_global_init; + +#define PI 3.1415926535897932 + +/** + * A BAR is defined as a solid rectangular cross section defined by two + * parameters. + */ +TEST_CASE("L_element_property_card_constant_base_1d", + "[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + + // Define Material Properties as MAST Parameters + MAST::Parameter rho("rho_param", 1420.5); // Density + MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity + MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio + MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity + MAST::Parameter k("k_param", 237.0); // Thermal Conductivity + MAST::Parameter alpha("alpha_param", 5.34e-05); // Coeff. of Thermal Exp. + + const Real G = E() / (2. * (1. + nu())); + + // Define Section Properties as MAST Parameters + MAST::Parameter DIM1("DIM1", 6.000); + MAST::Parameter DIM2("DIM2", 3.000); + MAST::Parameter DIM3("DIM3", 0.250); + MAST::Parameter DIM4("DIM4", 0.125); + + MAST::Parameter offset_y("offy_param", -0.918); // Section offset in y-direction + MAST::Parameter offset_z("offz_param", -0.347); // Section offset in z-direction + + // Define Sensitivity Parameters + std::vector sens_params = {&DIM1}; + uint n_s = sens_params.size(); + + // Create field functions to dsitribute these constant parameters throughout the model + // Section Property Field Functions + MAST::ConstantFieldFunction DIM1_f("DIM1", DIM1); + MAST::ConstantFieldFunction DIM2_f("DIM2", DIM2); + MAST::ConstantFieldFunction DIM3_f("DIM3", DIM3); + MAST::ConstantFieldFunction DIM4_f("DIM4", DIM4); + MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); + MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); + // Material Property Field Functions + MAST::ConstantFieldFunction rho_f("rho", rho); + MAST::ConstantFieldFunction E_f("E", E); + MAST::ConstantFieldFunction nu_f("nu", nu); + MAST::ConstantFieldFunction cp_f("cp", cp); + MAST::ConstantFieldFunction k_f("k_th", k); + MAST::ConstantFieldFunction alpha_f("alpha_expansion", alpha); + + // Initialize the material + MAST::IsotropicMaterialPropertyCard material; + + // Add the material property constant field functions to the material card + material.add(rho_f); + material.add(k_f); + material.add(cp_f); + material.add(E_f); + material.add(nu_f); + material.add(alpha_f); + + // Initialize the section + MAST::Solid1DLSectionElementPropertyCard section; + + // Add the section property constant field functions to the section card + section.add(DIM1_f); + section.add(DIM2_f); + section.add(DIM3_f); + section.add(DIM4_f); + + section.add(offsety_f); + section.add(offsetz_f); + + // Add the material card to the section card + section.set_material(material); + + // Specify a section orientation point and add it to the section. + RealVectorX orientation = RealVectorX::Zero(3); + orientation(1) = 1.0; + section.y_vector() = orientation; + + // Now initialize the section + section.init(*p_global_init, 14657); + + REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional + REQUIRE( section.depends_on(DIM1) ); + REQUIRE( section.depends_on(DIM2) ); + REQUIRE( section.depends_on(DIM3) ); + REQUIRE( section.depends_on(DIM4) ); + REQUIRE( section.depends_on(offset_y) ); + REQUIRE( section.depends_on(offset_z) ); + REQUIRE( section.depends_on(k) ); + REQUIRE( section.depends_on(cp) ); + REQUIRE( section.depends_on(rho) ); + + REQUIRE( section.if_isotropic() ); + + // True values + const Real area_true = 1.8437500000000016e+00; + const Real torsion_constant_true = 3.2286682945239953e-02; + const Real first_area_moment_z_true = -1.1769375000000004e+00; + const Real first_area_moment_y_true = 3.7664687499999974e+00; + const Real second_area_moment_zz_true = 1.6049689895833241e+00; + const Real second_area_moment_yy_true = 1.4607873559895829e+01; + const Real second_area_moment_zy_true = -3.6365401874999983e+00; + const Real second_area_moment_polar_true = 1.6212842549479152e+01; + const Real Izzc_true = 8.5368390271891748e-01; + const Real Iyyc_true = 6.9136162881797452e+00; + const Real Izyc_true = -1.2322563559322042e+00; + const Real Ipc_true = 7.7673001908986627e+00; + const Real warping_constant_true = 9.4267903516538354e-02; + const Real kappa_z_true = 6.9387360587828650e-01; + const Real kappa_y_true = 1.5217240110756519e-01; + const Real xs_true = -3.0394644727391729e-01; + const Real ys_true = -9.2444644346018534e-01; + const Real xst_true = -3.0394644727391729e-01; + const Real yst_true = -9.2444644346018534e-01; + const Real xc_true = 2.0428305084745730e+00; + const Real yc_true = -6.3833898305084713e-01; + const std::vector stress_points_true = { + libMesh::Point(-1.9803305084745730e+00, 3.5133389830508470e+00, 0.), + libMesh::Point(3.8946694915254270e+00, 5.1333898305084713e-01, 0.), + libMesh::Point(-2.1053305084745730e+00, 5.1333898305084713e-01, 0.), + libMesh::Point(-2.1053305084745730e+00, 3.5133389830508470e+00, 0.) + }; + + + const libMesh::Point centroid_true(xc_true, yc_true); + const libMesh::Point shear_center_true(xs_true, ys_true); + + const libMesh::Point point(4.3, -3.5, -6.7); + const Real time = 8.22; + + SECTION("section_properties") + { + Real area; + const MAST::FieldFunction& Area = section.A(); + Area(point, time, area); + CHECK( area == Approx(area_true) ); + + Real first_area_moment_y; + const MAST::FieldFunction& Ay = section.Ay(); + Ay(point, time, first_area_moment_y); + CHECK( first_area_moment_y == Approx(first_area_moment_y_true) ); + + Real first_area_moment_z; + const MAST::FieldFunction& Az = section.Az(); + Az(point, time, first_area_moment_z); + CHECK( first_area_moment_z == Approx(first_area_moment_z_true) ); + + RealMatrixX I; + const MAST::FieldFunction& Inertias = section.I(); + Inertias(point, time, I); + CHECK( I(0,1) == I(1,0) ); + Real Iyy = I(1,1); + Real Izz = I(0,0); + Real Izy = I(0,1); + CHECK( Izz == Approx(second_area_moment_zz_true) ); + CHECK( Iyy == Approx(second_area_moment_yy_true) ); + CHECK( Izy == Approx(second_area_moment_zy_true) ); + + Real Ip; + const MAST::FieldFunction& PolarInertia = section.Ip(); + PolarInertia(point, time, Ip); + CHECK( Ip == Approx(second_area_moment_polar_true) ); + + Real torsion_constant; + const MAST::FieldFunction& TorsionConstant = section.J(); + TorsionConstant(point, time, torsion_constant); + CHECK( torsion_constant == Approx(torsion_constant_true).epsilon(0.005)); + + libMesh::Point centroid = section.get_centroid(point, time); + CHECK( centroid(0) == Approx(centroid_true(0)) ); + CHECK( centroid(1) == Approx(centroid_true(1)) ); + + libMesh::out << "Centroid = " << centroid << std::endl; + + const std::vector geom_points = section.get_geom_points(point, time); + for (const auto& point : geom_points) + { + libMesh::out << point << std::endl; + } + + libMesh::Point shear_center = section.get_shear_center(point, time); + CHECK(shear_center(0) == Approx(xs_true).epsilon(0.005)); + CHECK(shear_center(1) == Approx(ys_true).epsilon(0.005)); + + RealMatrixX shear_coefficients; + const MAST::FieldFunction& ShearCoefficientMatrix = section.Kap(); + ShearCoefficientMatrix(point, time, shear_coefficients); + CHECK( shear_coefficients(0,0) == Approx(kappa_z_true).epsilon(0.005) ); + CHECK( shear_coefficients(1,1) == Approx(kappa_y_true).epsilon(0.005) ); + + Real warping_constant; + const MAST::FieldFunction& WarpingConstant = section.Gam(); + WarpingConstant(point, time, warping_constant); + CHECK( warping_constant == Approx(warping_constant_true).epsilon(0.005) ); + } + + SECTION("stress_points") + { + libMesh::Point centroid = section.get_centroid(point, time); + CHECK( centroid(0) == Approx(centroid_true(0)) ); + CHECK( centroid(1) == Approx(centroid_true(1)) ); + std::vector stress_points = section.get_stress_points(point, time, centroid); + + for (uint i=0; i sens_params = {&DIM1, &DIM2, &DIM3, &DIM4, &offset_y, &offset_z}; + uint n_s = sens_params.size(); + + // Create field functions to dsitribute these constant parameters throughout the model + // Section Property Field Functions + MAST::ConstantFieldFunction DIM1_f("DIM1", DIM1); + MAST::ConstantFieldFunction DIM2_f("DIM2", DIM2); + MAST::ConstantFieldFunction DIM3_f("DIM3", DIM3); + MAST::ConstantFieldFunction DIM4_f("DIM4", DIM4); + MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); + MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); + // Material Property Field Functions + MAST::ConstantFieldFunction rho_f("rho", rho); + MAST::ConstantFieldFunction E_f("E", E); + MAST::ConstantFieldFunction nu_f("nu", nu); + MAST::ConstantFieldFunction cp_f("cp", cp); + MAST::ConstantFieldFunction k_f("k_th", k); + MAST::ConstantFieldFunction alpha_f("alpha_expansion", alpha); + + // Initialize the material + MAST::IsotropicMaterialPropertyCard material; + + // Add the material property constant field functions to the material card + material.add(rho_f); + material.add(k_f); + material.add(cp_f); + material.add(E_f); + material.add(nu_f); + material.add(alpha_f); + + // Initialize the section + MAST::Solid1DLSectionElementPropertyCard section; + + // Add the section property constant field functions to the section card + section.add(DIM1_f); + section.add(DIM2_f); + section.add(DIM3_f); + section.add(DIM4_f); + + section.add(offsety_f); + section.add(offsetz_f); + + // Add the material card to the section card + section.set_material(material); + + // Specify a section orientation point and add it to the section. + RealVectorX orientation = RealVectorX::Zero(3); + orientation(1) = 1.0; + section.y_vector() = orientation; + + // Now initialize the section + section.init(*p_global_init); + + REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional + REQUIRE( section.depends_on(DIM1) ); + REQUIRE( section.depends_on(offset_y) ); + REQUIRE( section.depends_on(offset_z) ); + REQUIRE( section.depends_on(k) ); + REQUIRE( section.depends_on(cp) ); + REQUIRE( section.depends_on(rho) ); + + REQUIRE( section.if_isotropic() ); + + // True values + const Real area_true = 1.8437499999999953e+00; + const Real torsion_constant_true = 3.2287060106088283e-02; + const Real first_area_moment_z_true = -1.1769375000000033e+00; + const Real first_area_moment_y_true = 3.7664687499999960e+00; + const Real second_area_moment_zz_true = 1.6049689895833330e+00; + const Real second_area_moment_yy_true = 1.4607873559895838e+01; + const Real second_area_moment_zy_true = -3.6365401874999770e+00; + const Real second_area_moment_polar_true = 1.6212842549479170e+01; + const Real Izzc_true = 8.5368390271892014e-01; + const Real Iyyc_true = 6.9136162881797327e+00; + const Real Izyc_true = -1.2322563559321700e+00; + const Real Ipc_true = 7.7673001908986530e+00; + const Real warping_constant_true = 9.4267315264520590e-02; + const Real kappa_z_true = 6.9387531455434204e-01; + const Real kappa_y_true = 1.5217893373385735e-01; + const Real xs_true = -3.0393910943861346e-01; + const Real ys_true = -9.2444557187933163e-01; + const Real xst_true = -3.0393910943861346e-01; + const Real yst_true = -9.2444557187933163e-01; + const Real xc_true = 2.0428305084745793e+00; + const Real yc_true = -6.3833898305085091e-01; + const std::vector stress_points_true = { + libMesh::Point(-1.9803305084745793e+00, 3.5133389830508510e+00, 0.), + libMesh::Point(3.8946694915254207e+00, 5.1333898305085091e-01, 0.), + libMesh::Point(-2.1053305084745793e+00, 5.1333898305085091e-01, 0.), + libMesh::Point(-2.1053305084745793e+00, 3.5133389830508510e+00, 0.) + }; + + const libMesh::Point point(4.3, -3.5, -6.7); + const Real time = 8.22; + + Real dA_dDIM1, dA_dDIM2; + Real dCz_dDIM1, dCz_dDIM2; + Real dCy_dDIM1, dCy_dDIM2; + Real dQz_dDIM1, dQz_dDIM2; + Real dQy_dDIM1, dQy_dDIM2; + Real dIzz_dDIM1, dIzz_dDIM2; + Real dIyy_dDIM1, dIyy_dDIM2; + Real dIzy_dDIM1, dIzy_dDIM2; + Real dIp_dDIM1, dIp_dDIM2; + Real dIzzc_dDIM1, dIzzc_dDIM2; + Real dIyyc_dDIM1, dIyyc_dDIM2; + Real dIzyc_dDIM1, dIzyc_dDIM2; + Real dIpc_dDIM1, dIpc_dDIM2; + Real dJ_dDIM1, dJ_dDIM2; + Real dxs_dDIM1, dxs_dDIM2; + Real dys_dDIM1, dys_dDIM2; + Real dW_dDIM1, dW_dDIM2; + + Real f_h, f_2h, f_n, f_2n; + RealVectorX fv_h, fv_2h, fv_n, fv_2n; + RealMatrixX fm_h, fm_2h, fm_n, fm_2n; + + const Real delta = 1.220703125e-04; // (np.spacing(1))**(0.25) + + // Area Sensitivity Check + const MAST::FieldFunction& Area = section.A(); + std::vector dA(n_s); + for (uint i=0; i dA_cd(n_s); + for (uint i=0; iname() << " = " << dA[i] << "\tdA_cd = " << dA_cd[i] << std::endl; + REQUIRE(dA[i] == Approx(dA_cd[i])); + } + + + // Centroid Sensitivity Check + std::vector dC(n_s); + for (uint i=0; i dC_cd(n_s); + for (uint i=0; iname() << " = " << dC[i] << "\tdC_cd = " << dC_cd[i] << std::endl; + REQUIRE(dC[i](0) == Approx(dC_cd[i](0)).margin(1.49e-08) ); + REQUIRE(dC[i](1) == Approx(dC_cd[i](1)).margin(1.49e-08) ); + } + + // First Area Moments Sensitivity Check + const MAST::FieldFunction& Area_y = section.Ay(); + std::vector dAy(n_s); + for (uint i=0; i dAy_cd(n_s); + for (uint i=0; iname() << " = " << dAy[i] << "\tdAy_cd = " << dAy_cd[i] << std::endl; + REQUIRE(dAy[i] == Approx(dAy_cd[i])); + } + + + const MAST::FieldFunction& Area_z = section.Az(); + std::vector dAz(n_s); + for (uint i=0; i dAz_cd(n_s); + for (uint i=0; iname() << " = " << dAz[i] << "\tdAz_cd = " << dAz_cd[i] << std::endl; + REQUIRE(dAz[i] == Approx(dAz_cd[i])); + } + + + // Second Area Moments Sensitivity Check + const MAST::FieldFunction& Inertia = section.I(); + std::vector dI(n_s); + for (uint i=0; i dI_cd(n_s); + for (uint i=0; iname() << " =\n" << dI[i] << "\ndI_cd = \n" << dI_cd[i] << std::endl; + + Real dIzz = dI[i](0,0); + Real dIyy = dI[i](1,1); + Real dIyz = dI[i](1,0); + Real dIzy = dI[i](0,1); + + Real dIzz_cd = dI_cd[i](0,0); + Real dIyy_cd = dI_cd[i](1,1); + Real dIyz_cd = dI_cd[i](1,0); + Real dIzy_cd = dI_cd[i](0,1); + + REQUIRE(dIzz == Approx(dIzz_cd)); + REQUIRE(dIyy == Approx(dIyy_cd)); + REQUIRE(dIyz == Approx(dIyz_cd)); + REQUIRE(dIzy == Approx(dIzy_cd)); + REQUIRE(dIyz == dIzy); // symmetry check + } + + + // Second Area Polar Moment Sensitivity Check + const MAST::FieldFunction& PolarInertia = section.Ip(); + std::vector dIp(n_s); + for (uint i=0; i dIp_cd(n_s); + for (uint i=0; iname() << " = " << dIp[i] << "\tdIp_cd = " << dIp_cd[i] << std::endl; + REQUIRE(dIp[i] == Approx(dIp_cd[i])); + } + + +// // Shear Center Sensitivity Check +// std::vector dCs(n_s); +// for (uint i=0; i dCs_cd(n_s); +// for (uint i=0; iname() << " = " << dCs[i] << "\tdCs_cd = " << dCs_cd[i] << std::endl; +// REQUIRE(dCs[i](0) == Approx(dCs_cd[i](0)) ); +// REQUIRE(dCs[i](1) == Approx(dCs_cd[i](1)) ); +// } + + + // Torsion Constant Sensitivity Check + // NOTE: The field function below is not made constant because currently a finite difference is used to calculate sensitivity. + MAST::FieldFunction& TorsionConstant = section.J(); + std::vector dJ(n_s); + for (uint i=0; i dJ_cd(n_s); + for (uint i=0; iname() << " = " << dJ[i] << "\tdJ_cd = " << dJ_cd[i] << std::endl; + REQUIRE(dJ[i] == Approx(dJ_cd[i]).epsilon(0.1) ); + // NOTE: 10% error margin due to 'exact' sensitivity being calculated using finite difference + } + + + // Shear Coefficient Sensitivity Check + // NOTE: The field function below is not made constant because currently a finite difference is used to calculate sensitivity. + MAST::FieldFunction& Kappa = section.Kap(); + std::vector dK(n_s); + for (uint i=0; i dK_cd(n_s); + for (uint i=0; iname() << " =\n" << dK[i] << "\ndK_cd = \n" << dK_cd[i] << std::endl; + + Real dKzz = dK[i](0,0); + Real dKyy = dK[i](1,1); + Real dKyz = dK[i](1,0); + Real dKzy = dK[i](0,1); + + Real dKzz_cd = dK_cd[i](0,0); + Real dKyy_cd = dK_cd[i](1,1); + Real dKyz_cd = dK_cd[i](1,0); + Real dKzy_cd = dK_cd[i](0,1); + + REQUIRE(dKzz == Approx(dKzz_cd).epsilon(0.1)); + REQUIRE(dKyy == Approx(dKyy_cd).epsilon(0.1)); + //REQUIRE(dKyz == Approx(dKyz_cd).epsilon(0.1)); // Comparison can be hard when this is nearly infinite (~1e+13) + //REQUIRE(dKzy == Approx(dKzy_cd).epsilon(0.1)); // Comparison can be hard when this is nearly infinite (~1e+13) + // NOTE: 10% error margin due to 'exact' sensitivity being calculated using finite difference + REQUIRE(dKyz == dKzy); // symmetry check + } + + + // Warping Constant Sensitivity Check + // NOTE: The field function below is not made constant because currently a finite difference is used to calculate sensitivity. + MAST::FieldFunction& WarpingConstant = section.Gam(); + std::vector dW(n_s); + for (uint i=0; i dW_cd(n_s); + for (uint i=0; iname() << " = " << dW[i] << "\tdW_cd = " << dW_cd[i] << std::endl; + REQUIRE(dW[i] == Approx(dW_cd[i]).epsilon(0.1) ); + // NOTE: 10% error margin due to 'exact' sensitivity being calculated using finite difference + } +} + + +TEST_CASE("L_element_property_card_constant_heat_transfer_1d", + "[heat_transfer],[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + + // Define Material Properties as MAST Parameters + MAST::Parameter rho("rho_param", 1420.5); // Density + MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity + MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio + MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity + MAST::Parameter k("k_param", 237.0); // Thermal Conductivity + MAST::Parameter alpha("alpha_param", 5.34e-05); // Coeff. of Thermal Exp. + + const Real G = E() / (2. * (1. + nu())); + + // Define Section Properties as MAST Parameters + MAST::Parameter DIM1("DIM1", 6.000); + MAST::Parameter DIM2("DIM2", 3.000); + MAST::Parameter DIM3("DIM3", 0.250); + MAST::Parameter DIM4("DIM4", 0.125); + + MAST::Parameter offset_y("offy_param", -0.918); // Section offset in y-direction + MAST::Parameter offset_z("offz_param", -0.347); // Section offset in z-direction + + // Define Sensitivity Parameters + std::vector sens_params = {&DIM1}; + uint n_s = sens_params.size(); + + // Create field functions to dsitribute these constant parameters throughout the model + // Section Property Field Functions + MAST::ConstantFieldFunction DIM1_f("DIM1", DIM1); + MAST::ConstantFieldFunction DIM2_f("DIM2", DIM2); + MAST::ConstantFieldFunction DIM3_f("DIM3", DIM3); + MAST::ConstantFieldFunction DIM4_f("DIM4", DIM4); + MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); + MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); + // Material Property Field Functions + MAST::ConstantFieldFunction rho_f("rho", rho); + MAST::ConstantFieldFunction E_f("E", E); + MAST::ConstantFieldFunction nu_f("nu", nu); + MAST::ConstantFieldFunction cp_f("cp", cp); + MAST::ConstantFieldFunction k_f("k_th", k); + MAST::ConstantFieldFunction alpha_f("alpha_expansion", alpha); + + // Initialize the material + MAST::IsotropicMaterialPropertyCard material; + + // Add the material property constant field functions to the material card + material.add(rho_f); + material.add(k_f); + material.add(cp_f); + material.add(E_f); + material.add(nu_f); + material.add(alpha_f); + + // Initialize the section + MAST::Solid1DLSectionElementPropertyCard section; + + // Add the section property constant field functions to the section card + section.add(DIM1_f); + section.add(DIM2_f); + section.add(DIM3_f); + section.add(DIM4_f); + + section.add(offsety_f); + section.add(offsetz_f); + + // Add the material card to the section card + section.set_material(material); + + // Specify a section orientation point and add it to the section. + RealVectorX orientation = RealVectorX::Zero(3); + orientation(1) = 1.0; + section.y_vector() = orientation; + + // Now initialize the section + section.init(*p_global_init); + + REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional + REQUIRE( section.depends_on(DIM1) ); + REQUIRE( section.depends_on(offset_y) ); + REQUIRE( section.depends_on(offset_z) ); + REQUIRE( section.depends_on(k) ); + REQUIRE( section.depends_on(cp) ); + REQUIRE( section.depends_on(rho) ); + + REQUIRE( section.if_isotropic() ); + + // True values + const Real area_true = 1.8437499999999953e+00; + const Real torsion_constant_true = 3.2287060106088283e-02; + const Real first_area_moment_z_true = -1.1769375000000033e+00; + const Real first_area_moment_y_true = 3.7664687499999960e+00; + const Real second_area_moment_zz_true = 1.6049689895833330e+00; + const Real second_area_moment_yy_true = 1.4607873559895838e+01; + const Real second_area_moment_zy_true = -3.6365401874999770e+00; + const Real second_area_moment_polar_true = 1.6212842549479170e+01; + const Real Izzc_true = 8.5368390271892014e-01; + const Real Iyyc_true = 6.9136162881797327e+00; + const Real Izyc_true = -1.2322563559321700e+00; + const Real Ipc_true = 7.7673001908986530e+00; + const Real warping_constant_true = 9.4267315264520590e-02; + const Real kappa_z_true = 6.9387531455434204e-01; + const Real kappa_y_true = 1.5217893373385735e-01; + const Real xs_true = -3.0393910943861346e-01; + const Real ys_true = -9.2444557187933163e-01; + const Real xst_true = -3.0393910943861346e-01; + const Real yst_true = -9.2444557187933163e-01; + const Real xc_true = 2.0428305084745793e+00; + const Real yc_true = -6.3833898305085091e-01; + const std::vector stress_points_true = { + libMesh::Point(-1.9803305084745793e+00, 3.5133389830508510e+00, 0.), + libMesh::Point(3.8946694915254207e+00, 5.1333898305085091e-01, 0.), + libMesh::Point(-2.1053305084745793e+00, 5.1333898305085091e-01, 0.), + libMesh::Point(-2.1053305084745793e+00, 3.5133389830508510e+00, 0.) + }; + + const libMesh::Point point(4.3, -3.5, -6.7); + const Real time = 8.22; + + Real area; + const MAST::FieldFunction& Area = section.A(); + Area(point, time, area); + REQUIRE( area == Approx(area_true) ); + + + SECTION("1D section thermal conductance matrix") + { + /** + * As of Dec. 17, 2019, inertia_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * inertia_matrix to be obtained without any input arguments. + */ + std::unique_ptr> conduct_mat = section.thermal_conductance_matrix(); + + const libMesh::Point point(2.3, 3.1, 5.2); + const Real time = 2.34; + RealMatrixX D_sec_conduc; + conduct_mat->operator()(point, time, D_sec_conduc); + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_conduc_true = RealMatrixX::Zero(1,1); + D_sec_conduc_true(0,0) = k() * area_true; + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_conduc); + std::vector truth = eigen_matrix_to_std_vector(D_sec_conduc_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } + + SECTION("1D section thermal capacitance matrix") + { + /** + * As of Dec. 17, 2019, inertia_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * inertia_matrix to be obtained without any input arguments. + */ + std::unique_ptr> capaci_mat = section.thermal_capacitance_matrix(); + + const libMesh::Point point(2.3, 3.1, 5.2); + const Real time = 2.34; + RealMatrixX D_sec_capac; + capaci_mat->operator()(point, time, D_sec_capac); + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_capac_true = RealMatrixX::Zero(1,1); + D_sec_capac_true(0,0) = rho() * cp() * area_true; + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_capac); + std::vector truth = eigen_matrix_to_std_vector(D_sec_capac_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } +} + + +TEST_CASE("L_element_property_card_constant_thermoelastic_1d", + "[thermoelastic],[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + + // Define Material Properties as MAST Parameters + MAST::Parameter rho("rho_param", 1420.5); // Density + MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity + MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio + MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity + MAST::Parameter k("k_param", 237.0); // Thermal Conductivity + MAST::Parameter alpha("alpha_param", 5.34e-05); // Coeff. of Thermal Exp. + + const Real G = E() / (2. * (1. + nu())); + + // Define Section Properties as MAST Parameters + MAST::Parameter DIM1("DIM1", 6.000); + MAST::Parameter DIM2("DIM2", 3.000); + MAST::Parameter DIM3("DIM3", 0.250); + MAST::Parameter DIM4("DIM4", 0.125); + + MAST::Parameter offset_y("offy_param", -0.918); // Section offset in y-direction + MAST::Parameter offset_z("offz_param", -0.347); // Section offset in z-direction + + // Define Sensitivity Parameters + std::vector sens_params = {&DIM1}; + uint n_s = sens_params.size(); + + // Create field functions to dsitribute these constant parameters throughout the model + // Section Property Field Functions + MAST::ConstantFieldFunction DIM1_f("DIM1", DIM1); + MAST::ConstantFieldFunction DIM2_f("DIM2", DIM2); + MAST::ConstantFieldFunction DIM3_f("DIM3", DIM3); + MAST::ConstantFieldFunction DIM4_f("DIM4", DIM4); + MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); + MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); + // Material Property Field Functions + MAST::ConstantFieldFunction rho_f("rho", rho); + MAST::ConstantFieldFunction E_f("E", E); + MAST::ConstantFieldFunction nu_f("nu", nu); + MAST::ConstantFieldFunction cp_f("cp", cp); + MAST::ConstantFieldFunction k_f("k_th", k); + MAST::ConstantFieldFunction alpha_f("alpha_expansion", alpha); + + // Initialize the material + MAST::IsotropicMaterialPropertyCard material; + + // Add the material property constant field functions to the material card + material.add(rho_f); + material.add(k_f); + material.add(cp_f); + material.add(E_f); + material.add(nu_f); + material.add(alpha_f); + + // Initialize the section + MAST::Solid1DLSectionElementPropertyCard section; + + // Add the section property constant field functions to the section card + section.add(DIM1_f); + section.add(DIM2_f); + section.add(DIM3_f); + section.add(DIM4_f); + + section.add(offsety_f); + section.add(offsetz_f); + + // Add the material card to the section card + section.set_material(material); + + // Specify a section orientation point and add it to the section. + RealVectorX orientation = RealVectorX::Zero(3); + orientation(1) = 1.0; + section.y_vector() = orientation; + + // Now initialize the section + section.init(*p_global_init); + + REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional + REQUIRE( section.depends_on(DIM1) ); + REQUIRE( section.depends_on(offset_y) ); + REQUIRE( section.depends_on(offset_z) ); + REQUIRE( section.depends_on(k) ); + REQUIRE( section.depends_on(cp) ); + REQUIRE( section.depends_on(rho) ); + + REQUIRE( section.if_isotropic() ); + + // True values + const Real area_true = 1.8437499999999953e+00; + const Real torsion_constant_true = 3.2287060106088283e-02; + const Real first_area_moment_z_true = -1.1769375000000033e+00; + const Real first_area_moment_y_true = 3.7664687499999960e+00; + const Real second_area_moment_zz_true = 1.6049689895833330e+00; + const Real second_area_moment_yy_true = 1.4607873559895838e+01; + const Real second_area_moment_zy_true = -3.6365401874999770e+00; + const Real second_area_moment_polar_true = 1.6212842549479170e+01; + const Real Izzc_true = 8.5368390271892014e-01; + const Real Iyyc_true = 6.9136162881797327e+00; + const Real Izyc_true = -1.2322563559321700e+00; + const Real Ipc_true = 7.7673001908986530e+00; + const Real warping_constant_true = 9.4267315264520590e-02; + const Real kappa_z_true = 6.9387531455434204e-01; + const Real kappa_y_true = 1.5217893373385735e-01; + const Real xs_true = -3.0393910943861346e-01; + const Real ys_true = -9.2444557187933163e-01; + const Real xst_true = -3.0393910943861346e-01; + const Real yst_true = -9.2444557187933163e-01; + const Real xc_true = 2.0428305084745793e+00; + const Real yc_true = -6.3833898305085091e-01; + const std::vector stress_points_true = { + libMesh::Point(-1.9803305084745793e+00, 3.5133389830508510e+00, 0.), + libMesh::Point(3.8946694915254207e+00, 5.1333898305085091e-01, 0.), + libMesh::Point(-2.1053305084745793e+00, 5.1333898305085091e-01, 0.), + libMesh::Point(-2.1053305084745793e+00, 3.5133389830508510e+00, 0.) + }; + + const libMesh::Point point(4.3, -3.5, -6.7); + const Real time = 8.22; + + SECTION("1D thermal expansion A matrix") + { + /** + * As of Dec. 17, 2019, thermal_expansion_A_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * thermal_expansion_A_matrix to be obtained without any input arguments. + */ + + Real area; + const MAST::FieldFunction& Area = section.A(); + Area(point, time, area); + CHECK( area == Approx(area_true) ); + + std::unique_ptr> texp_A_mat = section.thermal_expansion_A_matrix(); + + const libMesh::Point point(2.3, 3.1, 5.2); + const Real time = 2.34; + RealMatrixX D_sec_texpA; + texp_A_mat->operator()(point, time, D_sec_texpA); + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_texpA_true = RealMatrixX::Zero(2,1); + D_sec_texpA_true(0,0) = E() * alpha() * area_true; + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_texpA); + std::vector truth = eigen_matrix_to_std_vector(D_sec_texpA_true); + + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } + + SECTION("1D thermal expansion B matrix") + { + /** + * As of Dec. 17, 2019, thermal_expansion_B_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * thermal_expansion_B_matrix to be obtained without any input arguments. + */ + + Real first_area_moment_y; + const MAST::FieldFunction& Ay = section.Ay(); + Ay(point, time, first_area_moment_y); + CHECK( first_area_moment_y == Approx(first_area_moment_y_true) ); + + Real first_area_moment_z; + const MAST::FieldFunction& Az = section.Az(); + Az(point, time, first_area_moment_z); + CHECK( first_area_moment_z == Approx(first_area_moment_z_true) ); + + std::unique_ptr> texp_B_mat = section.thermal_expansion_B_matrix(); + + const libMesh::Point point(2.3, 3.1, 5.2); + const Real time = 2.34; + RealMatrixX D_sec_texpB; + texp_B_mat->operator()(point, time, D_sec_texpB); + + libMesh::out << "texp_B_mat =\n" << D_sec_texpB << std::endl; + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_texpB_true = RealMatrixX::Zero(2,1); + D_sec_texpB_true(0,0) = E() * alpha() * first_area_moment_z_true; + D_sec_texpB_true(1,0) = E() * alpha() * first_area_moment_y_true; + + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_texpB); + std::vector truth = eigen_matrix_to_std_vector(D_sec_texpB_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } +} + +// FIXME: I don't think this one is being run. +TEST_CASE("L_element_property_card_constant_dynamic_1d", + "[dynamic],[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + + // Define Material Properties as MAST Parameters + MAST::Parameter rho("rho_param", 1420.5); // Density + MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity + MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio + MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity + MAST::Parameter k("k_param", 237.0); // Thermal Conductivity + MAST::Parameter alpha("alpha_param", 5.34e-05); // Coeff. of Thermal Exp. + + const Real G = E() / (2. * (1. + nu())); + + // Define Section Properties as MAST Parameters + MAST::Parameter DIM1("DIM1", 6.000); + MAST::Parameter DIM2("DIM2", 3.000); + MAST::Parameter DIM3("DIM3", 0.250); + MAST::Parameter DIM4("DIM4", 0.125); + + MAST::Parameter offset_y("offy_param", -0.918); // Section offset in y-direction + MAST::Parameter offset_z("offz_param", -0.347); // Section offset in z-direction + + // Define Sensitivity Parameters + std::vector sens_params = {&DIM1}; + uint n_s = sens_params.size(); + + // Create field functions to dsitribute these constant parameters throughout the model + // Section Property Field Functions + MAST::ConstantFieldFunction DIM1_f("DIM1", DIM1); + MAST::ConstantFieldFunction DIM2_f("DIM2", DIM2); + MAST::ConstantFieldFunction DIM3_f("DIM3", DIM3); + MAST::ConstantFieldFunction DIM4_f("DIM4", DIM4); + MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); + MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); + // Material Property Field Functions + MAST::ConstantFieldFunction rho_f("rho", rho); + MAST::ConstantFieldFunction E_f("E", E); + MAST::ConstantFieldFunction nu_f("nu", nu); + MAST::ConstantFieldFunction cp_f("cp", cp); + MAST::ConstantFieldFunction k_f("k_th", k); + MAST::ConstantFieldFunction alpha_f("alpha_expansion", alpha); + + // Initialize the material + MAST::IsotropicMaterialPropertyCard material; + + // Add the material property constant field functions to the material card + material.add(rho_f); + material.add(k_f); + material.add(cp_f); + material.add(E_f); + material.add(nu_f); + material.add(alpha_f); + + // Initialize the section + MAST::Solid1DLSectionElementPropertyCard section; + + // Add the section property constant field functions to the section card + section.add(DIM1_f); + section.add(DIM2_f); + section.add(DIM3_f); + section.add(DIM4_f); + + section.add(offsety_f); + section.add(offsetz_f); + + // Add the material card to the section card + section.set_material(material); + + // Specify a section orientation point and add it to the section. + RealVectorX orientation = RealVectorX::Zero(3); + orientation(1) = 1.0; + section.y_vector() = orientation; + + // Now initialize the section + section.init(*p_global_init); + + REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional + REQUIRE( section.depends_on(DIM1) ); + REQUIRE( section.depends_on(offset_y) ); + REQUIRE( section.depends_on(offset_z) ); + REQUIRE( section.depends_on(k) ); + REQUIRE( section.depends_on(cp) ); + REQUIRE( section.depends_on(rho) ); + + REQUIRE( section.if_isotropic() ); + + // True values + const Real area_true = 1.8437499999999953e+00; + const Real torsion_constant_true = 3.2287060106088283e-02; + const Real first_area_moment_z_true = -1.1769375000000033e+00; + const Real first_area_moment_y_true = 3.7664687499999960e+00; + const Real second_area_moment_zz_true = 1.6049689895833330e+00; + const Real second_area_moment_yy_true = 1.4607873559895838e+01; + const Real second_area_moment_zy_true = -3.6365401874999770e+00; + const Real second_area_moment_polar_true = 1.6212842549479170e+01; + const Real Izzc_true = 8.5368390271892014e-01; + const Real Iyyc_true = 6.9136162881797327e+00; + const Real Izyc_true = -1.2322563559321700e+00; + const Real Ipc_true = 7.7673001908986530e+00; + const Real warping_constant_true = 9.4267315264520590e-02; + const Real kappa_z_true = 6.9387531455434204e-01; + const Real kappa_y_true = 1.5217893373385735e-01; + const Real xs_true = -3.0393910943861346e-01; + const Real ys_true = -9.2444557187933163e-01; + const Real xst_true = -3.0393910943861346e-01; + const Real yst_true = -9.2444557187933163e-01; + const Real xc_true = 2.0428305084745793e+00; + const Real yc_true = -6.3833898305085091e-01; + const std::vector stress_points_true = { + libMesh::Point(-1.9803305084745793e+00, 3.5133389830508510e+00, 0.), + libMesh::Point(3.8946694915254207e+00, 5.1333898305085091e-01, 0.), + libMesh::Point(-2.1053305084745793e+00, 5.1333898305085091e-01, 0.), + libMesh::Point(-2.1053305084745793e+00, 3.5133389830508510e+00, 0.) + }; + + const libMesh::Point point(4.3, -3.5, -6.7); + const Real time = 8.22; + + SECTION("1D section inertia matrix") + { + /** + * As of Dec. 17, 2019, inertia_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * inertia_matrix to be obtained without any input arguments. + */ + std::unique_ptr> inertia_mat = section.inertia_matrix(); + + const libMesh::Point point(2.3, 3.1, 5.2); + const Real time = 2.34; + RealMatrixX D_sec_iner; + inertia_mat->operator()(point, time, D_sec_iner); + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_iner_true = RealMatrixX::Zero(6,6); + + + Real area; + const MAST::FieldFunction& Area = section.A(); + Area(point, time, area); + REQUIRE( area == Approx(area_true) ); + D_sec_iner_true(0,0) = D_sec_iner_true(1,1) = D_sec_iner_true(2,2) = area_true; + + Real Ip; + const MAST::FieldFunction& PolarInertia = section.Ip(); + PolarInertia(point, time, Ip); + CHECK( Ip == Approx(second_area_moment_polar_true) ); + D_sec_iner_true(3,3) = second_area_moment_polar_true; + + Real first_area_moment_y; + const MAST::FieldFunction& Ay = section.Ay(); + Ay(point, time, first_area_moment_y); + CHECK( first_area_moment_y == Approx(first_area_moment_y_true) ); + D_sec_iner_true(0,4) = D_sec_iner_true(4,0) = first_area_moment_y_true; + + Real first_area_moment_z; + const MAST::FieldFunction& Az = section.Az(); + Az(point, time, first_area_moment_z); + CHECK( first_area_moment_z == Approx(first_area_moment_z_true) ); + D_sec_iner_true(0,5) = D_sec_iner_true(5,0) = first_area_moment_z_true; + + RealMatrixX I; + const MAST::FieldFunction& Inertias = section.I(); + Inertias(point, time, I); + REQUIRE( I(0,1) == I(1,0) ); + Real Iyy = I(1,1); + Real Izz = I(0,0); + Real Izy = I(0,1); + REQUIRE( Izz == Approx(second_area_moment_zz_true) ); + REQUIRE( Iyy == Approx(second_area_moment_yy_true) ); + REQUIRE( Izy == Approx(second_area_moment_zy_true) ); + + D_sec_iner_true(4,4) = Iyy; // Should this be Izz? + D_sec_iner_true(4,5) = Izy; + D_sec_iner_true(5,4) = Izy; + D_sec_iner_true(5,5) = Izz; // Should this by Iyy? + + D_sec_iner_true *= rho(); + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_iner); + std::vector truth = eigen_matrix_to_std_vector(D_sec_iner_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } +} + + +TEST_CASE("L_element_property_card_constant_structural_1d", + "[structural],[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + + // Define Material Properties as MAST Parameters + MAST::Parameter rho("rho_param", 1420.5); // Density + MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity + MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio + MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity + MAST::Parameter k("k_param", 237.0); // Thermal Conductivity + MAST::Parameter alpha("alpha_param", 5.34e-05); // Coeff. of Thermal Exp. + + const Real G = E() / (2. * (1. + nu())); + + // Define Section Properties as MAST Parameters + MAST::Parameter DIM1("DIM1", 6.000); + MAST::Parameter DIM2("DIM2", 3.000); + MAST::Parameter DIM3("DIM3", 0.250); + MAST::Parameter DIM4("DIM4", 0.125); + + MAST::Parameter offset_y("offy_param", -0.918); // Section offset in y-direction + MAST::Parameter offset_z("offz_param", -0.347); // Section offset in z-direction + + // Define Sensitivity Parameters + std::vector sens_params = {&DIM1}; + uint n_s = sens_params.size(); + + // Create field functions to dsitribute these constant parameters throughout the model + // Section Property Field Functions + MAST::ConstantFieldFunction DIM1_f("DIM1", DIM1); + MAST::ConstantFieldFunction DIM2_f("DIM2", DIM2); + MAST::ConstantFieldFunction DIM3_f("DIM3", DIM3); + MAST::ConstantFieldFunction DIM4_f("DIM4", DIM4); + MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); + MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); + // Material Property Field Functions + MAST::ConstantFieldFunction rho_f("rho", rho); + MAST::ConstantFieldFunction E_f("E", E); + MAST::ConstantFieldFunction nu_f("nu", nu); + MAST::ConstantFieldFunction cp_f("cp", cp); + MAST::ConstantFieldFunction k_f("k_th", k); + MAST::ConstantFieldFunction alpha_f("alpha_expansion", alpha); + + // Initialize the material + MAST::IsotropicMaterialPropertyCard material; + + // Add the material property constant field functions to the material card + material.add(rho_f); + material.add(k_f); + material.add(cp_f); + material.add(E_f); + material.add(nu_f); + material.add(alpha_f); + + // Initialize the section + MAST::Solid1DLSectionElementPropertyCard section; + + // Add the section property constant field functions to the section card + section.add(DIM1_f); + section.add(DIM2_f); + section.add(DIM3_f); + section.add(DIM4_f); + + section.add(offsety_f); + section.add(offsetz_f); + + // Add the material card to the section card + section.set_material(material); + + // Specify a section orientation point and add it to the section. + RealVectorX orientation = RealVectorX::Zero(3); + orientation(1) = 1.0; + section.y_vector() = orientation; + + // Now initialize the section + section.init(*p_global_init); + + REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional + REQUIRE( section.depends_on(DIM1) ); + REQUIRE( section.depends_on(offset_y) ); + REQUIRE( section.depends_on(offset_z) ); + REQUIRE( section.depends_on(k) ); + REQUIRE( section.depends_on(cp) ); + REQUIRE( section.depends_on(rho) ); + + REQUIRE( section.if_isotropic() ); + + // True values + const Real area_true = 1.8437499999999953e+00; + const Real torsion_constant_true = 3.2287060106088283e-02; + const Real first_area_moment_z_true = -1.1769375000000033e+00; + const Real first_area_moment_y_true = 3.7664687499999960e+00; + const Real second_area_moment_zz_true = 1.6049689895833330e+00; + const Real second_area_moment_yy_true = 1.4607873559895838e+01; + const Real second_area_moment_zy_true = -3.6365401874999770e+00; + const Real second_area_moment_polar_true = 1.6212842549479170e+01; + const Real Izzc_true = 8.5368390271892014e-01; + const Real Iyyc_true = 6.9136162881797327e+00; + const Real Izyc_true = -1.2322563559321700e+00; + const Real Ipc_true = 7.7673001908986530e+00; + const Real warping_constant_true = 9.4267315264520590e-02; + const Real kappa_z_true = 6.9387531455434204e-01; + const Real kappa_y_true = 1.5217893373385735e-01; + const Real xs_true = -3.0393910943861346e-01; + const Real ys_true = -9.2444557187933163e-01; + const Real xst_true = -3.0393910943861346e-01; + const Real yst_true = -9.2444557187933163e-01; + const Real xc_true = 2.0428305084745793e+00; + const Real yc_true = -6.3833898305085091e-01; + const std::vector stress_points_true = { + libMesh::Point(-1.9803305084745793e+00, 3.5133389830508510e+00, 0.), + libMesh::Point(3.8946694915254207e+00, 5.1333898305085091e-01, 0.), + libMesh::Point(-2.1053305084745793e+00, 5.1333898305085091e-01, 0.), + libMesh::Point(-2.1053305084745793e+00, 3.5133389830508510e+00, 0.) + }; + + const libMesh::Point point(4.3, -3.5, -6.7); + const Real time = 8.22; + + SECTION("set_get_bending_model") + { + // NOTE: MAST::DKT and MAST::MINDLIN are not valid options for 1D sections, even though their input is accepted. + section.set_bending_model(MAST::BERNOULLI); + section.set_bending_model(MAST::DEFAULT_BENDING); + section.set_bending_model(MAST::NO_BENDING); + section.set_bending_model(MAST::TIMOSHENKO); + + // TODO: Implement element creation for testing of getting bending_model and checking default + //REQUIRE( section.bending_model() + } + +// SECTION("quadrature_order") +// { +// section.set_bending_model(MAST::MINDLIN); +// REQUIRE( section.extra_quadrature_order(elem) == 0 ); +// +// section.set_bending_model(MAST::DKT); +// REQUIRE( section.extra_quadrature_order(elem) == 2 ); +// } + + SECTION("1D extension stiffness matrix") + { + /** + * As of Dec. 17, 2019, stiffness_A_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * stiffness_A_matrix to be obtained without any input arguments. + */ + Real area; + const MAST::FieldFunction& Area = section.A(); + Area(point, time, area); + REQUIRE( area == Approx(area_true) ); + + Real torsion_constant; + const MAST::FieldFunction& TorsionConstant = section.J(); + TorsionConstant(point, time, torsion_constant); + REQUIRE( torsion_constant == Approx(torsion_constant_true).epsilon(0.05) ); + + std::unique_ptr> extension_stiffness_mat = section.stiffness_A_matrix(); + + const libMesh::Point point(2.3, 3.1, 5.2); + const Real time = 2.34; + RealMatrixX D_sec_ext; + extension_stiffness_mat->operator()(point, time, D_sec_ext); + + libMesh::out << "D_sec_ext\n" << D_sec_ext << std::endl; + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_ext_true = RealMatrixX::Zero(2,2); + D_sec_ext_true(0,0) = E() * area_true; + D_sec_ext_true(1,1) = G * torsion_constant_true; + + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_ext); + std::vector truth = eigen_matrix_to_std_vector(D_sec_ext_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth).epsilon(0.05) ); + } + + + SECTION("1D bending section stiffness matrix") + { + /** + * As of Dec. 17, 2019, stiffness_D_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * stiffness_D_matrix to be obtained without any input arguments. + */ + RealMatrixX I; + const MAST::FieldFunction& Inertias = section.I(); + Inertias(point, time, I); + REQUIRE( I(0,1) == I(1,0) ); + Real Izz = I(0,0); + Real Iyy = I(1,1); + Real Izy = I(0,1); + REQUIRE( Izz == Approx(second_area_moment_zz_true) ); + REQUIRE( Iyy == Approx(second_area_moment_yy_true) ); + REQUIRE( Izy == Approx(second_area_moment_zy_true) ); + + std::unique_ptr> bending_stiffness_mat = section.stiffness_D_matrix(); + + const libMesh::Point point(2.3, 3.1, 5.2); + const Real time = 2.34; + RealMatrixX D_sec_bnd; + bending_stiffness_mat->operator()(point, time, D_sec_bnd); + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_bnd_true = RealMatrixX::Zero(2,2); + D_sec_bnd_true(0,0) = E() * second_area_moment_zz_true; + D_sec_bnd_true(1,1) = E() * second_area_moment_yy_true; + D_sec_bnd_true(0,1) = E() * second_area_moment_zy_true; + D_sec_bnd_true(1,0) = E() * second_area_moment_zy_true; + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_bnd); + std::vector truth = eigen_matrix_to_std_vector(D_sec_bnd_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } + + SECTION("1D extension-bending section stiffness matrix") + { + /** + * As of Dec. 17, 2019, stiffness_B_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * stiffness_B_matrix to be obtained without any input arguments. + */ + Real first_area_moment_y; + const MAST::FieldFunction& Ay = section.Ay(); + Ay(point, time, first_area_moment_y); + CHECK( first_area_moment_y == Approx(first_area_moment_y_true) ); + + Real first_area_moment_z; + const MAST::FieldFunction& Az = section.Az(); + Az(point, time, first_area_moment_z); + CHECK( first_area_moment_z == Approx(first_area_moment_z_true) ); + + std::unique_ptr> bndext_stiffness_mat = section.stiffness_B_matrix(); + + const libMesh::Point point(2.3, 3.1, 5.2); + const Real time = 2.34; + RealMatrixX D_sec_bndext; + bndext_stiffness_mat->operator()(point, time, D_sec_bndext); + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_bndext_true = RealMatrixX::Zero(2,2); + D_sec_bndext_true(0,0) = E() * first_area_moment_z_true; + D_sec_bndext_true(0,1) = E() * first_area_moment_y_true; + // TODO: Add checks for torsion bending coupling when added to MAST. + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_bndext); + std::vector truth = eigen_matrix_to_std_vector(D_sec_bndext_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth) ); + } + + SECTION("1D transverse shear section stiffness matrix") + { + /** + * As of Dec. 17, 2019, transverse_shear_stiffness_matrix requires the input of an + * MAST::ElementBase object, but does not actually use it. To get + * around requiring the creation of such an object (and therefore + * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, + * and MAST::GeomElem objects as well). + * + * To remedy this, an additional method was added to MAST which allows + * transverse_shear_stiffness_matrix to be obtained without any input arguments. + */ + Real area; + const MAST::FieldFunction& Area = section.A(); + Area(point, time, area); + REQUIRE( area == Approx(area_true) ); + + std::unique_ptr> trans_shear_stiffness_mat = section.transverse_shear_stiffness_matrix(); + + const libMesh::Point point(2.3, 3.1, 5.2); + const Real time = 2.34; + RealMatrixX D_sec_shr; + trans_shear_stiffness_mat->operator()(point, time, D_sec_shr); + + // Hard-coded value of the section's extension stiffness + RealMatrixX D_sec_shr_true = RealMatrixX::Zero(2,2); + D_sec_shr_true(0,0) = G*area_true*kappa_z_true; + D_sec_shr_true(1,1) = G*area_true*kappa_y_true; + + // Convert the test and truth Eigen::Matrix objects to std::vector + // since Catch2 has built in methods to compare vectors + std::vector test = eigen_matrix_to_std_vector(D_sec_shr); + std::vector truth = eigen_matrix_to_std_vector(D_sec_shr_true); + + // Floating point approximations are diffcult to compare since the + // values typically aren't exactly equal due to numerical error. + // Therefore, we use the Approx comparison instead of Equals + CHECK_THAT( test, Catch::Approx(truth).epsilon(0.005) ); + } + + +// SECTION("1D spring section stiffness matrix") +// { +// /** +// * As of Dec. 17, 2019, spring_stiffness_matrix requires the input of an +// * MAST::ElementBase object, but does not actually use it. To get +// * around requiring the creation of such an object (and therefore +// * the creation of a MAST::SystemInitialization, MAST::AssemblyBase, +// * and MAST::GeomElem objects as well). +// * +// * To remedy this, an additional method was added to MAST which allows +// * transverse_shear_stiffness_matrix to be obtained without any input arguments. +// */ +// std::unique_ptr> spring_stiffness_mat = section.stiffness_S_matrix(); +// +// const libMesh::Point point(2.3, 3.1, 5.2); +// const Real time = 2.34; +// RealMatrixX D_sec_spring; +// spring_stiffness_mat->operator()(point, time, D_sec_spring); +// +// // Hard-coded value of the section's extension stiffness +// // NOTE: Should be all zero's for non-bushing sections +// RealMatrixX D_sec_spring_true = RealMatrixX::Zero(4,6); +// +// // Convert the test and truth Eigen::Matrix objects to std::vector +// // since Catch2 has built in methods to compare vectors +// std::vector test = eigen_matrix_to_std_vector(D_sec_spring); +// std::vector truth = eigen_matrix_to_std_vector(D_sec_spring_true); +// +// // Floating point approximations are diffcult to compare since the +// // values typically aren't exactly equal due to numerical error. +// // Therefore, we use the Approx comparison instead of Equals +// CHECK_THAT( test, Catch::Approx(truth) ); +// } +} From 00817d0686bb6e3b946a734d9f2fe327ecb85bf0 Mon Sep 17 00:00:00 2001 From: David John Neiferd <13425967+JohnDN90@users.noreply.github.com> Date: Wed, 4 Mar 2020 16:13:01 -0500 Subject: [PATCH 15/27] Set extra_quadrature_order for warping_only sections to -1. This reduces computational costs for warping systems. Refer to Robbie van Leeuwen paper. --- src/property_cards/element_property_card_2D.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/property_cards/element_property_card_2D.h b/src/property_cards/element_property_card_2D.h index bdf9a08b..dc4b0d14 100644 --- a/src/property_cards/element_property_card_2D.h +++ b/src/property_cards/element_property_card_2D.h @@ -58,10 +58,13 @@ namespace MAST /*! * returns the extra quadrature order (on top of the system) that * this element should use. This is elevated by two orders for a DKT - * element + * element and reduced by 1 order for warping analysis of a cross + * section */ virtual int extra_quadrature_order(const MAST::GeomElem& elem) const { - if (this->bending_model(elem) == MAST::DKT) + if ((this->_warping_only)) // May need to change this if quad elements are every supported in the future for warping + return -1; // Full integration for cross sectional property analysis for 1st or 2nd order triangles only requires 3 and 6 integrations points respectively. Defaults are 4 and 7 respectively. + else if (this->bending_model(elem) == MAST::DKT) return 2; else return 0; From 68319a927ce93dbb95ff6e361d63f0d619095d80 Mon Sep 17 00:00:00 2001 From: David John Neiferd <13425967+JohnDN90@users.noreply.github.com> Date: Thu, 5 Mar 2020 20:20:41 -0500 Subject: [PATCH 16/27] Refactored some material and property tests inline with J. Deaton's method. Created an Aluminum 7075-T6 and Titantium 6Al-4V materials for reuse in tests. Created an Aluminum 7075-T6 L cross section for reuse in L section tests. Created helper function to approximate field function derivatives via finite difference. --- tests/material/mast_isotropic_material.cpp | 64 +- tests/material/mast_isotropic_material.h | 84 ++ tests/property/CMakeLists.txt | 49 + ...lid_1d_L_section_element_property_card.cpp | 962 +++--------------- ...solid_1d_L_section_element_property_card.h | 96 ++ ...d_1d_bar_section_element_property_card.cpp | 64 +- tests/test_helpers.cpp | 55 + tests/test_helpers.h | 29 +- 8 files changed, 451 insertions(+), 952 deletions(-) create mode 100644 tests/material/mast_isotropic_material.h create mode 100644 tests/property/mast_solid_1d_L_section_element_property_card.h diff --git a/tests/material/mast_isotropic_material.cpp b/tests/material/mast_isotropic_material.cpp index 68ca5007..c6ed07e6 100644 --- a/tests/material/mast_isotropic_material.cpp +++ b/tests/material/mast_isotropic_material.cpp @@ -11,6 +11,7 @@ // Custom includes #include "test_helpers.h" +#include "mast_isotropic_material.h" // TODO: Need to test temperature dependent material property // TODO: Need to test stress dependent material property (plasticity) @@ -18,14 +19,10 @@ TEST_CASE("constant_isotropic_thermoelastic_material_1d", "[isotropic],[material],[constant],[1D],[thermoelastic]") { - MAST::Parameter alpha("alpha_param", 5.43e-05); // Coefficient of thermal expansion - MAST::ConstantFieldFunction alpha_f("alpha_expansion", alpha); // Initialize the material - MAST::IsotropicMaterialPropertyCard material; - - material.add(alpha_f); - + TEST::Aluminum7075T6 material; + REQUIRE( material.contains("alpha_expansion") ); SECTION("1D material thermal expansion matrix") @@ -40,7 +37,7 @@ TEST_CASE("constant_isotropic_thermoelastic_material_1d", // Hard-coded in the true value of material thermal expansion matrix RealMatrixX D_texp_true = RealMatrixX::Zero(2,1); - D_texp_true(0,0) = 5.43e-05; + D_texp_true(0,0) = material.alpha(); // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors @@ -58,20 +55,8 @@ TEST_CASE("constant_isotropic_thermoelastic_material_1d", TEST_CASE("constant_isotropic_structural_material_1d", "[isotropic],[material],[constant],[1D],[structural]") { - // Define Material Properties as MAST Parameters - MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity - MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio - - // Create field functions to dsitribute these constant parameters throughout the model - MAST::ConstantFieldFunction E_f("E", E); - MAST::ConstantFieldFunction nu_f("nu", nu); - // Initialize the material - MAST::IsotropicMaterialPropertyCard material; - - // Add the material property constant field functions to the material card - material.add(E_f); - material.add(nu_f); + TEST::Aluminum7075T6 material; // Ensure that the material properties were added before doing other checks REQUIRE( material.contains("E") ); @@ -89,8 +74,8 @@ TEST_CASE("constant_isotropic_structural_material_1d", // Hard-code in the true value of the material stiffness RealMatrixX D_true = RealMatrixX::Zero(2,2); - D_true(0,0) = 72.0e9; - D_true(1,1) = 2.706766917293233e+10; + D_true(0,0) = material.E(); + D_true(1,1) = material.G(); // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors @@ -108,24 +93,15 @@ TEST_CASE("constant_isotropic_structural_material_1d", TEST_CASE("constant_isotropic_heat_transfer_material_1d", "[isotropic],[material],[1D],[heat_transfer][constant]") { - // Define Material Properties as MAST Parameters - MAST::Parameter k("k_param", 237.0); // Thermal Conductivity - - // Create field functions to dsitribute these constant parameters throughout the model - MAST::ConstantFieldFunction k_f("k_th", k); - // Initialize the material - MAST::IsotropicMaterialPropertyCard material; - - // Add the material property constant field functions to the material card - material.add(k_f); + TEST::Aluminum7075T6 material; // Ensure that the material properties were added before doing other checks REQUIRE( material.contains("k_th") ); SECTION("material depends on the parameters that it should") { - CHECK( material.depends_on(k) ); + CHECK( material.depends_on(material.k) ); } SECTION("material does not depend on other parameters") @@ -146,7 +122,7 @@ TEST_CASE("constant_isotropic_heat_transfer_material_1d", // Hard-coded values for thermal conductivity matrix RealMatrixX D_k_true = RealMatrixX::Identity(1,1); - D_k_true *= 237.0; + D_k_true *= material.k(); // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors @@ -164,20 +140,8 @@ TEST_CASE("constant_isotropic_heat_transfer_material_1d", TEST_CASE("constant_isotropic_transient_heat_transfer_material_1d", "[isotropic],[material],[1D],[heat_transfer],[constant],[transient]") { - // Define Material Properties as MAST Parameters - MAST::Parameter rho("rho_param", 1234.5); // Density - MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity - - // Create field functions to dsitribute these constant parameters throughout the model - MAST::ConstantFieldFunction rho_f("rho", rho); - MAST::ConstantFieldFunction cp_f("cp", cp); - // Initialize the material - MAST::IsotropicMaterialPropertyCard material; - - // Add the material property constant field functions to the material card - material.add(rho_f); - material.add(cp_f); + TEST::Aluminum7075T6 material; // Ensure that the material properties were added before doing other checks REQUIRE( material.contains("rho") ); @@ -185,8 +149,8 @@ TEST_CASE("constant_isotropic_transient_heat_transfer_material_1d", SECTION("material depends on the parameters that it should") { - CHECK( material.depends_on(rho) ); - CHECK( material.depends_on(cp) ); + CHECK( material.depends_on(material.rho) ); + CHECK( material.depends_on(material.cp) ); } SECTION("material does not depend on other parameters") @@ -207,7 +171,7 @@ TEST_CASE("constant_isotropic_transient_heat_transfer_material_1d", // Hard-coded values for thermal conductivity matrix RealMatrixX D_cp_true = RealMatrixX::Identity(1,1); - D_cp_true *= (908.0 * 1234.5); + D_cp_true *= material.rho() * material.cp(); // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors diff --git a/tests/material/mast_isotropic_material.h b/tests/material/mast_isotropic_material.h new file mode 100644 index 00000000..bc12a86a --- /dev/null +++ b/tests/material/mast_isotropic_material.h @@ -0,0 +1,84 @@ +#ifndef MAST_ISOTROPIC_MATERIAL_H_INCLUDED +#define MAST_ISOTROPIC_MATERIAL_H_INCLUDED + +#include "property_cards/isotropic_material_property_card.h" + + +namespace TEST +{ + class Aluminum7075T6 : public MAST::IsotropicMaterialPropertyCard + { + public: + Aluminum7075T6(): + E("E_param", 71.7e9), nu("nu_param", 0.33), rho("rho_param", 2810.0), + alpha("alpha_param", 2.52e-05), cp("cp_param", 960.0), + k("k_param", 130.0), E_f("E", E), nu_f("nu", nu), rho_f("rho", rho), + alpha_f("alpha_expansion", alpha), cp_f("cp", cp), k_f("k_th", k) + { + add(E_f); + add(nu_f); + add(rho_f); + add(alpha_f); + add(cp_f); + add(k_f); + } + + Real G() + { + return E() / (2.0 * (1.0 + nu())); + }; + + MAST::Parameter E; + MAST::Parameter nu; + MAST::Parameter rho; + MAST::Parameter alpha; + MAST::Parameter cp; + MAST::Parameter k; + + MAST::ConstantFieldFunction E_f; + MAST::ConstantFieldFunction nu_f; + MAST::ConstantFieldFunction rho_f; + MAST::ConstantFieldFunction alpha_f; + MAST::ConstantFieldFunction cp_f; + MAST::ConstantFieldFunction k_f; + }; + + + class Titanium6Al4V : public MAST::IsotropicMaterialPropertyCard + { + public: + Titanium6Al4V(): + E("E_param", 113.8e9), nu("nu_param", 0.342), rho("rho_param", 4430), + alpha("alpha_param", 9.7e-06), cp("cp_param", 526.3), + k("k_param", 6.7), E_f("E", E), nu_f("nu", nu), rho_f("rho", rho), + alpha_f("alpha_expansion", alpha), cp_f("cp", cp), k_f("k_th", k) + { + add(E_f); + add(nu_f); + add(rho_f); + add(alpha_f); + add(cp_f); + add(k_f); + } + + Real G() + { + return E() / (2.0 * (1.0 + nu())); + }; + + MAST::Parameter E; + MAST::Parameter nu; + MAST::Parameter rho; + MAST::Parameter alpha; + MAST::Parameter cp; + MAST::Parameter k; + + MAST::ConstantFieldFunction E_f; + MAST::ConstantFieldFunction nu_f; + MAST::ConstantFieldFunction rho_f; + MAST::ConstantFieldFunction alpha_f; + MAST::ConstantFieldFunction cp_f; + MAST::ConstantFieldFunction k_f; + }; +} +#endif // MAST_ISOTROPIC_MATERIAL_H_INCLUDED diff --git a/tests/property/CMakeLists.txt b/tests/property/CMakeLists.txt index c6645b55..9e819184 100644 --- a/tests/property/CMakeLists.txt +++ b/tests/property/CMakeLists.txt @@ -758,12 +758,40 @@ set_tests_properties(L_Element_Property_Card_1D_Base LABELS "SEQ" FIXTURES_REQUIRED Isotropic_Material_1D_Structural) +add_test(NAME L_Element_Property_Card_1D_Base_mpi + COMMAND ${MPIEXEC_EXECUTABLE} -np 2 $ -w NoTests "L_element_property_card_constant_base_1d") +set_tests_properties(L_Element_Property_Card_1D_Base_mpi + PROPERTIES + LABELS "MPI" + FIXTURES_REQUIRED Isotropic_Material_1D_Structural_mpi) + +add_test(NAME L_Element_Property_Card_1D_Base_Sensitivity + COMMAND $ -w NoTests "L_element_property_card_constant_base_sensitivity_1d") +set_tests_properties(L_Element_Property_Card_1D_Base_Sensitivity + PROPERTIES + LABELS "SEQ" + FIXTURES_REQUIRED L_Element_Property_Card_1D_Base) + +add_test(NAME L_Element_Property_Card_1D_Base_Sensitivity_mpi + COMMAND ${MPIEXEC_EXECUTABLE} -np 2 $ -w NoTests "L_element_property_card_constant_base_sensitivity_1d") +set_tests_properties(L_Element_Property_Card_1D_Base_Sensitivity_mpi + PROPERTIES + LABELS "MPI" + FIXTURES_REQUIRED L_Element_Property_Card_1D_Base_mpi) + add_test(NAME L_Element_Property_Card_1D_Heat_Transfer COMMAND $ -w NoTests "L_element_property_card_constant_heat_transfer_1d") set_tests_properties(L_Element_Property_Card_1D_Heat_Transfer PROPERTIES LABELS "SEQ" FIXTURES_REQUIRED Isotropic_Material_1D_Heat_Transfer) + +add_test(NAME L_Element_Property_Card_1D_Heat_Transfer_mpi + COMMAND ${MPIEXEC_EXECUTABLE} -np 2 $ -w NoTests "L_element_property_card_constant_heat_transfer_1d") +set_tests_properties(L_Element_Property_Card_1D_Heat_Transfer_mpi + PROPERTIES + LABELS "MPI" + FIXTURES_REQUIRED Isotropic_Material_1D_Heat_Transfer_mpi) add_test(NAME L_Element_Property_Card_1D_Thermoelastic COMMAND $ -w NoTests "L_element_property_card_constant_thermoelastic_1d") @@ -772,6 +800,13 @@ set_tests_properties(L_Element_Property_Card_1D_Thermoelastic LABELS "SEQ" FIXTURES_REQUIRED Isotropic_Material_1D_Thermoelastic) +add_test(NAME L_Element_Property_Card_1D_Thermoelastic_mpi + COMMAND ${MPIEXEC_EXECUTABLE} -np 2 $ -w NoTests "L_element_property_card_constant_thermoelastic_1d") +set_tests_properties(L_Element_Property_Card_1D_Thermoelastic_mpi + PROPERTIES + LABELS "MPI" + FIXTURES_REQUIRED Isotropic_Material_1D_Thermoelastic_mpi) + add_test(NAME L_Element_Property_Card_1D_Structural COMMAND $ -w NoTests "L_element_property_card_constant_structural_1d") set_tests_properties(L_Element_Property_Card_1D_Structural @@ -779,10 +814,24 @@ set_tests_properties(L_Element_Property_Card_1D_Structural LABELS "SEQ" FIXTURES_REQUIRED Isotropic_Material_1D_Structural) +add_test(NAME L_Element_Property_Card_1D_Structural_mpi + COMMAND ${MPIEXEC_EXECUTABLE} -np 2 $ -w NoTests "L_element_property_card_constant_structural_1d") +set_tests_properties(L_Element_Property_Card_1D_Structural_mpi + PROPERTIES + LABELS "MPI" + FIXTURES_REQUIRED Isotropic_Material_1D_Structural_mpi) + add_test(NAME L_Element_Property_Card_1D_Dynamic COMMAND $ -w NoTests "L_element_property_card_constant_dynamic_1d") set_tests_properties(L_Element_Property_Card_1D_Dynamic PROPERTIES LABELS "SEQ" FIXTURES_REQUIRED Isotropic_Material_1D_Dynamic) + +add_test(NAME L_Element_Property_Card_1D_Dynamic_mpi + COMMAND ${MPIEXEC_EXECUTABLE} -np 2 $ -w NoTests "L_element_property_card_constant_dynamic_1d") +set_tests_properties(L_Element_Property_Card_1D_Dynamic_mpi + PROPERTIES + LABELS "MPI" + FIXTURES_REQUIRED Isotropic_Material_1D_Dynamic_mpi) # ## ============================================================================ diff --git a/tests/property/mast_solid_1d_L_section_element_property_card.cpp b/tests/property/mast_solid_1d_L_section_element_property_card.cpp index 3f50d99e..dd58215b 100644 --- a/tests/property/mast_solid_1d_L_section_element_property_card.cpp +++ b/tests/property/mast_solid_1d_L_section_element_property_card.cpp @@ -12,138 +12,37 @@ // Custom includes #include "test_helpers.h" +#include "material/mast_isotropic_material.h" +#include "mast_solid_1d_L_section_element_property_card.h" extern libMesh::LibMeshInit* p_global_init; -#define PI 3.1415926535897932 -/** - * A BAR is defined as a solid rectangular cross section defined by two - * parameters. - */ TEST_CASE("L_element_property_card_constant_base_1d", - "[1D],[isotropic],[constant],[property]") + "[1D][isotropic][constant][property]") { const uint dim = 1; - - // Define Material Properties as MAST Parameters - MAST::Parameter rho("rho_param", 1420.5); // Density - MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity - MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio - MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity - MAST::Parameter k("k_param", 237.0); // Thermal Conductivity - MAST::Parameter alpha("alpha_param", 5.34e-05); // Coeff. of Thermal Exp. - - const Real G = E() / (2. * (1. + nu())); + const uint n_target_elems = 3500; // 14657 - // Define Section Properties as MAST Parameters - MAST::Parameter DIM1("DIM1", 6.000); - MAST::Parameter DIM2("DIM2", 3.000); - MAST::Parameter DIM3("DIM3", 0.250); - MAST::Parameter DIM4("DIM4", 0.125); - - MAST::Parameter offset_y("offy_param", -0.918); // Section offset in y-direction - MAST::Parameter offset_z("offz_param", -0.347); // Section offset in z-direction - - // Define Sensitivity Parameters - std::vector sens_params = {&DIM1}; - uint n_s = sens_params.size(); - - // Create field functions to dsitribute these constant parameters throughout the model - // Section Property Field Functions - MAST::ConstantFieldFunction DIM1_f("DIM1", DIM1); - MAST::ConstantFieldFunction DIM2_f("DIM2", DIM2); - MAST::ConstantFieldFunction DIM3_f("DIM3", DIM3); - MAST::ConstantFieldFunction DIM4_f("DIM4", DIM4); - MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); - MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); - // Material Property Field Functions - MAST::ConstantFieldFunction rho_f("rho", rho); - MAST::ConstantFieldFunction E_f("E", E); - MAST::ConstantFieldFunction nu_f("nu", nu); - MAST::ConstantFieldFunction cp_f("cp", cp); - MAST::ConstantFieldFunction k_f("k_th", k); - MAST::ConstantFieldFunction alpha_f("alpha_expansion", alpha); - - // Initialize the material - MAST::IsotropicMaterialPropertyCard material; - - // Add the material property constant field functions to the material card - material.add(rho_f); - material.add(k_f); - material.add(cp_f); - material.add(E_f); - material.add(nu_f); - material.add(alpha_f); - - // Initialize the section - MAST::Solid1DLSectionElementPropertyCard section; - - // Add the section property constant field functions to the section card - section.add(DIM1_f); - section.add(DIM2_f); - section.add(DIM3_f); - section.add(DIM4_f); - - section.add(offsety_f); - section.add(offsetz_f); - - // Add the material card to the section card - section.set_material(material); - - // Specify a section orientation point and add it to the section. - RealVectorX orientation = RealVectorX::Zero(3); - orientation(1) = 1.0; - section.y_vector() = orientation; - - // Now initialize the section - section.init(*p_global_init, 14657); + TEST::AluminumLSection section(n_target_elems); REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional - REQUIRE( section.depends_on(DIM1) ); - REQUIRE( section.depends_on(DIM2) ); - REQUIRE( section.depends_on(DIM3) ); - REQUIRE( section.depends_on(DIM4) ); - REQUIRE( section.depends_on(offset_y) ); - REQUIRE( section.depends_on(offset_z) ); - REQUIRE( section.depends_on(k) ); - REQUIRE( section.depends_on(cp) ); - REQUIRE( section.depends_on(rho) ); + REQUIRE( section.depends_on(section.DIM1) ); + REQUIRE( section.depends_on(section.DIM2) ); + REQUIRE( section.depends_on(section.DIM3) ); + REQUIRE( section.depends_on(section.DIM4) ); - REQUIRE( section.if_isotropic() ); + REQUIRE( section.depends_on(section.offset_y) ); + REQUIRE( section.depends_on(section.offset_z) ); - // True values - const Real area_true = 1.8437500000000016e+00; - const Real torsion_constant_true = 3.2286682945239953e-02; - const Real first_area_moment_z_true = -1.1769375000000004e+00; - const Real first_area_moment_y_true = 3.7664687499999974e+00; - const Real second_area_moment_zz_true = 1.6049689895833241e+00; - const Real second_area_moment_yy_true = 1.4607873559895829e+01; - const Real second_area_moment_zy_true = -3.6365401874999983e+00; - const Real second_area_moment_polar_true = 1.6212842549479152e+01; - const Real Izzc_true = 8.5368390271891748e-01; - const Real Iyyc_true = 6.9136162881797452e+00; - const Real Izyc_true = -1.2322563559322042e+00; - const Real Ipc_true = 7.7673001908986627e+00; - const Real warping_constant_true = 9.4267903516538354e-02; - const Real kappa_z_true = 6.9387360587828650e-01; - const Real kappa_y_true = 1.5217240110756519e-01; - const Real xs_true = -3.0394644727391729e-01; - const Real ys_true = -9.2444644346018534e-01; - const Real xst_true = -3.0394644727391729e-01; - const Real yst_true = -9.2444644346018534e-01; - const Real xc_true = 2.0428305084745730e+00; - const Real yc_true = -6.3833898305084713e-01; - const std::vector stress_points_true = { - libMesh::Point(-1.9803305084745730e+00, 3.5133389830508470e+00, 0.), - libMesh::Point(3.8946694915254270e+00, 5.1333898305084713e-01, 0.), - libMesh::Point(-2.1053305084745730e+00, 5.1333898305084713e-01, 0.), - libMesh::Point(-2.1053305084745730e+00, 3.5133389830508470e+00, 0.) - }; - + REQUIRE( section.depends_on(section.material.k) ); + REQUIRE( section.depends_on(section.material.cp) ); + REQUIRE( section.depends_on(section.material.rho) ); + REQUIRE( section.depends_on(section.material.E) ); + REQUIRE( section.depends_on(section.material.nu) ); + REQUIRE( section.depends_on(section.material.alpha) ); - const libMesh::Point centroid_true(xc_true, yc_true); - const libMesh::Point shear_center_true(xs_true, ys_true); + REQUIRE( section.if_isotropic() ); const libMesh::Point point(4.3, -3.5, -6.7); const Real time = 8.22; @@ -153,17 +52,17 @@ TEST_CASE("L_element_property_card_constant_base_1d", Real area; const MAST::FieldFunction& Area = section.A(); Area(point, time, area); - CHECK( area == Approx(area_true) ); + CHECK( area == Approx(section.area_true) ); Real first_area_moment_y; const MAST::FieldFunction& Ay = section.Ay(); Ay(point, time, first_area_moment_y); - CHECK( first_area_moment_y == Approx(first_area_moment_y_true) ); + CHECK( first_area_moment_y == Approx(section.first_area_moment_y_true) ); Real first_area_moment_z; const MAST::FieldFunction& Az = section.Az(); Az(point, time, first_area_moment_z); - CHECK( first_area_moment_z == Approx(first_area_moment_z_true) ); + CHECK( first_area_moment_z == Approx(section.first_area_moment_z_true) ); RealMatrixX I; const MAST::FieldFunction& Inertias = section.I(); @@ -172,26 +71,24 @@ TEST_CASE("L_element_property_card_constant_base_1d", Real Iyy = I(1,1); Real Izz = I(0,0); Real Izy = I(0,1); - CHECK( Izz == Approx(second_area_moment_zz_true) ); - CHECK( Iyy == Approx(second_area_moment_yy_true) ); - CHECK( Izy == Approx(second_area_moment_zy_true) ); + CHECK( Izz == Approx(section.second_area_moment_zz_true) ); + CHECK( Iyy == Approx(section.second_area_moment_yy_true) ); + CHECK( Izy == Approx(section.second_area_moment_zy_true) ); Real Ip; const MAST::FieldFunction& PolarInertia = section.Ip(); PolarInertia(point, time, Ip); - CHECK( Ip == Approx(second_area_moment_polar_true) ); + CHECK( Ip == Approx(section.second_area_moment_polar_true) ); Real torsion_constant; const MAST::FieldFunction& TorsionConstant = section.J(); TorsionConstant(point, time, torsion_constant); - CHECK( torsion_constant == Approx(torsion_constant_true).epsilon(0.005)); + CHECK( torsion_constant == Approx(section.torsion_constant_true).epsilon(0.005)); libMesh::Point centroid = section.get_centroid(point, time); - CHECK( centroid(0) == Approx(centroid_true(0)) ); - CHECK( centroid(1) == Approx(centroid_true(1)) ); - - libMesh::out << "Centroid = " << centroid << std::endl; - + CHECK( centroid(0) == Approx(section.centroid_true(0)) ); + CHECK( centroid(1) == Approx(section.centroid_true(1)) ); + const std::vector geom_points = section.get_geom_points(point, time); for (const auto& point : geom_points) { @@ -199,37 +96,36 @@ TEST_CASE("L_element_property_card_constant_base_1d", } libMesh::Point shear_center = section.get_shear_center(point, time); - CHECK(shear_center(0) == Approx(xs_true).epsilon(0.005)); - CHECK(shear_center(1) == Approx(ys_true).epsilon(0.005)); + CHECK(shear_center(0) == Approx(section.xs_true).epsilon(0.005)); + CHECK(shear_center(1) == Approx(section.ys_true).epsilon(0.005)); RealMatrixX shear_coefficients; const MAST::FieldFunction& ShearCoefficientMatrix = section.Kap(); ShearCoefficientMatrix(point, time, shear_coefficients); - CHECK( shear_coefficients(0,0) == Approx(kappa_z_true).epsilon(0.005) ); - CHECK( shear_coefficients(1,1) == Approx(kappa_y_true).epsilon(0.005) ); + CHECK( shear_coefficients(0,0) == Approx(section.kappa_z_true).epsilon(0.005) ); + CHECK( shear_coefficients(1,1) == Approx(section.kappa_y_true).epsilon(0.005) ); Real warping_constant; const MAST::FieldFunction& WarpingConstant = section.Gam(); WarpingConstant(point, time, warping_constant); - CHECK( warping_constant == Approx(warping_constant_true).epsilon(0.005) ); + CHECK( warping_constant == Approx(section.warping_constant_true).epsilon(0.005) ); } SECTION("stress_points") { libMesh::Point centroid = section.get_centroid(point, time); - CHECK( centroid(0) == Approx(centroid_true(0)) ); - CHECK( centroid(1) == Approx(centroid_true(1)) ); + CHECK( centroid(0) == Approx(section.centroid_true(0)) ); + CHECK( centroid(1) == Approx(section.centroid_true(1)) ); std::vector stress_points = section.get_stress_points(point, time, centroid); for (uint i=0; i sens_params = {&DIM1, &DIM2, &DIM3, &DIM4, &offset_y, &offset_z}; + std::vector sens_params = {§ion.DIM1}; uint n_s = sens_params.size(); - // Create field functions to dsitribute these constant parameters throughout the model - // Section Property Field Functions - MAST::ConstantFieldFunction DIM1_f("DIM1", DIM1); - MAST::ConstantFieldFunction DIM2_f("DIM2", DIM2); - MAST::ConstantFieldFunction DIM3_f("DIM3", DIM3); - MAST::ConstantFieldFunction DIM4_f("DIM4", DIM4); - MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); - MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); - // Material Property Field Functions - MAST::ConstantFieldFunction rho_f("rho", rho); - MAST::ConstantFieldFunction E_f("E", E); - MAST::ConstantFieldFunction nu_f("nu", nu); - MAST::ConstantFieldFunction cp_f("cp", cp); - MAST::ConstantFieldFunction k_f("k_th", k); - MAST::ConstantFieldFunction alpha_f("alpha_expansion", alpha); - - // Initialize the material - MAST::IsotropicMaterialPropertyCard material; - - // Add the material property constant field functions to the material card - material.add(rho_f); - material.add(k_f); - material.add(cp_f); - material.add(E_f); - material.add(nu_f); - material.add(alpha_f); - - // Initialize the section - MAST::Solid1DLSectionElementPropertyCard section; - - // Add the section property constant field functions to the section card - section.add(DIM1_f); - section.add(DIM2_f); - section.add(DIM3_f); - section.add(DIM4_f); - - section.add(offsety_f); - section.add(offsetz_f); - - // Add the material card to the section card - section.set_material(material); - - // Specify a section orientation point and add it to the section. - RealVectorX orientation = RealVectorX::Zero(3); - orientation(1) = 1.0; - section.y_vector() = orientation; - - // Now initialize the section - section.init(*p_global_init); - - REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional - REQUIRE( section.depends_on(DIM1) ); - REQUIRE( section.depends_on(offset_y) ); - REQUIRE( section.depends_on(offset_z) ); - REQUIRE( section.depends_on(k) ); - REQUIRE( section.depends_on(cp) ); - REQUIRE( section.depends_on(rho) ); - REQUIRE( section.if_isotropic() ); - // True values - const Real area_true = 1.8437499999999953e+00; - const Real torsion_constant_true = 3.2287060106088283e-02; - const Real first_area_moment_z_true = -1.1769375000000033e+00; - const Real first_area_moment_y_true = 3.7664687499999960e+00; - const Real second_area_moment_zz_true = 1.6049689895833330e+00; - const Real second_area_moment_yy_true = 1.4607873559895838e+01; - const Real second_area_moment_zy_true = -3.6365401874999770e+00; - const Real second_area_moment_polar_true = 1.6212842549479170e+01; - const Real Izzc_true = 8.5368390271892014e-01; - const Real Iyyc_true = 6.9136162881797327e+00; - const Real Izyc_true = -1.2322563559321700e+00; - const Real Ipc_true = 7.7673001908986530e+00; - const Real warping_constant_true = 9.4267315264520590e-02; - const Real kappa_z_true = 6.9387531455434204e-01; - const Real kappa_y_true = 1.5217893373385735e-01; - const Real xs_true = -3.0393910943861346e-01; - const Real ys_true = -9.2444557187933163e-01; - const Real xst_true = -3.0393910943861346e-01; - const Real yst_true = -9.2444557187933163e-01; - const Real xc_true = 2.0428305084745793e+00; - const Real yc_true = -6.3833898305085091e-01; - const std::vector stress_points_true = { - libMesh::Point(-1.9803305084745793e+00, 3.5133389830508510e+00, 0.), - libMesh::Point(3.8946694915254207e+00, 5.1333898305085091e-01, 0.), - libMesh::Point(-2.1053305084745793e+00, 5.1333898305085091e-01, 0.), - libMesh::Point(-2.1053305084745793e+00, 3.5133389830508510e+00, 0.) - }; - const libMesh::Point point(4.3, -3.5, -6.7); const Real time = 8.22; @@ -398,23 +190,9 @@ TEST_CASE("L_element_property_card_constant_base_sensitivity_1d", std::vector dA_cd(n_s); for (uint i=0; iname() << " = " << dA[i] << "\tdA_cd = " << dA_cd[i] << std::endl; + //libMesh::out << "dA_d" << sens_params[i]->name() << " = " << dA[i] << "\tdA_cd = " << dA_cd[i] << std::endl; REQUIRE(dA[i] == Approx(dA_cd[i])); } @@ -462,21 +240,7 @@ TEST_CASE("L_element_property_card_constant_base_sensitivity_1d", std::vector dAy_cd(n_s); for (uint i=0; iname() << " = " << dAy[i] << "\tdAy_cd = " << dAy_cd[i] << std::endl; REQUIRE(dAy[i] == Approx(dAy_cd[i])); @@ -493,21 +257,7 @@ TEST_CASE("L_element_property_card_constant_base_sensitivity_1d", std::vector dAz_cd(n_s); for (uint i=0; iname() << " = " << dAz[i] << "\tdAz_cd = " << dAz_cd[i] << std::endl; REQUIRE(dAz[i] == Approx(dAz_cd[i])); @@ -525,21 +275,7 @@ TEST_CASE("L_element_property_card_constant_base_sensitivity_1d", std::vector dI_cd(n_s); for (uint i=0; iname() << " =\n" << dI[i] << "\ndI_cd = \n" << dI_cd[i] << std::endl; @@ -572,21 +308,7 @@ TEST_CASE("L_element_property_card_constant_base_sensitivity_1d", std::vector dIp_cd(n_s); for (uint i=0; iname() << " = " << dIp[i] << "\tdIp_cd = " << dIp_cd[i] << std::endl; REQUIRE(dIp[i] == Approx(dIp_cd[i])); @@ -637,21 +359,7 @@ TEST_CASE("L_element_property_card_constant_base_sensitivity_1d", std::vector dJ_cd(n_s); for (uint i=0; iname() << " = " << dJ[i] << "\tdJ_cd = " << dJ_cd[i] << std::endl; REQUIRE(dJ[i] == Approx(dJ_cd[i]).epsilon(0.1) ); @@ -671,21 +379,7 @@ TEST_CASE("L_element_property_card_constant_base_sensitivity_1d", std::vector dK_cd(n_s); for (uint i=0; iname() << " =\n" << dK[i] << "\ndK_cd = \n" << dK_cd[i] << std::endl; @@ -720,21 +414,7 @@ TEST_CASE("L_element_property_card_constant_base_sensitivity_1d", std::vector dW_cd(n_s); for (uint i=0; iname() << " = " << dW[i] << "\tdW_cd = " << dW_cd[i] << std::endl; REQUIRE(dW[i] == Approx(dW_cd[i]).epsilon(0.1) ); @@ -747,126 +427,27 @@ TEST_CASE("L_element_property_card_constant_heat_transfer_1d", "[heat_transfer],[1D],[isotropic],[constant],[property]") { const uint dim = 1; - - // Define Material Properties as MAST Parameters - MAST::Parameter rho("rho_param", 1420.5); // Density - MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity - MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio - MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity - MAST::Parameter k("k_param", 237.0); // Thermal Conductivity - MAST::Parameter alpha("alpha_param", 5.34e-05); // Coeff. of Thermal Exp. - - const Real G = E() / (2. * (1. + nu())); + const uint n_target_elems = 3500; - // Define Section Properties as MAST Parameters - MAST::Parameter DIM1("DIM1", 6.000); - MAST::Parameter DIM2("DIM2", 3.000); - MAST::Parameter DIM3("DIM3", 0.250); - MAST::Parameter DIM4("DIM4", 0.125); - - MAST::Parameter offset_y("offy_param", -0.918); // Section offset in y-direction - MAST::Parameter offset_z("offz_param", -0.347); // Section offset in z-direction - - // Define Sensitivity Parameters - std::vector sens_params = {&DIM1}; - uint n_s = sens_params.size(); - - // Create field functions to dsitribute these constant parameters throughout the model - // Section Property Field Functions - MAST::ConstantFieldFunction DIM1_f("DIM1", DIM1); - MAST::ConstantFieldFunction DIM2_f("DIM2", DIM2); - MAST::ConstantFieldFunction DIM3_f("DIM3", DIM3); - MAST::ConstantFieldFunction DIM4_f("DIM4", DIM4); - MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); - MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); - // Material Property Field Functions - MAST::ConstantFieldFunction rho_f("rho", rho); - MAST::ConstantFieldFunction E_f("E", E); - MAST::ConstantFieldFunction nu_f("nu", nu); - MAST::ConstantFieldFunction cp_f("cp", cp); - MAST::ConstantFieldFunction k_f("k_th", k); - MAST::ConstantFieldFunction alpha_f("alpha_expansion", alpha); - - // Initialize the material - MAST::IsotropicMaterialPropertyCard material; - - // Add the material property constant field functions to the material card - material.add(rho_f); - material.add(k_f); - material.add(cp_f); - material.add(E_f); - material.add(nu_f); - material.add(alpha_f); - - // Initialize the section - MAST::Solid1DLSectionElementPropertyCard section; - - // Add the section property constant field functions to the section card - section.add(DIM1_f); - section.add(DIM2_f); - section.add(DIM3_f); - section.add(DIM4_f); - - section.add(offsety_f); - section.add(offsetz_f); - - // Add the material card to the section card - section.set_material(material); - - // Specify a section orientation point and add it to the section. - RealVectorX orientation = RealVectorX::Zero(3); - orientation(1) = 1.0; - section.y_vector() = orientation; - - // Now initialize the section - section.init(*p_global_init); + TEST::AluminumLSection section(n_target_elems); REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional - REQUIRE( section.depends_on(DIM1) ); - REQUIRE( section.depends_on(offset_y) ); - REQUIRE( section.depends_on(offset_z) ); - REQUIRE( section.depends_on(k) ); - REQUIRE( section.depends_on(cp) ); - REQUIRE( section.depends_on(rho) ); + REQUIRE( section.depends_on(section.DIM1) ); + REQUIRE( section.depends_on(section.offset_y) ); + REQUIRE( section.depends_on(section.offset_z) ); + REQUIRE( section.depends_on(section.material.k) ); + REQUIRE( section.depends_on(section.material.cp) ); + REQUIRE( section.depends_on(section.material.rho) ); REQUIRE( section.if_isotropic() ); - // True values - const Real area_true = 1.8437499999999953e+00; - const Real torsion_constant_true = 3.2287060106088283e-02; - const Real first_area_moment_z_true = -1.1769375000000033e+00; - const Real first_area_moment_y_true = 3.7664687499999960e+00; - const Real second_area_moment_zz_true = 1.6049689895833330e+00; - const Real second_area_moment_yy_true = 1.4607873559895838e+01; - const Real second_area_moment_zy_true = -3.6365401874999770e+00; - const Real second_area_moment_polar_true = 1.6212842549479170e+01; - const Real Izzc_true = 8.5368390271892014e-01; - const Real Iyyc_true = 6.9136162881797327e+00; - const Real Izyc_true = -1.2322563559321700e+00; - const Real Ipc_true = 7.7673001908986530e+00; - const Real warping_constant_true = 9.4267315264520590e-02; - const Real kappa_z_true = 6.9387531455434204e-01; - const Real kappa_y_true = 1.5217893373385735e-01; - const Real xs_true = -3.0393910943861346e-01; - const Real ys_true = -9.2444557187933163e-01; - const Real xst_true = -3.0393910943861346e-01; - const Real yst_true = -9.2444557187933163e-01; - const Real xc_true = 2.0428305084745793e+00; - const Real yc_true = -6.3833898305085091e-01; - const std::vector stress_points_true = { - libMesh::Point(-1.9803305084745793e+00, 3.5133389830508510e+00, 0.), - libMesh::Point(3.8946694915254207e+00, 5.1333898305085091e-01, 0.), - libMesh::Point(-2.1053305084745793e+00, 5.1333898305085091e-01, 0.), - libMesh::Point(-2.1053305084745793e+00, 3.5133389830508510e+00, 0.) - }; - const libMesh::Point point(4.3, -3.5, -6.7); const Real time = 8.22; Real area; const MAST::FieldFunction& Area = section.A(); Area(point, time, area); - REQUIRE( area == Approx(area_true) ); + REQUIRE( area == Approx(section.area_true) ); SECTION("1D section thermal conductance matrix") @@ -890,7 +471,7 @@ TEST_CASE("L_element_property_card_constant_heat_transfer_1d", // Hard-coded value of the section's extension stiffness RealMatrixX D_sec_conduc_true = RealMatrixX::Zero(1,1); - D_sec_conduc_true(0,0) = k() * area_true; + D_sec_conduc_true(0,0) = section.material.k() * section.area_true; // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors @@ -924,7 +505,7 @@ TEST_CASE("L_element_property_card_constant_heat_transfer_1d", // Hard-coded value of the section's extension stiffness RealMatrixX D_sec_capac_true = RealMatrixX::Zero(1,1); - D_sec_capac_true(0,0) = rho() * cp() * area_true; + D_sec_capac_true(0,0) = section.material.rho() * section.material.cp() * section.area_true; // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors @@ -943,119 +524,20 @@ TEST_CASE("L_element_property_card_constant_thermoelastic_1d", "[thermoelastic],[1D],[isotropic],[constant],[property]") { const uint dim = 1; - - // Define Material Properties as MAST Parameters - MAST::Parameter rho("rho_param", 1420.5); // Density - MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity - MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio - MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity - MAST::Parameter k("k_param", 237.0); // Thermal Conductivity - MAST::Parameter alpha("alpha_param", 5.34e-05); // Coeff. of Thermal Exp. - - const Real G = E() / (2. * (1. + nu())); - - // Define Section Properties as MAST Parameters - MAST::Parameter DIM1("DIM1", 6.000); - MAST::Parameter DIM2("DIM2", 3.000); - MAST::Parameter DIM3("DIM3", 0.250); - MAST::Parameter DIM4("DIM4", 0.125); - - MAST::Parameter offset_y("offy_param", -0.918); // Section offset in y-direction - MAST::Parameter offset_z("offz_param", -0.347); // Section offset in z-direction + const uint n_target_elems = 3500; - // Define Sensitivity Parameters - std::vector sens_params = {&DIM1}; - uint n_s = sens_params.size(); - - // Create field functions to dsitribute these constant parameters throughout the model - // Section Property Field Functions - MAST::ConstantFieldFunction DIM1_f("DIM1", DIM1); - MAST::ConstantFieldFunction DIM2_f("DIM2", DIM2); - MAST::ConstantFieldFunction DIM3_f("DIM3", DIM3); - MAST::ConstantFieldFunction DIM4_f("DIM4", DIM4); - MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); - MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); - // Material Property Field Functions - MAST::ConstantFieldFunction rho_f("rho", rho); - MAST::ConstantFieldFunction E_f("E", E); - MAST::ConstantFieldFunction nu_f("nu", nu); - MAST::ConstantFieldFunction cp_f("cp", cp); - MAST::ConstantFieldFunction k_f("k_th", k); - MAST::ConstantFieldFunction alpha_f("alpha_expansion", alpha); - - // Initialize the material - MAST::IsotropicMaterialPropertyCard material; - - // Add the material property constant field functions to the material card - material.add(rho_f); - material.add(k_f); - material.add(cp_f); - material.add(E_f); - material.add(nu_f); - material.add(alpha_f); - - // Initialize the section - MAST::Solid1DLSectionElementPropertyCard section; - - // Add the section property constant field functions to the section card - section.add(DIM1_f); - section.add(DIM2_f); - section.add(DIM3_f); - section.add(DIM4_f); - - section.add(offsety_f); - section.add(offsetz_f); - - // Add the material card to the section card - section.set_material(material); - - // Specify a section orientation point and add it to the section. - RealVectorX orientation = RealVectorX::Zero(3); - orientation(1) = 1.0; - section.y_vector() = orientation; - - // Now initialize the section - section.init(*p_global_init); + TEST::AluminumLSection section(n_target_elems); REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional - REQUIRE( section.depends_on(DIM1) ); - REQUIRE( section.depends_on(offset_y) ); - REQUIRE( section.depends_on(offset_z) ); - REQUIRE( section.depends_on(k) ); - REQUIRE( section.depends_on(cp) ); - REQUIRE( section.depends_on(rho) ); + REQUIRE( section.depends_on(section.DIM1) ); + REQUIRE( section.depends_on(section.offset_y) ); + REQUIRE( section.depends_on(section.offset_z) ); + REQUIRE( section.depends_on(section.material.k) ); + REQUIRE( section.depends_on(section.material.cp) ); + REQUIRE( section.depends_on(section.material.rho) ); REQUIRE( section.if_isotropic() ); - // True values - const Real area_true = 1.8437499999999953e+00; - const Real torsion_constant_true = 3.2287060106088283e-02; - const Real first_area_moment_z_true = -1.1769375000000033e+00; - const Real first_area_moment_y_true = 3.7664687499999960e+00; - const Real second_area_moment_zz_true = 1.6049689895833330e+00; - const Real second_area_moment_yy_true = 1.4607873559895838e+01; - const Real second_area_moment_zy_true = -3.6365401874999770e+00; - const Real second_area_moment_polar_true = 1.6212842549479170e+01; - const Real Izzc_true = 8.5368390271892014e-01; - const Real Iyyc_true = 6.9136162881797327e+00; - const Real Izyc_true = -1.2322563559321700e+00; - const Real Ipc_true = 7.7673001908986530e+00; - const Real warping_constant_true = 9.4267315264520590e-02; - const Real kappa_z_true = 6.9387531455434204e-01; - const Real kappa_y_true = 1.5217893373385735e-01; - const Real xs_true = -3.0393910943861346e-01; - const Real ys_true = -9.2444557187933163e-01; - const Real xst_true = -3.0393910943861346e-01; - const Real yst_true = -9.2444557187933163e-01; - const Real xc_true = 2.0428305084745793e+00; - const Real yc_true = -6.3833898305085091e-01; - const std::vector stress_points_true = { - libMesh::Point(-1.9803305084745793e+00, 3.5133389830508510e+00, 0.), - libMesh::Point(3.8946694915254207e+00, 5.1333898305085091e-01, 0.), - libMesh::Point(-2.1053305084745793e+00, 5.1333898305085091e-01, 0.), - libMesh::Point(-2.1053305084745793e+00, 3.5133389830508510e+00, 0.) - }; - const libMesh::Point point(4.3, -3.5, -6.7); const Real time = 8.22; @@ -1075,7 +557,7 @@ TEST_CASE("L_element_property_card_constant_thermoelastic_1d", Real area; const MAST::FieldFunction& Area = section.A(); Area(point, time, area); - CHECK( area == Approx(area_true) ); + CHECK( area == Approx(section.area_true) ); std::unique_ptr> texp_A_mat = section.thermal_expansion_A_matrix(); @@ -1086,7 +568,7 @@ TEST_CASE("L_element_property_card_constant_thermoelastic_1d", // Hard-coded value of the section's extension stiffness RealMatrixX D_sec_texpA_true = RealMatrixX::Zero(2,1); - D_sec_texpA_true(0,0) = E() * alpha() * area_true; + D_sec_texpA_true(0,0) = section.material.E() * section.material.alpha() * section.area_true; // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors @@ -1116,12 +598,12 @@ TEST_CASE("L_element_property_card_constant_thermoelastic_1d", Real first_area_moment_y; const MAST::FieldFunction& Ay = section.Ay(); Ay(point, time, first_area_moment_y); - CHECK( first_area_moment_y == Approx(first_area_moment_y_true) ); + CHECK( first_area_moment_y == Approx(section.first_area_moment_y_true) ); Real first_area_moment_z; const MAST::FieldFunction& Az = section.Az(); Az(point, time, first_area_moment_z); - CHECK( first_area_moment_z == Approx(first_area_moment_z_true) ); + CHECK( first_area_moment_z == Approx(section.first_area_moment_z_true) ); std::unique_ptr> texp_B_mat = section.thermal_expansion_B_matrix(); @@ -1134,8 +616,8 @@ TEST_CASE("L_element_property_card_constant_thermoelastic_1d", // Hard-coded value of the section's extension stiffness RealMatrixX D_sec_texpB_true = RealMatrixX::Zero(2,1); - D_sec_texpB_true(0,0) = E() * alpha() * first_area_moment_z_true; - D_sec_texpB_true(1,0) = E() * alpha() * first_area_moment_y_true; + D_sec_texpB_true(0,0) = section.material.E() * section.material.alpha() * section.first_area_moment_z_true; + D_sec_texpB_true(1,0) = section.material.E() * section.material.alpha() * section.first_area_moment_y_true; // Convert the test and truth Eigen::Matrix objects to std::vector @@ -1155,119 +637,20 @@ TEST_CASE("L_element_property_card_constant_dynamic_1d", "[dynamic],[1D],[isotropic],[constant],[property]") { const uint dim = 1; - - // Define Material Properties as MAST Parameters - MAST::Parameter rho("rho_param", 1420.5); // Density - MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity - MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio - MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity - MAST::Parameter k("k_param", 237.0); // Thermal Conductivity - MAST::Parameter alpha("alpha_param", 5.34e-05); // Coeff. of Thermal Exp. - - const Real G = E() / (2. * (1. + nu())); - - // Define Section Properties as MAST Parameters - MAST::Parameter DIM1("DIM1", 6.000); - MAST::Parameter DIM2("DIM2", 3.000); - MAST::Parameter DIM3("DIM3", 0.250); - MAST::Parameter DIM4("DIM4", 0.125); - - MAST::Parameter offset_y("offy_param", -0.918); // Section offset in y-direction - MAST::Parameter offset_z("offz_param", -0.347); // Section offset in z-direction + const uint n_target_elems = 3500; - // Define Sensitivity Parameters - std::vector sens_params = {&DIM1}; - uint n_s = sens_params.size(); - - // Create field functions to dsitribute these constant parameters throughout the model - // Section Property Field Functions - MAST::ConstantFieldFunction DIM1_f("DIM1", DIM1); - MAST::ConstantFieldFunction DIM2_f("DIM2", DIM2); - MAST::ConstantFieldFunction DIM3_f("DIM3", DIM3); - MAST::ConstantFieldFunction DIM4_f("DIM4", DIM4); - MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); - MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); - // Material Property Field Functions - MAST::ConstantFieldFunction rho_f("rho", rho); - MAST::ConstantFieldFunction E_f("E", E); - MAST::ConstantFieldFunction nu_f("nu", nu); - MAST::ConstantFieldFunction cp_f("cp", cp); - MAST::ConstantFieldFunction k_f("k_th", k); - MAST::ConstantFieldFunction alpha_f("alpha_expansion", alpha); - - // Initialize the material - MAST::IsotropicMaterialPropertyCard material; - - // Add the material property constant field functions to the material card - material.add(rho_f); - material.add(k_f); - material.add(cp_f); - material.add(E_f); - material.add(nu_f); - material.add(alpha_f); - - // Initialize the section - MAST::Solid1DLSectionElementPropertyCard section; - - // Add the section property constant field functions to the section card - section.add(DIM1_f); - section.add(DIM2_f); - section.add(DIM3_f); - section.add(DIM4_f); - - section.add(offsety_f); - section.add(offsetz_f); - - // Add the material card to the section card - section.set_material(material); - - // Specify a section orientation point and add it to the section. - RealVectorX orientation = RealVectorX::Zero(3); - orientation(1) = 1.0; - section.y_vector() = orientation; - - // Now initialize the section - section.init(*p_global_init); + TEST::AluminumLSection section(n_target_elems); REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional - REQUIRE( section.depends_on(DIM1) ); - REQUIRE( section.depends_on(offset_y) ); - REQUIRE( section.depends_on(offset_z) ); - REQUIRE( section.depends_on(k) ); - REQUIRE( section.depends_on(cp) ); - REQUIRE( section.depends_on(rho) ); + REQUIRE( section.depends_on(section.DIM1) ); + REQUIRE( section.depends_on(section.offset_y) ); + REQUIRE( section.depends_on(section.offset_z) ); + REQUIRE( section.depends_on(section.material.k) ); + REQUIRE( section.depends_on(section.material.cp) ); + REQUIRE( section.depends_on(section.material.rho) ); REQUIRE( section.if_isotropic() ); - // True values - const Real area_true = 1.8437499999999953e+00; - const Real torsion_constant_true = 3.2287060106088283e-02; - const Real first_area_moment_z_true = -1.1769375000000033e+00; - const Real first_area_moment_y_true = 3.7664687499999960e+00; - const Real second_area_moment_zz_true = 1.6049689895833330e+00; - const Real second_area_moment_yy_true = 1.4607873559895838e+01; - const Real second_area_moment_zy_true = -3.6365401874999770e+00; - const Real second_area_moment_polar_true = 1.6212842549479170e+01; - const Real Izzc_true = 8.5368390271892014e-01; - const Real Iyyc_true = 6.9136162881797327e+00; - const Real Izyc_true = -1.2322563559321700e+00; - const Real Ipc_true = 7.7673001908986530e+00; - const Real warping_constant_true = 9.4267315264520590e-02; - const Real kappa_z_true = 6.9387531455434204e-01; - const Real kappa_y_true = 1.5217893373385735e-01; - const Real xs_true = -3.0393910943861346e-01; - const Real ys_true = -9.2444557187933163e-01; - const Real xst_true = -3.0393910943861346e-01; - const Real yst_true = -9.2444557187933163e-01; - const Real xc_true = 2.0428305084745793e+00; - const Real yc_true = -6.3833898305085091e-01; - const std::vector stress_points_true = { - libMesh::Point(-1.9803305084745793e+00, 3.5133389830508510e+00, 0.), - libMesh::Point(3.8946694915254207e+00, 5.1333898305085091e-01, 0.), - libMesh::Point(-2.1053305084745793e+00, 5.1333898305085091e-01, 0.), - libMesh::Point(-2.1053305084745793e+00, 3.5133389830508510e+00, 0.) - }; - const libMesh::Point point(4.3, -3.5, -6.7); const Real time = 8.22; @@ -1297,26 +680,26 @@ TEST_CASE("L_element_property_card_constant_dynamic_1d", Real area; const MAST::FieldFunction& Area = section.A(); Area(point, time, area); - REQUIRE( area == Approx(area_true) ); - D_sec_iner_true(0,0) = D_sec_iner_true(1,1) = D_sec_iner_true(2,2) = area_true; + REQUIRE( area == Approx(section.area_true) ); + D_sec_iner_true(0,0) = D_sec_iner_true(1,1) = D_sec_iner_true(2,2) = section.area_true; Real Ip; const MAST::FieldFunction& PolarInertia = section.Ip(); PolarInertia(point, time, Ip); - CHECK( Ip == Approx(second_area_moment_polar_true) ); - D_sec_iner_true(3,3) = second_area_moment_polar_true; + CHECK( Ip == Approx(section.second_area_moment_polar_true) ); + D_sec_iner_true(3,3) = section.second_area_moment_polar_true; Real first_area_moment_y; const MAST::FieldFunction& Ay = section.Ay(); Ay(point, time, first_area_moment_y); - CHECK( first_area_moment_y == Approx(first_area_moment_y_true) ); - D_sec_iner_true(0,4) = D_sec_iner_true(4,0) = first_area_moment_y_true; + CHECK( first_area_moment_y == Approx(section.first_area_moment_y_true) ); + D_sec_iner_true(0,4) = D_sec_iner_true(4,0) = section.first_area_moment_y_true; Real first_area_moment_z; const MAST::FieldFunction& Az = section.Az(); Az(point, time, first_area_moment_z); - CHECK( first_area_moment_z == Approx(first_area_moment_z_true) ); - D_sec_iner_true(0,5) = D_sec_iner_true(5,0) = first_area_moment_z_true; + CHECK( first_area_moment_z == Approx(section.first_area_moment_z_true) ); + D_sec_iner_true(0,5) = D_sec_iner_true(5,0) = section.first_area_moment_z_true; RealMatrixX I; const MAST::FieldFunction& Inertias = section.I(); @@ -1325,16 +708,16 @@ TEST_CASE("L_element_property_card_constant_dynamic_1d", Real Iyy = I(1,1); Real Izz = I(0,0); Real Izy = I(0,1); - REQUIRE( Izz == Approx(second_area_moment_zz_true) ); - REQUIRE( Iyy == Approx(second_area_moment_yy_true) ); - REQUIRE( Izy == Approx(second_area_moment_zy_true) ); + REQUIRE( Izz == Approx(section.second_area_moment_zz_true) ); + REQUIRE( Iyy == Approx(section.second_area_moment_yy_true) ); + REQUIRE( Izy == Approx(section.second_area_moment_zy_true) ); D_sec_iner_true(4,4) = Iyy; // Should this be Izz? D_sec_iner_true(4,5) = Izy; D_sec_iner_true(5,4) = Izy; D_sec_iner_true(5,5) = Izz; // Should this by Iyy? - D_sec_iner_true *= rho(); + D_sec_iner_true *= section.material.rho(); // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors @@ -1353,119 +736,20 @@ TEST_CASE("L_element_property_card_constant_structural_1d", "[structural],[1D],[isotropic],[constant],[property]") { const uint dim = 1; - - // Define Material Properties as MAST Parameters - MAST::Parameter rho("rho_param", 1420.5); // Density - MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity - MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio - MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity - MAST::Parameter k("k_param", 237.0); // Thermal Conductivity - MAST::Parameter alpha("alpha_param", 5.34e-05); // Coeff. of Thermal Exp. - - const Real G = E() / (2. * (1. + nu())); - - // Define Section Properties as MAST Parameters - MAST::Parameter DIM1("DIM1", 6.000); - MAST::Parameter DIM2("DIM2", 3.000); - MAST::Parameter DIM3("DIM3", 0.250); - MAST::Parameter DIM4("DIM4", 0.125); - - MAST::Parameter offset_y("offy_param", -0.918); // Section offset in y-direction - MAST::Parameter offset_z("offz_param", -0.347); // Section offset in z-direction + const uint n_target_elems = 3500; - // Define Sensitivity Parameters - std::vector sens_params = {&DIM1}; - uint n_s = sens_params.size(); - - // Create field functions to dsitribute these constant parameters throughout the model - // Section Property Field Functions - MAST::ConstantFieldFunction DIM1_f("DIM1", DIM1); - MAST::ConstantFieldFunction DIM2_f("DIM2", DIM2); - MAST::ConstantFieldFunction DIM3_f("DIM3", DIM3); - MAST::ConstantFieldFunction DIM4_f("DIM4", DIM4); - MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); - MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); - // Material Property Field Functions - MAST::ConstantFieldFunction rho_f("rho", rho); - MAST::ConstantFieldFunction E_f("E", E); - MAST::ConstantFieldFunction nu_f("nu", nu); - MAST::ConstantFieldFunction cp_f("cp", cp); - MAST::ConstantFieldFunction k_f("k_th", k); - MAST::ConstantFieldFunction alpha_f("alpha_expansion", alpha); - - // Initialize the material - MAST::IsotropicMaterialPropertyCard material; - - // Add the material property constant field functions to the material card - material.add(rho_f); - material.add(k_f); - material.add(cp_f); - material.add(E_f); - material.add(nu_f); - material.add(alpha_f); - - // Initialize the section - MAST::Solid1DLSectionElementPropertyCard section; - - // Add the section property constant field functions to the section card - section.add(DIM1_f); - section.add(DIM2_f); - section.add(DIM3_f); - section.add(DIM4_f); - - section.add(offsety_f); - section.add(offsetz_f); - - // Add the material card to the section card - section.set_material(material); - - // Specify a section orientation point and add it to the section. - RealVectorX orientation = RealVectorX::Zero(3); - orientation(1) = 1.0; - section.y_vector() = orientation; - - // Now initialize the section - section.init(*p_global_init); + TEST::AluminumLSection section(n_target_elems); REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional - REQUIRE( section.depends_on(DIM1) ); - REQUIRE( section.depends_on(offset_y) ); - REQUIRE( section.depends_on(offset_z) ); - REQUIRE( section.depends_on(k) ); - REQUIRE( section.depends_on(cp) ); - REQUIRE( section.depends_on(rho) ); + REQUIRE( section.depends_on(section.DIM1) ); + REQUIRE( section.depends_on(section.offset_y) ); + REQUIRE( section.depends_on(section.offset_z) ); + REQUIRE( section.depends_on(section.material.k) ); + REQUIRE( section.depends_on(section.material.cp) ); + REQUIRE( section.depends_on(section.material.rho) ); REQUIRE( section.if_isotropic() ); - // True values - const Real area_true = 1.8437499999999953e+00; - const Real torsion_constant_true = 3.2287060106088283e-02; - const Real first_area_moment_z_true = -1.1769375000000033e+00; - const Real first_area_moment_y_true = 3.7664687499999960e+00; - const Real second_area_moment_zz_true = 1.6049689895833330e+00; - const Real second_area_moment_yy_true = 1.4607873559895838e+01; - const Real second_area_moment_zy_true = -3.6365401874999770e+00; - const Real second_area_moment_polar_true = 1.6212842549479170e+01; - const Real Izzc_true = 8.5368390271892014e-01; - const Real Iyyc_true = 6.9136162881797327e+00; - const Real Izyc_true = -1.2322563559321700e+00; - const Real Ipc_true = 7.7673001908986530e+00; - const Real warping_constant_true = 9.4267315264520590e-02; - const Real kappa_z_true = 6.9387531455434204e-01; - const Real kappa_y_true = 1.5217893373385735e-01; - const Real xs_true = -3.0393910943861346e-01; - const Real ys_true = -9.2444557187933163e-01; - const Real xst_true = -3.0393910943861346e-01; - const Real yst_true = -9.2444557187933163e-01; - const Real xc_true = 2.0428305084745793e+00; - const Real yc_true = -6.3833898305085091e-01; - const std::vector stress_points_true = { - libMesh::Point(-1.9803305084745793e+00, 3.5133389830508510e+00, 0.), - libMesh::Point(3.8946694915254207e+00, 5.1333898305085091e-01, 0.), - libMesh::Point(-2.1053305084745793e+00, 5.1333898305085091e-01, 0.), - libMesh::Point(-2.1053305084745793e+00, 3.5133389830508510e+00, 0.) - }; - const libMesh::Point point(4.3, -3.5, -6.7); const Real time = 8.22; @@ -1505,12 +789,12 @@ TEST_CASE("L_element_property_card_constant_structural_1d", Real area; const MAST::FieldFunction& Area = section.A(); Area(point, time, area); - REQUIRE( area == Approx(area_true) ); + REQUIRE( area == Approx(section.area_true) ); Real torsion_constant; const MAST::FieldFunction& TorsionConstant = section.J(); TorsionConstant(point, time, torsion_constant); - REQUIRE( torsion_constant == Approx(torsion_constant_true).epsilon(0.05) ); + REQUIRE( torsion_constant == Approx(section.torsion_constant_true).epsilon(0.05) ); std::unique_ptr> extension_stiffness_mat = section.stiffness_A_matrix(); @@ -1523,8 +807,8 @@ TEST_CASE("L_element_property_card_constant_structural_1d", // Hard-coded value of the section's extension stiffness RealMatrixX D_sec_ext_true = RealMatrixX::Zero(2,2); - D_sec_ext_true(0,0) = E() * area_true; - D_sec_ext_true(1,1) = G * torsion_constant_true; + D_sec_ext_true(0,0) = section.material.E() * section.area_true; + D_sec_ext_true(1,1) = section.material.G() * section.torsion_constant_true; // Convert the test and truth Eigen::Matrix objects to std::vector @@ -1558,9 +842,9 @@ TEST_CASE("L_element_property_card_constant_structural_1d", Real Izz = I(0,0); Real Iyy = I(1,1); Real Izy = I(0,1); - REQUIRE( Izz == Approx(second_area_moment_zz_true) ); - REQUIRE( Iyy == Approx(second_area_moment_yy_true) ); - REQUIRE( Izy == Approx(second_area_moment_zy_true) ); + REQUIRE( Izz == Approx(section.second_area_moment_zz_true) ); + REQUIRE( Iyy == Approx(section.second_area_moment_yy_true) ); + REQUIRE( Izy == Approx(section.second_area_moment_zy_true) ); std::unique_ptr> bending_stiffness_mat = section.stiffness_D_matrix(); @@ -1571,10 +855,10 @@ TEST_CASE("L_element_property_card_constant_structural_1d", // Hard-coded value of the section's extension stiffness RealMatrixX D_sec_bnd_true = RealMatrixX::Zero(2,2); - D_sec_bnd_true(0,0) = E() * second_area_moment_zz_true; - D_sec_bnd_true(1,1) = E() * second_area_moment_yy_true; - D_sec_bnd_true(0,1) = E() * second_area_moment_zy_true; - D_sec_bnd_true(1,0) = E() * second_area_moment_zy_true; + D_sec_bnd_true(0,0) = section.material.E() * section.second_area_moment_zz_true; + D_sec_bnd_true(1,1) = section.material.E() * section.second_area_moment_yy_true; + D_sec_bnd_true(0,1) = section.material.E() * section.second_area_moment_zy_true; + D_sec_bnd_true(1,0) = section.material.E() * section.second_area_moment_zy_true; // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors @@ -1602,12 +886,12 @@ TEST_CASE("L_element_property_card_constant_structural_1d", Real first_area_moment_y; const MAST::FieldFunction& Ay = section.Ay(); Ay(point, time, first_area_moment_y); - CHECK( first_area_moment_y == Approx(first_area_moment_y_true) ); + CHECK( first_area_moment_y == Approx(section.first_area_moment_y_true) ); Real first_area_moment_z; const MAST::FieldFunction& Az = section.Az(); Az(point, time, first_area_moment_z); - CHECK( first_area_moment_z == Approx(first_area_moment_z_true) ); + CHECK( first_area_moment_z == Approx(section.first_area_moment_z_true) ); std::unique_ptr> bndext_stiffness_mat = section.stiffness_B_matrix(); @@ -1618,8 +902,8 @@ TEST_CASE("L_element_property_card_constant_structural_1d", // Hard-coded value of the section's extension stiffness RealMatrixX D_sec_bndext_true = RealMatrixX::Zero(2,2); - D_sec_bndext_true(0,0) = E() * first_area_moment_z_true; - D_sec_bndext_true(0,1) = E() * first_area_moment_y_true; + D_sec_bndext_true(0,0) = section.material.E() * section.first_area_moment_z_true; + D_sec_bndext_true(0,1) = section.material.E() * section.first_area_moment_y_true; // TODO: Add checks for torsion bending coupling when added to MAST. // Convert the test and truth Eigen::Matrix objects to std::vector @@ -1648,7 +932,7 @@ TEST_CASE("L_element_property_card_constant_structural_1d", Real area; const MAST::FieldFunction& Area = section.A(); Area(point, time, area); - REQUIRE( area == Approx(area_true) ); + REQUIRE( area == Approx(section.area_true) ); std::unique_ptr> trans_shear_stiffness_mat = section.transverse_shear_stiffness_matrix(); @@ -1659,8 +943,8 @@ TEST_CASE("L_element_property_card_constant_structural_1d", // Hard-coded value of the section's extension stiffness RealMatrixX D_sec_shr_true = RealMatrixX::Zero(2,2); - D_sec_shr_true(0,0) = G*area_true*kappa_z_true; - D_sec_shr_true(1,1) = G*area_true*kappa_y_true; + D_sec_shr_true(0,0) = section.material.G()*section.area_true*section.kappa_z_true; + D_sec_shr_true(1,1) = section.material.G()*section.area_true*section.kappa_y_true; // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors diff --git a/tests/property/mast_solid_1d_L_section_element_property_card.h b/tests/property/mast_solid_1d_L_section_element_property_card.h new file mode 100644 index 00000000..6efedc1f --- /dev/null +++ b/tests/property/mast_solid_1d_L_section_element_property_card.h @@ -0,0 +1,96 @@ +#ifndef MAST_SOLID_1D_L_SECTION_ELEMENT_PROPERTY_CARD_H_INCLUDED +#define MAST_SOLID_1D_L_SECTION_ELEMENT_PROPERTY_CARD_H_INCLUDED + + +#include "property_cards/solid_1d_L_section_element_property_card.h" +#include "material/mast_isotropic_material.h" + +extern libMesh::LibMeshInit* p_global_init; + +namespace TEST +{ + class AluminumLSection : public MAST::Solid1DLSectionElementPropertyCard + { + public: + + AluminumLSection(const uint n_target_elems=3500): + DIM1("DIM1", 6.000), DIM2("DIM2", 3.000), DIM3("DIM3", 0.250), + DIM4("DIM4", 0.125), offset_y("offy_param", -0.918), + offset_z("offz_param", -0.347), DIM1_f("DIM1", DIM1), + DIM2_f("DIM2", DIM2), DIM3_f("DIM3", DIM3), DIM4_f("DIM4", DIM4), + offsety_f("hy_off", offset_y), offsetz_f("hz_off", offset_z), + centroid_true(xc_true, yc_true), shear_center_true(xs_true, ys_true) + { + add(DIM1_f); + add(DIM2_f); + add(DIM3_f); + add(DIM4_f); + + add(offsety_f); + add(offsetz_f); + + // Add the material card to the section card + set_material(material); + + // Specify a section orientation point and add it to the + RealVectorX orientation = RealVectorX::Zero(3); + orientation(1) = 1.0; + y_vector() = orientation; + + // Now initialize the section + init(*p_global_init, n_target_elems); + } + + TEST::Aluminum7075T6 material; + + MAST::Parameter DIM1; + MAST::Parameter DIM2; + MAST::Parameter DIM3; + MAST::Parameter DIM4; + + MAST::Parameter offset_y; + MAST::Parameter offset_z; + + MAST::ConstantFieldFunction DIM1_f; + MAST::ConstantFieldFunction DIM2_f; + MAST::ConstantFieldFunction DIM3_f; + MAST::ConstantFieldFunction DIM4_f; + + MAST::ConstantFieldFunction offsety_f; + MAST::ConstantFieldFunction offsetz_f; + + // True values + const Real area_true = 1.8437500000000016e+00; + const Real torsion_constant_true = 3.2286682945239953e-02; + const Real first_area_moment_z_true = -1.1769375000000004e+00; + const Real first_area_moment_y_true = 3.7664687499999974e+00; + const Real second_area_moment_zz_true = 1.6049689895833241e+00; + const Real second_area_moment_yy_true = 1.4607873559895829e+01; + const Real second_area_moment_zy_true = -3.6365401874999983e+00; + const Real second_area_moment_polar_true = 1.6212842549479152e+01; + const Real Izzc_true = 8.5368390271891748e-01; + const Real Iyyc_true = 6.9136162881797452e+00; + const Real Izyc_true = -1.2322563559322042e+00; + const Real Ipc_true = 7.7673001908986627e+00; + const Real warping_constant_true = 9.4267903516538354e-02; + const Real kappa_z_true = 6.9387360587828650e-01; + const Real kappa_y_true = 1.5217240110756519e-01; + const Real xs_true = -3.0394644727391729e-01; + const Real ys_true = -9.2444644346018534e-01; + const Real xst_true = -3.0394644727391729e-01; + const Real yst_true = -9.2444644346018534e-01; + const Real xc_true = 2.0428305084745730e+00; + const Real yc_true = -6.3833898305084713e-01; + const std::vector stress_points_true = { + libMesh::Point(-1.9803305084745730e+00, 3.5133389830508470e+00, 0.), + libMesh::Point(3.8946694915254270e+00, 5.1333898305084713e-01, 0.), + libMesh::Point(-2.1053305084745730e+00, 5.1333898305084713e-01, 0.), + libMesh::Point(-2.1053305084745730e+00, 3.5133389830508470e+00, 0.) + }; + + libMesh::Point centroid_true; + libMesh::Point shear_center_true; + + }; +} +#endif // MAST_SOLID_1D_L_SECTION_ELEMENT_PROPERTY_CARD_H_INCLUDED diff --git a/tests/property/mast_solid_1d_bar_section_element_property_card.cpp b/tests/property/mast_solid_1d_bar_section_element_property_card.cpp index aa3b68f8..59f482a6 100644 --- a/tests/property/mast_solid_1d_bar_section_element_property_card.cpp +++ b/tests/property/mast_solid_1d_bar_section_element_property_card.cpp @@ -337,21 +337,7 @@ TEST_CASE("bar_element_property_card_constant_base_sensitivity_1d", std::vector dA_cd(n_s); for (uint i=0; iname() << " = " << dA[i] << "\tdA_cd = " << dA_cd[i] << std::endl; REQUIRE(dA[i] == Approx(dA_cd[i])); @@ -403,21 +389,7 @@ TEST_CASE("bar_element_property_card_constant_base_sensitivity_1d", std::vector dAy_cd(n_s); for (uint i=0; iname() << " = " << dAy[i] << "\tdAy_cd = " << dAy_cd[i] << std::endl; REQUIRE(dAy[i] == Approx(dAy_cd[i])); @@ -434,21 +406,7 @@ TEST_CASE("bar_element_property_card_constant_base_sensitivity_1d", std::vector dAz_cd(n_s); for (uint i=0; iname() << " = " << dAz[i] << "\tdAz_cd = " << dAz_cd[i] << std::endl; REQUIRE(dAz[i] == Approx(dAz_cd[i])); @@ -467,21 +425,7 @@ TEST_CASE("bar_element_property_card_constant_base_sensitivity_1d", std::vector dI_cd(n_s); for (uint i=0; iname() << " =\n" << dI[i] << "\ndI_cd = \n" << dI_cd[i] << std::endl; diff --git a/tests/test_helpers.cpp b/tests/test_helpers.cpp index 44f1575d..334e780c 100644 --- a/tests/test_helpers.cpp +++ b/tests/test_helpers.cpp @@ -26,6 +26,9 @@ #include "libmesh/point.h" #include "libmesh/face_quad4.h" +#include "base/parameter.h" +#include "base/constant_field_function.h" + #define pi 3.14159265358979323846 @@ -394,3 +397,55 @@ void TEST::transform_element(libMesh::MeshBase& mesh, const RealMatrixX X0, (*mesh.node_ptr(i)) = libMesh::Point(X(0,i), X(1,i), X(2,i)); } } + + +Real approximate_field_function_derivative(const MAST::FieldFunction& f, + MAST::Parameter* p, + const libMesh::Point& point, + const Real& time, + Real delta) +{ + Real f_h, f_2h, f_n, f_2n; + + (*p)() += delta; + f(point, time, f_h); + + (*p)() += delta; + f(point, time, f_2h); + + (*p)() -= 3.0*delta; + f(point, time, f_n); + + (*p)() -= delta; + f(point, time, f_2n); + + (*p)() += 2.0*delta; + + return (f_2n - 8.*f_n + 8*f_h - f_2h)/(12.*delta); +} + + +RealMatrixX approximate_field_function_derivative(const MAST::FieldFunction& f, + MAST::Parameter* p, + const libMesh::Point& point, + const Real& time, + Real delta) +{ + RealMatrixX f_h, f_2h, f_n, f_2n; + + (*p)() += delta; + f(point, time, f_h); + + (*p)() += delta; + f(point, time, f_2h); + + (*p)() -= 3.0*delta; + f(point, time, f_n); + + (*p)() -= delta; + f(point, time, f_2n); + + (*p)() += 2.0*delta; + + return (f_2n - 8.*f_n + 8*f_h - f_2h)/(12.*delta); +} diff --git a/tests/test_helpers.h b/tests/test_helpers.h index 0e00d21e..9af5b103 100644 --- a/tests/test_helpers.h +++ b/tests/test_helpers.h @@ -17,8 +17,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef __test__test_helpers__ -#define __test__test_helpers__ +#ifndef TEST_HELPERS_H_INCLUDED +#define TEST_HELPERS_H_INCLUDED #include "base/mast_data_types.h" #include "elasticity/structural_element_base.h" @@ -91,6 +91,7 @@ namespace TEST { MAST::BoundaryConditionBase& thermal_bc); + /** * Transform an element by applying any combination of: shifts, scales, * rotations, and shears. Useful for testing elements of different geometries @@ -101,5 +102,27 @@ namespace TEST { Real scale_x, Real scale_y, Real rotation_x, Real rotation_y, Real rotation_z, Real shear_x = 0, Real shear_y = 0); + + /** + * Approximates a Real field function derivative w.r.t. a parameter using a 4th + * order accurate central finite difference scheme. + */ + Real approximate_field_function_derivative(const MAST::FieldFunction& f, + MAST::Parameter* p, + const libMesh::Point& point, + const Real& time, + Real delta = 3.4526698e-04); + + + /** + * Approximates a RealMatrixX field function derivative w.r.t. a parameter + * using a 4th order accurate central finite difference scheme. + */ + RealMatrixX approximate_field_function_derivative(const MAST::FieldFunction& f, + MAST::Parameter* p, + const libMesh::Point& point, + const Real& time, + Real delta = 3.4526698e-04); } -#endif // __test__test_helpers__ + +#endif // TEST_HELPERS_H_INCLUDED From 40c428d09b1174b191e011ac0414576fc5b9a8f5 Mon Sep 17 00:00:00 2001 From: David John Neiferd <13425967+JohnDN90@users.noreply.github.com> Date: Thu, 5 Mar 2020 21:00:36 -0500 Subject: [PATCH 17/27] Refactored feature/add_beam_library on top of master branch which had refactored tests by J. Deaton merged in. --- ...id_1d_I1_section_element_property_card.cpp | 40 ++++++------- ...lid_1d_L_section_element_property_card.cpp | 56 +++++++++---------- ...d_1d_bar_section_element_property_card.cpp | 48 ++++++++-------- ...d_1d_rod_section_element_property_card.cpp | 40 ++++++------- ...1d_tube2_section_element_property_card.cpp | 40 ++++++------- ..._1d_tube_section_element_property_card.cpp | 40 ++++++------- tests/test_helpers.cpp | 4 +- 7 files changed, 134 insertions(+), 134 deletions(-) diff --git a/tests/property/mast_solid_1d_I1_section_element_property_card.cpp b/tests/property/mast_solid_1d_I1_section_element_property_card.cpp index fb20c6e9..790ff608 100644 --- a/tests/property/mast_solid_1d_I1_section_element_property_card.cpp +++ b/tests/property/mast_solid_1d_I1_section_element_property_card.cpp @@ -862,8 +862,8 @@ TEST_CASE("I1_element_property_card_constant_heat_transfer_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_conduc); - std::vector truth = eigen_matrix_to_std_vector(D_sec_conduc_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_conduc); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_conduc_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -896,8 +896,8 @@ TEST_CASE("I1_element_property_card_constant_heat_transfer_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_capac); - std::vector truth = eigen_matrix_to_std_vector(D_sec_capac_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_capac); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_capac_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -1054,8 +1054,8 @@ TEST_CASE("I1_element_property_card_constant_thermoelastic_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_texpA); - std::vector truth = eigen_matrix_to_std_vector(D_sec_texpA_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_texpA); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_texpA_true); // Floating point approximations are diffcult to compare since the @@ -1104,8 +1104,8 @@ TEST_CASE("I1_element_property_card_constant_thermoelastic_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_texpB); - std::vector truth = eigen_matrix_to_std_vector(D_sec_texpB_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_texpB); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_texpB_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -1294,8 +1294,8 @@ TEST_CASE("I1_element_property_card_constant_dynamic_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_iner); - std::vector truth = eigen_matrix_to_std_vector(D_sec_iner_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_iner); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_iner_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -1478,8 +1478,8 @@ TEST_CASE("I1_element_property_card_constant_structural_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_ext); - std::vector truth = eigen_matrix_to_std_vector(D_sec_ext_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_ext); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_ext_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -1527,8 +1527,8 @@ TEST_CASE("I1_element_property_card_constant_structural_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_bnd); - std::vector truth = eigen_matrix_to_std_vector(D_sec_bnd_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_bnd); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_bnd_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -1573,8 +1573,8 @@ TEST_CASE("I1_element_property_card_constant_structural_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_bndext); - std::vector truth = eigen_matrix_to_std_vector(D_sec_bndext_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_bndext); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_bndext_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -1613,8 +1613,8 @@ TEST_CASE("I1_element_property_card_constant_structural_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_shr); - std::vector truth = eigen_matrix_to_std_vector(D_sec_shr_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_shr); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_shr_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -1648,8 +1648,8 @@ TEST_CASE("I1_element_property_card_constant_structural_1d", // // // Convert the test and truth Eigen::Matrix objects to std::vector // // since Catch2 has built in methods to compare vectors -// std::vector test = eigen_matrix_to_std_vector(D_sec_spring); -// std::vector truth = eigen_matrix_to_std_vector(D_sec_spring_true); +// std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_spring); +// std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_spring_true); // // // Floating point approximations are diffcult to compare since the // // values typically aren't exactly equal due to numerical error. diff --git a/tests/property/mast_solid_1d_L_section_element_property_card.cpp b/tests/property/mast_solid_1d_L_section_element_property_card.cpp index dd58215b..11dc2057 100644 --- a/tests/property/mast_solid_1d_L_section_element_property_card.cpp +++ b/tests/property/mast_solid_1d_L_section_element_property_card.cpp @@ -190,7 +190,7 @@ TEST_CASE("L_element_property_card_constant_base_sensitivity_1d", std::vector dA_cd(n_s); for (uint i=0; iname() << " = " << dA[i] << "\tdA_cd = " << dA_cd[i] << std::endl; REQUIRE(dA[i] == Approx(dA_cd[i])); @@ -240,7 +240,7 @@ TEST_CASE("L_element_property_card_constant_base_sensitivity_1d", std::vector dAy_cd(n_s); for (uint i=0; iname() << " = " << dAy[i] << "\tdAy_cd = " << dAy_cd[i] << std::endl; REQUIRE(dAy[i] == Approx(dAy_cd[i])); @@ -257,7 +257,7 @@ TEST_CASE("L_element_property_card_constant_base_sensitivity_1d", std::vector dAz_cd(n_s); for (uint i=0; iname() << " = " << dAz[i] << "\tdAz_cd = " << dAz_cd[i] << std::endl; REQUIRE(dAz[i] == Approx(dAz_cd[i])); @@ -275,7 +275,7 @@ TEST_CASE("L_element_property_card_constant_base_sensitivity_1d", std::vector dI_cd(n_s); for (uint i=0; iname() << " =\n" << dI[i] << "\ndI_cd = \n" << dI_cd[i] << std::endl; @@ -308,7 +308,7 @@ TEST_CASE("L_element_property_card_constant_base_sensitivity_1d", std::vector dIp_cd(n_s); for (uint i=0; iname() << " = " << dIp[i] << "\tdIp_cd = " << dIp_cd[i] << std::endl; REQUIRE(dIp[i] == Approx(dIp_cd[i])); @@ -359,7 +359,7 @@ TEST_CASE("L_element_property_card_constant_base_sensitivity_1d", std::vector dJ_cd(n_s); for (uint i=0; iname() << " = " << dJ[i] << "\tdJ_cd = " << dJ_cd[i] << std::endl; REQUIRE(dJ[i] == Approx(dJ_cd[i]).epsilon(0.1) ); @@ -379,7 +379,7 @@ TEST_CASE("L_element_property_card_constant_base_sensitivity_1d", std::vector dK_cd(n_s); for (uint i=0; iname() << " =\n" << dK[i] << "\ndK_cd = \n" << dK_cd[i] << std::endl; @@ -414,7 +414,7 @@ TEST_CASE("L_element_property_card_constant_base_sensitivity_1d", std::vector dW_cd(n_s); for (uint i=0; iname() << " = " << dW[i] << "\tdW_cd = " << dW_cd[i] << std::endl; REQUIRE(dW[i] == Approx(dW_cd[i]).epsilon(0.1) ); @@ -475,8 +475,8 @@ TEST_CASE("L_element_property_card_constant_heat_transfer_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_conduc); - std::vector truth = eigen_matrix_to_std_vector(D_sec_conduc_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_conduc); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_conduc_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -509,8 +509,8 @@ TEST_CASE("L_element_property_card_constant_heat_transfer_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_capac); - std::vector truth = eigen_matrix_to_std_vector(D_sec_capac_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_capac); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_capac_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -572,8 +572,8 @@ TEST_CASE("L_element_property_card_constant_thermoelastic_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_texpA); - std::vector truth = eigen_matrix_to_std_vector(D_sec_texpA_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_texpA); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_texpA_true); // Floating point approximations are diffcult to compare since the @@ -622,8 +622,8 @@ TEST_CASE("L_element_property_card_constant_thermoelastic_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_texpB); - std::vector truth = eigen_matrix_to_std_vector(D_sec_texpB_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_texpB); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_texpB_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -721,8 +721,8 @@ TEST_CASE("L_element_property_card_constant_dynamic_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_iner); - std::vector truth = eigen_matrix_to_std_vector(D_sec_iner_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_iner); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_iner_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -813,8 +813,8 @@ TEST_CASE("L_element_property_card_constant_structural_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_ext); - std::vector truth = eigen_matrix_to_std_vector(D_sec_ext_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_ext); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_ext_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -862,8 +862,8 @@ TEST_CASE("L_element_property_card_constant_structural_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_bnd); - std::vector truth = eigen_matrix_to_std_vector(D_sec_bnd_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_bnd); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_bnd_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -908,8 +908,8 @@ TEST_CASE("L_element_property_card_constant_structural_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_bndext); - std::vector truth = eigen_matrix_to_std_vector(D_sec_bndext_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_bndext); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_bndext_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -948,8 +948,8 @@ TEST_CASE("L_element_property_card_constant_structural_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_shr); - std::vector truth = eigen_matrix_to_std_vector(D_sec_shr_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_shr); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_shr_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -983,8 +983,8 @@ TEST_CASE("L_element_property_card_constant_structural_1d", // // // Convert the test and truth Eigen::Matrix objects to std::vector // // since Catch2 has built in methods to compare vectors -// std::vector test = eigen_matrix_to_std_vector(D_sec_spring); -// std::vector truth = eigen_matrix_to_std_vector(D_sec_spring_true); +// std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_spring); +// std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_spring_true); // // // Floating point approximations are diffcult to compare since the // // values typically aren't exactly equal due to numerical error. diff --git a/tests/property/mast_solid_1d_bar_section_element_property_card.cpp b/tests/property/mast_solid_1d_bar_section_element_property_card.cpp index 59f482a6..22f660e9 100644 --- a/tests/property/mast_solid_1d_bar_section_element_property_card.cpp +++ b/tests/property/mast_solid_1d_bar_section_element_property_card.cpp @@ -337,7 +337,7 @@ TEST_CASE("bar_element_property_card_constant_base_sensitivity_1d", std::vector dA_cd(n_s); for (uint i=0; iname() << " = " << dA[i] << "\tdA_cd = " << dA_cd[i] << std::endl; REQUIRE(dA[i] == Approx(dA_cd[i])); @@ -389,7 +389,7 @@ TEST_CASE("bar_element_property_card_constant_base_sensitivity_1d", std::vector dAy_cd(n_s); for (uint i=0; iname() << " = " << dAy[i] << "\tdAy_cd = " << dAy_cd[i] << std::endl; REQUIRE(dAy[i] == Approx(dAy_cd[i])); @@ -406,7 +406,7 @@ TEST_CASE("bar_element_property_card_constant_base_sensitivity_1d", std::vector dAz_cd(n_s); for (uint i=0; iname() << " = " << dAz[i] << "\tdAz_cd = " << dAz_cd[i] << std::endl; REQUIRE(dAz[i] == Approx(dAz_cd[i])); @@ -425,7 +425,7 @@ TEST_CASE("bar_element_property_card_constant_base_sensitivity_1d", std::vector dI_cd(n_s); for (uint i=0; iname() << " =\n" << dI[i] << "\ndI_cd = \n" << dI_cd[i] << std::endl; @@ -737,8 +737,8 @@ TEST_CASE("bar_element_property_card_constant_heat_transfer_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_conduc); - std::vector truth = eigen_matrix_to_std_vector(D_sec_conduc_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_conduc); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_conduc_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -771,8 +771,8 @@ TEST_CASE("bar_element_property_card_constant_heat_transfer_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_capac); - std::vector truth = eigen_matrix_to_std_vector(D_sec_capac_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_capac); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_capac_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -887,8 +887,8 @@ TEST_CASE("bar_element_property_card_constant_thermoelastic_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_texpA); - std::vector truth = eigen_matrix_to_std_vector(D_sec_texpA_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_texpA); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_texpA_true); // Floating point approximations are diffcult to compare since the @@ -937,8 +937,8 @@ TEST_CASE("bar_element_property_card_constant_thermoelastic_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_texpB); - std::vector truth = eigen_matrix_to_std_vector(D_sec_texpB_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_texpB); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_texpB_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -1115,8 +1115,8 @@ TEST_CASE("bar_element_property_card_constant_dynamic_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_iner); - std::vector truth = eigen_matrix_to_std_vector(D_sec_iner_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_iner); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_iner_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -1282,8 +1282,8 @@ TEST_CASE("bar_element_property_card_constant_structural_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_ext); - std::vector truth = eigen_matrix_to_std_vector(D_sec_ext_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_ext); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_ext_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -1331,8 +1331,8 @@ TEST_CASE("bar_element_property_card_constant_structural_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_bnd); - std::vector truth = eigen_matrix_to_std_vector(D_sec_bnd_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_bnd); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_bnd_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -1377,8 +1377,8 @@ TEST_CASE("bar_element_property_card_constant_structural_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_bndext); - std::vector truth = eigen_matrix_to_std_vector(D_sec_bndext_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_bndext); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_bndext_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -1417,8 +1417,8 @@ TEST_CASE("bar_element_property_card_constant_structural_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_shr); - std::vector truth = eigen_matrix_to_std_vector(D_sec_shr_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_shr); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_shr_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -1452,8 +1452,8 @@ TEST_CASE("bar_element_property_card_constant_structural_1d", // // // Convert the test and truth Eigen::Matrix objects to std::vector // // since Catch2 has built in methods to compare vectors -// std::vector test = eigen_matrix_to_std_vector(D_sec_spring); -// std::vector truth = eigen_matrix_to_std_vector(D_sec_spring_true); +// std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_spring); +// std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_spring_true); // // // Floating point approximations are diffcult to compare since the // // values typically aren't exactly equal due to numerical error. diff --git a/tests/property/mast_solid_1d_rod_section_element_property_card.cpp b/tests/property/mast_solid_1d_rod_section_element_property_card.cpp index d95df88d..5096c38e 100644 --- a/tests/property/mast_solid_1d_rod_section_element_property_card.cpp +++ b/tests/property/mast_solid_1d_rod_section_element_property_card.cpp @@ -796,8 +796,8 @@ TEST_CASE("rod_element_property_card_constant_heat_transfer_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_conduc); - std::vector truth = eigen_matrix_to_std_vector(D_sec_conduc_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_conduc); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_conduc_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -830,8 +830,8 @@ TEST_CASE("rod_element_property_card_constant_heat_transfer_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_capac); - std::vector truth = eigen_matrix_to_std_vector(D_sec_capac_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_capac); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_capac_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -972,8 +972,8 @@ TEST_CASE("rod_element_property_card_constant_thermoelastic_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_texpA); - std::vector truth = eigen_matrix_to_std_vector(D_sec_texpA_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_texpA); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_texpA_true); // Floating point approximations are diffcult to compare since the @@ -1022,8 +1022,8 @@ TEST_CASE("rod_element_property_card_constant_thermoelastic_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_texpB); - std::vector truth = eigen_matrix_to_std_vector(D_sec_texpB_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_texpB); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_texpB_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -1197,8 +1197,8 @@ TEST_CASE("rod_element_property_card_constant_dynamic_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_iner); - std::vector truth = eigen_matrix_to_std_vector(D_sec_iner_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_iner); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_iner_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -1365,8 +1365,8 @@ TEST_CASE("rod_element_property_card_constant_structural_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_ext); - std::vector truth = eigen_matrix_to_std_vector(D_sec_ext_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_ext); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_ext_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -1414,8 +1414,8 @@ TEST_CASE("rod_element_property_card_constant_structural_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_bnd); - std::vector truth = eigen_matrix_to_std_vector(D_sec_bnd_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_bnd); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_bnd_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -1460,8 +1460,8 @@ TEST_CASE("rod_element_property_card_constant_structural_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_bndext); - std::vector truth = eigen_matrix_to_std_vector(D_sec_bndext_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_bndext); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_bndext_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -1500,8 +1500,8 @@ TEST_CASE("rod_element_property_card_constant_structural_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_shr); - std::vector truth = eigen_matrix_to_std_vector(D_sec_shr_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_shr); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_shr_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -1535,8 +1535,8 @@ TEST_CASE("rod_element_property_card_constant_structural_1d", // // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors -// std::vector test = eigen_matrix_to_std_vector(D_sec_spring); -// std::vector truth = eigen_matrix_to_std_vector(D_sec_spring_true); +// std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_spring); +// std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_spring_true); // // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. diff --git a/tests/property/mast_solid_1d_tube2_section_element_property_card.cpp b/tests/property/mast_solid_1d_tube2_section_element_property_card.cpp index 76998228..2caf0dc6 100644 --- a/tests/property/mast_solid_1d_tube2_section_element_property_card.cpp +++ b/tests/property/mast_solid_1d_tube2_section_element_property_card.cpp @@ -760,8 +760,8 @@ TEST_CASE("tube2_element_property_card_constant_heat_transfer_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_conduc); - std::vector truth = eigen_matrix_to_std_vector(D_sec_conduc_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_conduc); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_conduc_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -792,8 +792,8 @@ TEST_CASE("tube2_element_property_card_constant_heat_transfer_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_capac); - std::vector truth = eigen_matrix_to_std_vector(D_sec_capac_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_capac); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_capac_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -936,8 +936,8 @@ TEST_CASE("tube2_element_property_card_constant_thermoelastic_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_texpA); - std::vector truth = eigen_matrix_to_std_vector(D_sec_texpA_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_texpA); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_texpA_true); // Floating point approximations are diffcult to compare since the @@ -984,8 +984,8 @@ TEST_CASE("tube2_element_property_card_constant_thermoelastic_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_texpB); - std::vector truth = eigen_matrix_to_std_vector(D_sec_texpB_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_texpB); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_texpB_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -1165,8 +1165,8 @@ TEST_CASE("tube2_element_property_card_constant_dynamic_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_iner); - std::vector truth = eigen_matrix_to_std_vector(D_sec_iner_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_iner); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_iner_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -1338,8 +1338,8 @@ TEST_CASE("tube2_element_property_card_constant_structural_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_ext); - std::vector truth = eigen_matrix_to_std_vector(D_sec_ext_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_ext); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_ext_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -1385,8 +1385,8 @@ TEST_CASE("tube2_element_property_card_constant_structural_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_bnd); - std::vector truth = eigen_matrix_to_std_vector(D_sec_bnd_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_bnd); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_bnd_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -1428,8 +1428,8 @@ TEST_CASE("tube2_element_property_card_constant_structural_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_bndext); - std::vector truth = eigen_matrix_to_std_vector(D_sec_bndext_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_bndext); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_bndext_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -1466,8 +1466,8 @@ TEST_CASE("tube2_element_property_card_constant_structural_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_shr); - std::vector truth = eigen_matrix_to_std_vector(D_sec_shr_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_shr); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_shr_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -1499,8 +1499,8 @@ TEST_CASE("tube2_element_property_card_constant_structural_1d", // // // Convert the test and truth Eigen::Matrix objects to std::vector // // since Catch2 has built in methods to compare vectors -// std::vector test = eigen_matrix_to_std_vector(D_sec_spring); -// std::vector truth = eigen_matrix_to_std_vector(D_sec_spring_true); +// std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_spring); +// std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_spring_true); // // // Floating point approximations are diffcult to compare since the // // values typically aren't exactly equal due to numerical error. diff --git a/tests/property/mast_solid_1d_tube_section_element_property_card.cpp b/tests/property/mast_solid_1d_tube_section_element_property_card.cpp index 72a44e25..d2711b42 100644 --- a/tests/property/mast_solid_1d_tube_section_element_property_card.cpp +++ b/tests/property/mast_solid_1d_tube_section_element_property_card.cpp @@ -760,8 +760,8 @@ TEST_CASE("tube_element_property_card_constant_heat_transfer_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_conduc); - std::vector truth = eigen_matrix_to_std_vector(D_sec_conduc_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_conduc); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_conduc_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -792,8 +792,8 @@ TEST_CASE("tube_element_property_card_constant_heat_transfer_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_capac); - std::vector truth = eigen_matrix_to_std_vector(D_sec_capac_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_capac); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_capac_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -936,8 +936,8 @@ TEST_CASE("tube_element_property_card_constant_thermoelastic_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_texpA); - std::vector truth = eigen_matrix_to_std_vector(D_sec_texpA_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_texpA); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_texpA_true); // Floating point approximations are diffcult to compare since the @@ -984,8 +984,8 @@ TEST_CASE("tube_element_property_card_constant_thermoelastic_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_texpB); - std::vector truth = eigen_matrix_to_std_vector(D_sec_texpB_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_texpB); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_texpB_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -1163,8 +1163,8 @@ TEST_CASE("tube_element_property_card_constant_dynamic_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_iner); - std::vector truth = eigen_matrix_to_std_vector(D_sec_iner_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_iner); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_iner_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -1336,8 +1336,8 @@ TEST_CASE("tube_element_property_card_constant_structural_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_ext); - std::vector truth = eigen_matrix_to_std_vector(D_sec_ext_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_ext); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_ext_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -1383,8 +1383,8 @@ TEST_CASE("tube_element_property_card_constant_structural_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_bnd); - std::vector truth = eigen_matrix_to_std_vector(D_sec_bnd_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_bnd); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_bnd_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -1426,8 +1426,8 @@ TEST_CASE("tube_element_property_card_constant_structural_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_bndext); - std::vector truth = eigen_matrix_to_std_vector(D_sec_bndext_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_bndext); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_bndext_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -1464,8 +1464,8 @@ TEST_CASE("tube_element_property_card_constant_structural_1d", // Convert the test and truth Eigen::Matrix objects to std::vector // since Catch2 has built in methods to compare vectors - std::vector test = eigen_matrix_to_std_vector(D_sec_shr); - std::vector truth = eigen_matrix_to_std_vector(D_sec_shr_true); + std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_shr); + std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_shr_true); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. @@ -1497,8 +1497,8 @@ TEST_CASE("tube_element_property_card_constant_structural_1d", // // // Convert the test and truth Eigen::Matrix objects to std::vector // // since Catch2 has built in methods to compare vectors -// std::vector test = eigen_matrix_to_std_vector(D_sec_spring); -// std::vector truth = eigen_matrix_to_std_vector(D_sec_spring_true); +// std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_spring); +// std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_spring_true); // // // Floating point approximations are diffcult to compare since the // // values typically aren't exactly equal due to numerical error. diff --git a/tests/test_helpers.cpp b/tests/test_helpers.cpp index 334e780c..085b4d0a 100644 --- a/tests/test_helpers.cpp +++ b/tests/test_helpers.cpp @@ -399,7 +399,7 @@ void TEST::transform_element(libMesh::MeshBase& mesh, const RealMatrixX X0, } -Real approximate_field_function_derivative(const MAST::FieldFunction& f, +Real TEST::approximate_field_function_derivative(const MAST::FieldFunction& f, MAST::Parameter* p, const libMesh::Point& point, const Real& time, @@ -425,7 +425,7 @@ Real approximate_field_function_derivative(const MAST::FieldFunction& f, } -RealMatrixX approximate_field_function_derivative(const MAST::FieldFunction& f, +RealMatrixX TEST::approximate_field_function_derivative(const MAST::FieldFunction& f, MAST::Parameter* p, const libMesh::Point& point, const Real& time, From 8a85e71172adf02a37795194a368446e3fe6a0f2 Mon Sep 17 00:00:00 2001 From: David John Neiferd <13425967+JohnDN90@users.noreply.github.com> Date: Tue, 10 Mar 2020 16:31:02 -0400 Subject: [PATCH 18/27] Fixed bug in calculation of stress points for ROD section. Removed some leftover libMesh::out statements from debugging. --- src/base/warping_assembly.cpp | 12 +----------- .../solid_1d_rod_section_element_property_card.cpp | 4 ++-- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/src/base/warping_assembly.cpp b/src/base/warping_assembly.cpp index 59510a0a..aa4610f4 100644 --- a/src/base/warping_assembly.cpp +++ b/src/base/warping_assembly.cpp @@ -313,16 +313,8 @@ const warping_properties MAST::WarpingAssembly::calculate_warping_properties( // TODO: This isn't quite correct below because it doesn't account for a // changing value of nu like is done above when looping through elements // and quadrature points. - libMesh::out << "Ixxc = " << Ixxc << std::endl; - libMesh::out << "Iyyc = " << Iyyc << std::endl; - libMesh::out << "Ixyc = " << Ixyc << std::endl; - libMesh::out << "delta_s = " << delta_s << std::endl; - libMesh::out << "x_se_1 = " << wp.xs << std::endl; - libMesh::out << "y_se_1 = " << wp.ys << std::endl; wp.xs += -F_warp.dot(Phi)/delta_s; wp.ys += F_warp.dot(Psi)/delta_s; - libMesh::out << "x_se_2 = " << (-F_warp.dot(Phi)/delta_s) << std::endl; - libMesh::out << "y_se_2 = " << (F_warp.dot(Psi)/delta_s) << std::endl; //wp.xs -= localized_F_warp->dot(*localized_Phi)/delta_s; //wp.ys += localized_F_warp->dot(*localized_Psi)/delta_s; @@ -357,9 +349,7 @@ const warping_properties MAST::WarpingAssembly::calculate_warping_properties( wp.ys_t += yc; wp.xs += xc; wp.ys += yc; - libMesh::out << "wp.xs = " << wp.xs << std::endl; - libMesh::out << "wp.ys = " << wp.ys << std::endl; - + return wp; } diff --git a/src/property_cards/solid_1d_rod_section_element_property_card.cpp b/src/property_cards/solid_1d_rod_section_element_property_card.cpp index 2c82d4ad..5f2f37d5 100644 --- a/src/property_cards/solid_1d_rod_section_element_property_card.cpp +++ b/src/property_cards/solid_1d_rod_section_element_property_card.cpp @@ -227,10 +227,10 @@ MAST::Solid1DRodSectionElementPropertyCard::get_stress_points(const libMesh::Poi hy_off(p, t, offset_y); hz_off(p, t, offset_z); libMesh::Point offset(offset_z, offset_y); - + return {libMesh::Point(0., DIM1v, 0.) + offset - ps, libMesh::Point(DIM1v, 0., 0.) + offset - ps, - libMesh::Point(0. -DIM1v, 0.) + offset - ps, + libMesh::Point(0., -DIM1v, 0.) + offset - ps, libMesh::Point(-DIM1v, 0., 0.) + offset - ps }; } From ea86e736ea6ae49faa226e65a19f40ec4a212c73 Mon Sep 17 00:00:00 2001 From: David John Neiferd <13425967+JohnDN90@users.noreply.github.com> Date: Tue, 10 Mar 2020 16:33:06 -0400 Subject: [PATCH 19/27] Modified calculate_stress method to get stress points from property card. Previously hardcoded values for a rectangular section were used. --- src/elasticity/structural_element_1d.cpp | 86 +++++++++++------------- 1 file changed, 40 insertions(+), 46 deletions(-) diff --git a/src/elasticity/structural_element_1d.cpp b/src/elasticity/structural_element_1d.cpp index 98130db7..858d26e9 100644 --- a/src/elasticity/structural_element_1d.cpp +++ b/src/elasticity/structural_element_1d.cpp @@ -166,35 +166,50 @@ MAST::StructuralElement1D::calculate_stress(bool request_derivative, std::unique_ptr fe(_elem.init_fe(true, false)); - const unsigned int - qp_loc_fe_size = (unsigned int)fe->get_qpoints().size(), - n_added_qp = 4; + const unsigned int qp_loc_fe_size = (unsigned int)fe->get_qpoints().size(); + const std::vector& xyz = fe->get_xyz(); + const uint n_added_qp = 4; // Always 4? std::vector qp_loc_fe = fe->get_qpoints(), qp_loc(qp_loc_fe_size*n_added_qp); + // Sensitivity of stress evaluation point + std::vector dqp_loc(qp_loc_fe_size*n_added_qp); + - // we will evaluate the stress at upper and lower layers of element, - // so we will add two new points for each qp_loc - // TODO: move this to element section property class for composite materials - for (unsigned int i=0; i stress_points = _property.get_stress_points(xyz[i], _time, centroid); - qp_loc[i*4+1] = qp_loc_fe[i]; - qp_loc[i*4+1](1) = -1.; - qp_loc[i*4+1](2) = +1.; // upper left - - qp_loc[i*4+2] = qp_loc_fe[i]; - qp_loc[i*4+2](1) = +1.; - qp_loc[i*4+2](2) = -1.; // lower right - - qp_loc[i*4+3] = qp_loc_fe[i]; - qp_loc[i*4+3](1) = -1.; - qp_loc[i*4+3](2) = -1.; // lower left + for (uint j=0; j dstress_points = _property.get_stress_points_derivative(*p, xyz[i], _time, dcentroid); + + for (uint j=0; j &JxW = fe->get_JxW(); - const std::vector& xyz = fe->get_xyz(); const unsigned int n_phi = (unsigned int)fe->n_shape_functions(), n1 = this->n_direct_strain_components(), @@ -271,14 +285,6 @@ MAST::StructuralElement1D::calculate_stress(bool request_derivative, mat_stiff = const_cast(_property.get_material()).stiffness_matrix(1); - // get the thickness values for the bending strain calculation - const MAST::FieldFunction - &hy = _property.get >("hy"), - &hz = _property.get >("hz"), - &hy_off = _property.get >("hy_off"), - &hz_off = _property.get >("hz_off"); - - bool if_vk = (_property.strain_type() == MAST::NONLINEAR_STRAIN), if_bending = (_property.bending_model(_elem) != MAST::NO_BENDING); @@ -351,12 +357,6 @@ MAST::StructuralElement1D::calculate_stress(bool request_derivative, strain += strain_vk; } - // add to this the bending strain - hy (xyz[qp_loc_index], _time, y); - hz (xyz[qp_loc_index], _time, z); - hy_off(xyz[qp_loc_index], _time, y_off); - hz_off(xyz[qp_loc_index], _time, z_off); - // TODO: this assumes isotropic section. Multilayered sections need // special considerations // This operator depends on the y and z thickness values. Sensitivity @@ -364,8 +364,8 @@ MAST::StructuralElement1D::calculate_stress(bool request_derivative, // these thickness values bend->initialize_bending_strain_operator_for_yz(*fe, qp_loc_index, - qp_loc[qp](1) * y/2.+y_off, - qp_loc[qp](2) * z/2.+z_off, + qp_loc[qp](1), + qp_loc[qp](2), Bmat_bend_v, Bmat_bend_w); Bmat_bend_v.vector_mult(strain_bend, _local_sol); @@ -474,16 +474,10 @@ MAST::StructuralElement1D::calculate_stress(bool request_derivative, // include the dependence of strain on the thickness if (if_bending) { - // add to this the bending strain - hy.derivative(*p, xyz[qp_loc_index], _time, y); - hz.derivative(*p, xyz[qp_loc_index], _time, z); - hy_off.derivative(*p, xyz[qp_loc_index], _time, y_off); - hz_off.derivative(*p, xyz[qp_loc_index], _time, z_off); - bend->initialize_bending_strain_operator_for_yz(*fe, qp_loc_index, - qp_loc[qp](1) * y/2.+y_off, - qp_loc[qp](2) * z/2.+z_off, + qp_loc[qp](1), + qp_loc[qp](2), Bmat_bend_v, Bmat_bend_w); Bmat_bend_v.vector_mult(strain_bend, _local_sol); From 9f9f9ed96862f94b8d7333e813206f60efa3872f Mon Sep 17 00:00:00 2001 From: David John Neiferd <13425967+JohnDN90@users.noreply.github.com> Date: Wed, 11 Mar 2020 10:09:09 -0400 Subject: [PATCH 20/27] Refactored code for I1, L, BAR, and ROD sections to minimized duplicate code. --- ...id_1d_I1_section_element_property_card.cpp | 1050 +++-------------- ...olid_1d_I1_section_element_property_card.h | 95 ++ ...lid_1d_L_section_element_property_card.cpp | 2 +- ...d_1d_bar_section_element_property_card.cpp | 929 ++++----------- ...lid_1d_bar_section_element_property_card.h | 87 ++ ...d_1d_rod_section_element_property_card.cpp | 1033 ++++------------ ...lid_1d_rod_section_element_property_card.h | 87 ++ 7 files changed, 834 insertions(+), 2449 deletions(-) create mode 100644 tests/property/mast_solid_1d_I1_section_element_property_card.h create mode 100644 tests/property/mast_solid_1d_bar_section_element_property_card.h create mode 100644 tests/property/mast_solid_1d_rod_section_element_property_card.h diff --git a/tests/property/mast_solid_1d_I1_section_element_property_card.cpp b/tests/property/mast_solid_1d_I1_section_element_property_card.cpp index 790ff608..457cb5e2 100644 --- a/tests/property/mast_solid_1d_I1_section_element_property_card.cpp +++ b/tests/property/mast_solid_1d_I1_section_element_property_card.cpp @@ -1,136 +1,35 @@ // Catch2 includes #include "catch.hpp" -// libMesh includes -#include "libmesh/point.h" - -// MAST includes -#include "base/parameter.h" -#include "base/constant_field_function.h" -#include "property_cards/isotropic_material_property_card.h" -#include "property_cards/solid_1d_I1_section_element_property_card.h" - // Custom includes #include "test_helpers.h" +#include "mast_solid_1d_I1_section_element_property_card.h" -extern libMesh::LibMeshInit* p_global_init; - -#define PI 3.1415926535897932 -/** - * A BAR is defined as a solid rectangular cross section defined by two - * parameters. - */ TEST_CASE("I1_element_property_card_constant_base_1d", "[1D],[isotropic],[constant],[property]") { const uint dim = 1; - - // Define Material Properties as MAST Parameters - MAST::Parameter rho("rho_param", 1420.5); // Density - MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity - MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio - MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity - MAST::Parameter k("k_param", 237.0); // Thermal Conductivity - - const Real G = E() / (2. * (1. + nu())); + const uint n_target_elems = 3000; - // Define Section Properties as MAST Parameters - MAST::Parameter DIM1("DIM1", 3.770); - MAST::Parameter DIM2("DIM2", 0.170); - MAST::Parameter DIM3("DIM3", 5.470); - MAST::Parameter DIM4("DIM4", 5.900); + TEST::AluminumI1Section section(n_target_elems); - MAST::Parameter offset_y("offy_param", -0.787); // Section offset in y-direction - MAST::Parameter offset_z("offz_param", 0.687); // Section offset in z-direction - - // Define Sensitivity Parameters - std::vector sens_params = {&DIM1}; - uint n_s = sens_params.size(); + REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional + REQUIRE( section.depends_on(section.DIM1) ); + REQUIRE( section.depends_on(section.DIM2) ); - // Create field functions to dsitribute these constant parameters throughout the model - // Section Property Field Functions - MAST::ConstantFieldFunction DIM1_f("DIM1", DIM1); - MAST::ConstantFieldFunction DIM2_f("DIM2", DIM2); - MAST::ConstantFieldFunction DIM3_f("DIM3", DIM3); - MAST::ConstantFieldFunction DIM4_f("DIM4", DIM4); - MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); - MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); - // Material Property Field Functions - MAST::ConstantFieldFunction rho_f("rho", rho); - MAST::ConstantFieldFunction E_f("E", E); - MAST::ConstantFieldFunction nu_f("nu", nu); - MAST::ConstantFieldFunction cp_f("cp", cp); - MAST::ConstantFieldFunction k_f("k_th", k); - - // Initialize the material - MAST::IsotropicMaterialPropertyCard material; - - // Add the material property constant field functions to the material card - material.add(rho_f); - material.add(k_f); - material.add(cp_f); - material.add(E_f); - material.add(nu_f); - - // Initialize the section - MAST::Solid1DI1SectionElementPropertyCard section; - - // Add the section property constant field functions to the section card - section.add(DIM1_f); - section.add(DIM2_f); - section.add(DIM3_f); - section.add(DIM4_f); - - section.add(offsety_f); - section.add(offsetz_f); - - // Add the material card to the section card - section.set_material(material); - - // Specify a section orientation point and add it to the section. - RealVectorX orientation = RealVectorX::Zero(3); - orientation(1) = 1.0; - section.y_vector() = orientation; - - // Now initialize the section - section.init(*p_global_init); + REQUIRE( section.depends_on(section.offset_y) ); + REQUIRE( section.depends_on(section.offset_z) ); - REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional - REQUIRE( section.depends_on(DIM1) ); - REQUIRE( section.depends_on(offset_y) ); - REQUIRE( section.depends_on(offset_z) ); - REQUIRE( section.depends_on(k) ); - REQUIRE( section.depends_on(cp) ); - REQUIRE( section.depends_on(rho) ); + REQUIRE( section.depends_on(section.material.k) ); + REQUIRE( section.depends_on(section.material.cp) ); + REQUIRE( section.depends_on(section.material.rho) ); + REQUIRE( section.depends_on(section.material.E) ); + REQUIRE( section.depends_on(section.material.nu) ); + REQUIRE( section.depends_on(section.material.alpha) ); REQUIRE( section.if_isotropic() ); - // True values - const Real area_true = 2.6241000000000039e+00; - const Real torsion_constant_true = 3.4912416307463445e-02; - const Real first_area_moment_z_true = -2.0651667000000016e+00; - const Real first_area_moment_y_true = 1.8027567000000015e+00; - const Real second_area_moment_zz_true = 1.7639240550400139e+01; - const Real second_area_moment_yy_true = 3.4324069553999919e+00; - const Real second_area_moment_zy_true = -1.4187695228999926e+00; - const Real second_area_moment_polar_true = 2.1071647505800129e+01; - const Real Izzc_true = 1.6013954357500140e+01; - const Real Iyyc_true = 2.1939131024999914e+00; - const Real Izyc_true = 7.5495165674510645e-15; - const Real Ipc_true = 1.8207867460000131e+01; - const Real warping_constant_true = 1.7690289289249652e+01; - const Real kappa_z_true = 5.4403106725573769e-01; - const Real kappa_y_true = 3.5065087923352467e-01; - const Real xs_true = 6.8699874537432160e-01; - const Real ys_true = -7.8699671905199586e-01; - const Real xst_true = 6.8699874537432160e-01; - const Real yst_true = -7.8699671905199586e-01; - const Real xc_true = 6.8699999999999961e-01; - const Real yc_true = -7.8699999999999948e-01; - const libMesh::Point centroid_true(xc_true, yc_true); - const libMesh::Point shear_center_true(xs_true, ys_true); - const libMesh::Point point(4.3, -3.5, -6.7); const Real time = 8.22; @@ -139,17 +38,17 @@ TEST_CASE("I1_element_property_card_constant_base_1d", Real area; const MAST::FieldFunction& Area = section.A(); Area(point, time, area); - CHECK( area == Approx(area_true) ); + CHECK( area == Approx(section.area_true) ); Real first_area_moment_y; const MAST::FieldFunction& Ay = section.Ay(); Ay(point, time, first_area_moment_y); - CHECK( first_area_moment_y == Approx(first_area_moment_y_true) ); + CHECK( first_area_moment_y == Approx(section.first_area_moment_y_true) ); Real first_area_moment_z; const MAST::FieldFunction& Az = section.Az(); Az(point, time, first_area_moment_z); - CHECK( first_area_moment_z == Approx(first_area_moment_z_true) ); + CHECK( first_area_moment_z == Approx(section.first_area_moment_z_true) ); RealMatrixX I; const MAST::FieldFunction& Inertias = section.I(); @@ -158,60 +57,55 @@ TEST_CASE("I1_element_property_card_constant_base_1d", Real Iyy = I(1,1); Real Izz = I(0,0); Real Izy = I(0,1); - CHECK( Izz == Approx(second_area_moment_zz_true) ); - CHECK( Iyy == Approx(second_area_moment_yy_true) ); - CHECK( Izy == Approx(second_area_moment_zy_true) ); - + CHECK( Izz == Approx(section.second_area_moment_zz_true) ); + CHECK( Iyy == Approx(section.second_area_moment_yy_true) ); + CHECK( Izy == Approx(section.second_area_moment_zy_true) ); + Real Ip; const MAST::FieldFunction& PolarInertia = section.Ip(); PolarInertia(point, time, Ip); - CHECK( Ip == Approx(second_area_moment_polar_true) ); + CHECK( Ip == Approx(section.second_area_moment_polar_true) ); Real torsion_constant; const MAST::FieldFunction& TorsionConstant = section.J(); TorsionConstant(point, time, torsion_constant); - CHECK( torsion_constant == Approx(torsion_constant_true).epsilon(0.005)); + CHECK( torsion_constant == Approx(section.torsion_constant_true).epsilon(0.005)); - Real warping_constant; - const MAST::FieldFunction& WarpingConstant = section.Gam(); - WarpingConstant(point, time, warping_constant); - CHECK( warping_constant == Approx(warping_constant_true).epsilon(0.005) ); + libMesh::Point centroid = section.get_centroid(point, time); + CHECK( centroid(0) == Approx(section.centroid_true(0)) ); + CHECK( centroid(1) == Approx(section.centroid_true(1)) ); + libMesh::Point shear_center = section.get_shear_center(point, time); + CHECK(shear_center(0) == Approx(section.xs_true).epsilon(0.005)); + CHECK(shear_center(1) == Approx(section.ys_true).epsilon(0.005)); + RealMatrixX shear_coefficients; const MAST::FieldFunction& ShearCoefficientMatrix = section.Kap(); ShearCoefficientMatrix(point, time, shear_coefficients); - CHECK( shear_coefficients(0,0) == Approx(kappa_z_true).epsilon(0.005) ); - CHECK( shear_coefficients(1,1) == Approx(kappa_y_true).epsilon(0.005) ); - - libMesh::Point centroid = section.get_centroid(point, time); - CHECK( centroid(0) == Approx(centroid_true(0)) ); - CHECK( centroid(1) == Approx(centroid_true(1)) ); - - libMesh::Point shear_center = section.get_shear_center(point, time); - CHECK(shear_center(0) == Approx(xs_true).epsilon(0.005)); - CHECK(shear_center(1) == Approx(ys_true).epsilon(0.005)); + CHECK( shear_coefficients(0,0) == Approx(section.kappa_z_true).epsilon(0.005) ); + CHECK( shear_coefficients(1,1) == Approx(section.kappa_y_true).epsilon(0.005) ); + + Real warping_constant; + const MAST::FieldFunction& WarpingConstant = section.Gam(); + WarpingConstant(point, time, warping_constant); + CHECK( warping_constant == Approx(section.warping_constant_true).epsilon(0.005) ); } SECTION("stress_points") { - const std::vector stress_points_true = { - libMesh::Point(1.9700000000000000e+00, 2.9500000000000002e+00, 0.), - libMesh::Point(1.9700000000000000e+00, -2.9500000000000002e+00, 0.), - libMesh::Point(-1.9700000000000000e+00, -2.9500000000000002e+00, 0.), - libMesh::Point(-1.9700000000000000e+00, 2.9500000000000002e+00, 0.) - }; libMesh::Point centroid = section.get_centroid(point, time); - CHECK( centroid(0) == Approx(centroid_true(0)) ); - CHECK( centroid(1) == Approx(centroid_true(1)) ); + CHECK( centroid(0) == Approx(section.centroid_true(0)) ); + CHECK( centroid(1) == Approx(section.centroid_true(1)) ); std::vector stress_points = section.get_stress_points(point, time, centroid); for (uint i=0; i sens_params = {&DIM1, &DIM2, &DIM3, &DIM4}; + std::vector sens_params = {§ion.DIM1}; uint n_s = sens_params.size(); - // Create field functions to dsitribute these constant parameters throughout the model - // Section Property Field Functions - MAST::ConstantFieldFunction DIM1_f("DIM1", DIM1); - MAST::ConstantFieldFunction DIM2_f("DIM2", DIM2); - MAST::ConstantFieldFunction DIM3_f("DIM3", DIM3); - MAST::ConstantFieldFunction DIM4_f("DIM4", DIM4); - MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); - MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); - // Material Property Field Functions - MAST::ConstantFieldFunction rho_f("rho", rho); - MAST::ConstantFieldFunction E_f("E", E); - MAST::ConstantFieldFunction nu_f("nu", nu); - MAST::ConstantFieldFunction cp_f("cp", cp); - MAST::ConstantFieldFunction k_f("k_th", k); - - // Initialize the material - MAST::IsotropicMaterialPropertyCard material; - - // Add the material property constant field functions to the material card - material.add(rho_f); - material.add(k_f); - material.add(cp_f); - material.add(E_f); - material.add(nu_f); - - // Initialize the section - MAST::Solid1DI1SectionElementPropertyCard section; - - // Add the section property constant field functions to the section card - section.add(DIM1_f); - section.add(DIM2_f); - section.add(DIM3_f); - section.add(DIM4_f); - - section.add(offsety_f); - section.add(offsetz_f); - - // Add the material card to the section card - section.set_material(material); - - // Specify a section orientation point and add it to the section. - RealVectorX orientation = RealVectorX::Zero(3); - orientation(1) = 1.0; - section.y_vector() = orientation; - - // Now initialize the section - section.init(*p_global_init); - - REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional - REQUIRE( section.depends_on(DIM1) ); - REQUIRE( section.depends_on(offset_y) ); - REQUIRE( section.depends_on(offset_z) ); - REQUIRE( section.depends_on(k) ); - REQUIRE( section.depends_on(cp) ); - REQUIRE( section.depends_on(rho) ); - REQUIRE( section.if_isotropic() ); - // True values - const Real area_true = 2.6241000000000039e+00; - const Real torsion_constant_true = 3.4912416307463445e-02; - const Real first_area_moment_z_true = -2.0651667000000016e+00; - const Real first_area_moment_y_true = 1.8027567000000015e+00; - const Real second_area_moment_zz_true = 1.7639240550400139e+01; - const Real second_area_moment_yy_true = 3.4324069553999919e+00; - const Real second_area_moment_zy_true = -1.4187695228999926e+00; - const Real second_area_moment_polar_true = 2.1071647505800129e+01; - const Real Izzc_true = 1.6013954357500140e+01; - const Real Iyyc_true = 2.1939131024999914e+00; - const Real Izyc_true = 7.5495165674510645e-15; - const Real Ipc_true = 1.8207867460000131e+01; - const Real warping_constant_true = 1.7690289289249652e+01; - const Real kappa_z_true = 5.4403106725573769e-01; - const Real kappa_y_true = 3.5065087923352467e-01; - const Real xs_true = 6.8699874537432160e-01; - const Real ys_true = -7.8699671905199586e-01; - const Real xst_true = 6.8699874537432160e-01; - const Real yst_true = -7.8699671905199586e-01; - const Real xc_true = 6.8699999999999961e-01; - const Real yc_true = -7.8699999999999948e-01; - const libMesh::Point centroid_true(xc_true, yc_true); - const libMesh::Point shear_center_true(xs_true, ys_true); - const libMesh::Point point(4.3, -3.5, -6.7); const Real time = 8.22; @@ -373,23 +170,9 @@ TEST_CASE("I1_element_property_card_constant_base_sensitivity_1d", std::vector dA_cd(n_s); for (uint i=0; iname() << " = " << dA[i] << "\tdA_cd = " << dA_cd[i] << std::endl; + //libMesh::out << "dA_d" << sens_params[i]->name() << " = " << dA[i] << "\tdA_cd = " << dA_cd[i] << std::endl; REQUIRE(dA[i] == Approx(dA_cd[i])); } @@ -437,21 +220,7 @@ TEST_CASE("I1_element_property_card_constant_base_sensitivity_1d", std::vector dAy_cd(n_s); for (uint i=0; iname() << " = " << dAy[i] << "\tdAy_cd = " << dAy_cd[i] << std::endl; REQUIRE(dAy[i] == Approx(dAy_cd[i])); @@ -468,21 +237,7 @@ TEST_CASE("I1_element_property_card_constant_base_sensitivity_1d", std::vector dAz_cd(n_s); for (uint i=0; iname() << " = " << dAz[i] << "\tdAz_cd = " << dAz_cd[i] << std::endl; REQUIRE(dAz[i] == Approx(dAz_cd[i])); @@ -500,21 +255,7 @@ TEST_CASE("I1_element_property_card_constant_base_sensitivity_1d", std::vector dI_cd(n_s); for (uint i=0; iname() << " =\n" << dI[i] << "\ndI_cd = \n" << dI_cd[i] << std::endl; @@ -547,21 +288,7 @@ TEST_CASE("I1_element_property_card_constant_base_sensitivity_1d", std::vector dIp_cd(n_s); for (uint i=0; iname() << " = " << dIp[i] << "\tdIp_cd = " << dIp_cd[i] << std::endl; REQUIRE(dIp[i] == Approx(dIp_cd[i])); @@ -600,38 +327,24 @@ TEST_CASE("I1_element_property_card_constant_base_sensitivity_1d", // } - // Torsion Constant Sensitivity Check - // NOTE: The field function below is not made constant because currently a finite difference is used to calculate sensitivity. - MAST::FieldFunction& TorsionConstant = section.J(); - std::vector dJ(n_s); - for (uint i=0; i dJ_cd(n_s); - for (uint i=0; iname() << " = " << dJ[i] << "\tdJ_cd = " << dJ_cd[i] << std::endl; - REQUIRE(dJ[i] == Approx(dJ_cd[i]).epsilon(0.1) ); - // NOTE: 10% error margin due to 'exact' sensitivity being calculated using finite difference - } +// // Torsion Constant Sensitivity Check +// // NOTE: The field function below is not made constant because currently a finite difference is used to calculate sensitivity. +// MAST::FieldFunction& TorsionConstant = section.J(); +// std::vector dJ(n_s); +// for (uint i=0; i dJ_cd(n_s); +// for (uint i=0; iname() << " = " << dJ[i] << "\tdJ_cd = " << dJ_cd[i] << std::endl; +// REQUIRE(dJ[i] == Approx(dJ_cd[i]).epsilon(0.1) ); +// // NOTE: 10% error margin due to 'exact' sensitivity being calculated using finite difference +// } // Shear Coefficient Sensitivity Check @@ -646,21 +359,7 @@ TEST_CASE("I1_element_property_card_constant_base_sensitivity_1d", std::vector dK_cd(n_s); for (uint i=0; iname() << " =\n" << dK[i] << "\ndK_cd = \n" << dK_cd[i] << std::endl; @@ -695,21 +394,7 @@ TEST_CASE("I1_element_property_card_constant_base_sensitivity_1d", std::vector dW_cd(n_s); for (uint i=0; iname() << " = " << dW[i] << "\tdW_cd = " << dW_cd[i] << std::endl; REQUIRE(dW[i] == Approx(dW_cd[i]).epsilon(0.1) ); @@ -718,123 +403,32 @@ TEST_CASE("I1_element_property_card_constant_base_sensitivity_1d", } + TEST_CASE("I1_element_property_card_constant_heat_transfer_1d", "[heat_transfer],[1D],[isotropic],[constant],[property]") { const uint dim = 1; - - // Define Material Properties as MAST Parameters - MAST::Parameter rho("rho_param", 1420.5); // Density - MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity - MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio - MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity - MAST::Parameter k("k_param", 237.0); // Thermal Conductivity + const uint n_target_elems = 3000; - const Real G = E() / (2. * (1. + nu())); - - // Define Section Properties as MAST Parameters - MAST::Parameter DIM1("DIM1", 3.770); - MAST::Parameter DIM2("DIM2", 0.170); - MAST::Parameter DIM3("DIM3", 5.470); - MAST::Parameter DIM4("DIM4", 5.900); - - MAST::Parameter offset_y("offy_param", -0.787); // Section offset in y-direction - MAST::Parameter offset_z("offz_param", 0.687); // Section offset in z-direction - - // Define Sensitivity Parameters - std::vector sens_params = {&DIM1}; - uint n_s = sens_params.size(); - - // Create field functions to dsitribute these constant parameters throughout the model - // Section Property Field Functions - MAST::ConstantFieldFunction DIM1_f("DIM1", DIM1); - MAST::ConstantFieldFunction DIM2_f("DIM2", DIM2); - MAST::ConstantFieldFunction DIM3_f("DIM3", DIM3); - MAST::ConstantFieldFunction DIM4_f("DIM4", DIM4); - MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); - MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); - // Material Property Field Functions - MAST::ConstantFieldFunction rho_f("rho", rho); - MAST::ConstantFieldFunction E_f("E", E); - MAST::ConstantFieldFunction nu_f("nu", nu); - MAST::ConstantFieldFunction cp_f("cp", cp); - MAST::ConstantFieldFunction k_f("k_th", k); - - // Initialize the material - MAST::IsotropicMaterialPropertyCard material; - - // Add the material property constant field functions to the material card - material.add(rho_f); - material.add(k_f); - material.add(cp_f); - material.add(E_f); - material.add(nu_f); - - // Initialize the section - MAST::Solid1DI1SectionElementPropertyCard section; - - // Add the section property constant field functions to the section card - section.add(DIM1_f); - section.add(DIM2_f); - section.add(DIM3_f); - section.add(DIM4_f); - - section.add(offsety_f); - section.add(offsetz_f); - - // Add the material card to the section card - section.set_material(material); - - // Specify a section orientation point and add it to the section. - RealVectorX orientation = RealVectorX::Zero(3); - orientation(1) = 1.0; - section.y_vector() = orientation; - - // Now initialize the section - section.init(*p_global_init); + TEST::AluminumI1Section section(n_target_elems); REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional - REQUIRE( section.depends_on(DIM1) ); - REQUIRE( section.depends_on(offset_y) ); - REQUIRE( section.depends_on(offset_z) ); - REQUIRE( section.depends_on(k) ); - REQUIRE( section.depends_on(cp) ); - REQUIRE( section.depends_on(rho) ); + REQUIRE( section.depends_on(section.DIM1) ); + REQUIRE( section.depends_on(section.offset_y) ); + REQUIRE( section.depends_on(section.offset_z) ); + REQUIRE( section.depends_on(section.material.k) ); + REQUIRE( section.depends_on(section.material.cp) ); + REQUIRE( section.depends_on(section.material.rho) ); REQUIRE( section.if_isotropic() ); - // True values - const Real area_true = 2.6241000000000039e+00; - const Real torsion_constant_true = 3.4912416307463445e-02; - const Real first_area_moment_z_true = -2.0651667000000016e+00; - const Real first_area_moment_y_true = 1.8027567000000015e+00; - const Real second_area_moment_zz_true = 1.7639240550400139e+01; - const Real second_area_moment_yy_true = 3.4324069553999919e+00; - const Real second_area_moment_zy_true = -1.4187695228999926e+00; - const Real second_area_moment_polar_true = 2.1071647505800129e+01; - const Real Izzc_true = 1.6013954357500140e+01; - const Real Iyyc_true = 2.1939131024999914e+00; - const Real Izyc_true = 7.5495165674510645e-15; - const Real Ipc_true = 1.8207867460000131e+01; - const Real warping_constant_true = 1.7690289289249652e+01; - const Real kappa_z_true = 5.4403106725573769e-01; - const Real kappa_y_true = 3.5065087923352467e-01; - const Real xs_true = 6.8699874537432160e-01; - const Real ys_true = -7.8699671905199586e-01; - const Real xst_true = 6.8699874537432160e-01; - const Real yst_true = -7.8699671905199586e-01; - const Real xc_true = 6.8699999999999961e-01; - const Real yc_true = -7.8699999999999948e-01; - const libMesh::Point centroid_true(xc_true, yc_true); - const libMesh::Point shear_center_true(xs_true, ys_true); - const libMesh::Point point(4.3, -3.5, -6.7); const Real time = 8.22; Real area; const MAST::FieldFunction& Area = section.A(); Area(point, time, area); - REQUIRE( area == Approx(area_true) ); + REQUIRE( area == Approx(section.area_true) ); SECTION("1D section thermal conductance matrix") @@ -858,17 +452,12 @@ TEST_CASE("I1_element_property_card_constant_heat_transfer_1d", // Hard-coded value of the section's extension stiffness RealMatrixX D_sec_conduc_true = RealMatrixX::Zero(1,1); - D_sec_conduc_true(0,0) = k() * area_true; - - // Convert the test and truth Eigen::Matrix objects to std::vector - // since Catch2 has built in methods to compare vectors - std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_conduc); - std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_conduc_true); + D_sec_conduc_true(0,0) = section.material.k() * section.area_true; // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. // Therefore, we use the Approx comparison instead of Equals - CHECK_THAT( test, Catch::Approx(truth) ); + CHECK_THAT( TEST::eigen_matrix_to_std_vector(D_sec_conduc), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_conduc_true)) ); } SECTION("1D section thermal capacitance matrix") @@ -892,17 +481,12 @@ TEST_CASE("I1_element_property_card_constant_heat_transfer_1d", // Hard-coded value of the section's extension stiffness RealMatrixX D_sec_capac_true = RealMatrixX::Zero(1,1); - D_sec_capac_true(0,0) = rho() * cp() * area_true; - - // Convert the test and truth Eigen::Matrix objects to std::vector - // since Catch2 has built in methods to compare vectors - std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_capac); - std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_capac_true); + D_sec_capac_true(0,0) = section.material.rho() * section.material.cp() * section.area_true; // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. // Therefore, we use the Approx comparison instead of Equals - CHECK_THAT( test, Catch::Approx(truth) ); + CHECK_THAT( TEST::eigen_matrix_to_std_vector(D_sec_capac), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_capac_true)) ); } } @@ -911,115 +495,20 @@ TEST_CASE("I1_element_property_card_constant_thermoelastic_1d", "[thermoelastic],[1D],[isotropic],[constant],[property]") { const uint dim = 1; - - // Define Material Properties as MAST Parameters - MAST::Parameter rho("rho_param", 1420.5); // Density - MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity - MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio - MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity - MAST::Parameter k("k_param", 237.0); // Thermal Conductivity - MAST::Parameter alpha("alpha_parm", 5.23e-05); // Coeff. of Thermal Exp. - - const Real G = E() / (2. * (1. + nu())); - - // Define Section Properties as MAST Parameters - MAST::Parameter DIM1("DIM1", 3.770); - MAST::Parameter DIM2("DIM2", 0.170); - MAST::Parameter DIM3("DIM3", 5.470); - MAST::Parameter DIM4("DIM4", 5.900); + const uint n_target_elems = 3000; - MAST::Parameter offset_y("offy_param", -0.787); // Section offset in y-direction - MAST::Parameter offset_z("offz_param", 0.687); // Section offset in z-direction - - // Define Sensitivity Parameters - std::vector sens_params = {&DIM1}; - uint n_s = sens_params.size(); - - // Create field functions to dsitribute these constant parameters throughout the model - // Section Property Field Functions - MAST::ConstantFieldFunction DIM1_f("DIM1", DIM1); - MAST::ConstantFieldFunction DIM2_f("DIM2", DIM2); - MAST::ConstantFieldFunction DIM3_f("DIM3", DIM3); - MAST::ConstantFieldFunction DIM4_f("DIM4", DIM4); - MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); - MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); - // Material Property Field Functions - MAST::ConstantFieldFunction rho_f("rho", rho); - MAST::ConstantFieldFunction E_f("E", E); - MAST::ConstantFieldFunction nu_f("nu", nu); - MAST::ConstantFieldFunction cp_f("cp", cp); - MAST::ConstantFieldFunction k_f("k_th", k); - MAST::ConstantFieldFunction alpha_f("alpha_expansion", alpha); - - // Initialize the material - MAST::IsotropicMaterialPropertyCard material; - - // Add the material property constant field functions to the material card - material.add(rho_f); - material.add(k_f); - material.add(cp_f); - material.add(E_f); - material.add(nu_f); - material.add(alpha_f); - - // Initialize the section - MAST::Solid1DI1SectionElementPropertyCard section; - - // Add the section property constant field functions to the section card - section.add(DIM1_f); - section.add(DIM2_f); - section.add(DIM3_f); - section.add(DIM4_f); - - section.add(offsety_f); - section.add(offsetz_f); - - // Add the material card to the section card - section.set_material(material); - - // Specify a section orientation point and add it to the section. - RealVectorX orientation = RealVectorX::Zero(3); - orientation(1) = 1.0; - section.y_vector() = orientation; - - // Now initialize the section - section.init(*p_global_init); + TEST::AluminumI1Section section(n_target_elems); REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional - REQUIRE( section.depends_on(DIM1) ); - REQUIRE( section.depends_on(offset_y) ); - REQUIRE( section.depends_on(offset_z) ); - REQUIRE( section.depends_on(k) ); - REQUIRE( section.depends_on(cp) ); - REQUIRE( section.depends_on(rho) ); + REQUIRE( section.depends_on(section.DIM1) ); + REQUIRE( section.depends_on(section.offset_y) ); + REQUIRE( section.depends_on(section.offset_z) ); + REQUIRE( section.depends_on(section.material.k) ); + REQUIRE( section.depends_on(section.material.cp) ); + REQUIRE( section.depends_on(section.material.rho) ); REQUIRE( section.if_isotropic() ); - // True values - const Real area_true = 2.6241000000000039e+00; - const Real torsion_constant_true = 3.4912416307463445e-02; - const Real first_area_moment_z_true = -2.0651667000000016e+00; - const Real first_area_moment_y_true = 1.8027567000000015e+00; - const Real second_area_moment_zz_true = 1.7639240550400139e+01; - const Real second_area_moment_yy_true = 3.4324069553999919e+00; - const Real second_area_moment_zy_true = -1.4187695228999926e+00; - const Real second_area_moment_polar_true = 2.1071647505800129e+01; - const Real Izzc_true = 1.6013954357500140e+01; - const Real Iyyc_true = 2.1939131024999914e+00; - const Real Izyc_true = 7.5495165674510645e-15; - const Real Ipc_true = 1.8207867460000131e+01; - const Real warping_constant_true = 1.7690289289249652e+01; - const Real kappa_z_true = 5.4403106725573769e-01; - const Real kappa_y_true = 3.5065087923352467e-01; - const Real xs_true = 6.8699874537432160e-01; - const Real ys_true = -7.8699671905199586e-01; - const Real xst_true = 6.8699874537432160e-01; - const Real yst_true = -7.8699671905199586e-01; - const Real xc_true = 6.8699999999999961e-01; - const Real yc_true = -7.8699999999999948e-01; - const libMesh::Point centroid_true(xc_true, yc_true); - const libMesh::Point shear_center_true(xs_true, ys_true); - const libMesh::Point point(4.3, -3.5, -6.7); const Real time = 8.22; @@ -1039,7 +528,7 @@ TEST_CASE("I1_element_property_card_constant_thermoelastic_1d", Real area; const MAST::FieldFunction& Area = section.A(); Area(point, time, area); - CHECK( area == Approx(area_true) ); + CHECK( area == Approx(section.area_true) ); std::unique_ptr> texp_A_mat = section.thermal_expansion_A_matrix(); @@ -1050,18 +539,12 @@ TEST_CASE("I1_element_property_card_constant_thermoelastic_1d", // Hard-coded value of the section's extension stiffness RealMatrixX D_sec_texpA_true = RealMatrixX::Zero(2,1); - D_sec_texpA_true(0,0) = E() * alpha() * area_true; - - // Convert the test and truth Eigen::Matrix objects to std::vector - // since Catch2 has built in methods to compare vectors - std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_texpA); - std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_texpA_true); - + D_sec_texpA_true(0,0) = section.material.E() * section.material.alpha() * section.area_true; // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. // Therefore, we use the Approx comparison instead of Equals - CHECK_THAT( test, Catch::Approx(truth) ); + CHECK_THAT( TEST::eigen_matrix_to_std_vector(D_sec_texpA), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_texpA_true)) ); } SECTION("1D thermal expansion B matrix") @@ -1080,12 +563,12 @@ TEST_CASE("I1_element_property_card_constant_thermoelastic_1d", Real first_area_moment_y; const MAST::FieldFunction& Ay = section.Ay(); Ay(point, time, first_area_moment_y); - CHECK( first_area_moment_y == Approx(first_area_moment_y_true) ); + CHECK( first_area_moment_y == Approx(section.first_area_moment_y_true) ); Real first_area_moment_z; const MAST::FieldFunction& Az = section.Az(); Az(point, time, first_area_moment_z); - CHECK( first_area_moment_z == Approx(first_area_moment_z_true) ); + CHECK( first_area_moment_z == Approx(section.first_area_moment_z_true) ); std::unique_ptr> texp_B_mat = section.thermal_expansion_B_matrix(); @@ -1098,133 +581,35 @@ TEST_CASE("I1_element_property_card_constant_thermoelastic_1d", // Hard-coded value of the section's extension stiffness RealMatrixX D_sec_texpB_true = RealMatrixX::Zero(2,1); - D_sec_texpB_true(0,0) = E() * alpha() * first_area_moment_z_true; - D_sec_texpB_true(1,0) = E() * alpha() * first_area_moment_y_true; - - - // Convert the test and truth Eigen::Matrix objects to std::vector - // since Catch2 has built in methods to compare vectors - std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_texpB); - std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_texpB_true); + D_sec_texpB_true(0,0) = section.material.E() * section.material.alpha() * section.first_area_moment_z_true; + D_sec_texpB_true(1,0) = section.material.E() * section.material.alpha() * section.first_area_moment_y_true; // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. // Therefore, we use the Approx comparison instead of Equals - CHECK_THAT( test, Catch::Approx(truth) ); + CHECK_THAT( TEST::eigen_matrix_to_std_vector(D_sec_texpB), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_texpB_true)) ); } } -// FIXME: I don't think this one is being run. + TEST_CASE("I1_element_property_card_constant_dynamic_1d", "[dynamic],[1D],[isotropic],[constant],[property]") { const uint dim = 1; - - // Define Material Properties as MAST Parameters - MAST::Parameter rho("rho_param", 1420.5); // Density - MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity - MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio - MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity - MAST::Parameter k("k_param", 237.0); // Thermal Conductivity + const uint n_target_elems = 3000; - const Real G = E() / (2. * (1. + nu())); - - // Define Section Properties as MAST Parameters - MAST::Parameter DIM1("DIM1", 3.770); - MAST::Parameter DIM2("DIM2", 0.170); - MAST::Parameter DIM3("DIM3", 5.470); - MAST::Parameter DIM4("DIM4", 5.900); - - MAST::Parameter offset_y("offy_param", -0.787); // Section offset in y-direction - MAST::Parameter offset_z("offz_param", 0.687); // Section offset in z-direction - - // Define Sensitivity Parameters - std::vector sens_params = {&DIM1}; - uint n_s = sens_params.size(); - - // Create field functions to dsitribute these constant parameters throughout the model - // Section Property Field Functions - MAST::ConstantFieldFunction DIM1_f("DIM1", DIM1); - MAST::ConstantFieldFunction DIM2_f("DIM2", DIM2); - MAST::ConstantFieldFunction DIM3_f("DIM3", DIM3); - MAST::ConstantFieldFunction DIM4_f("DIM4", DIM4); - MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); - MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); - // Material Property Field Functions - MAST::ConstantFieldFunction rho_f("rho", rho); - MAST::ConstantFieldFunction E_f("E", E); - MAST::ConstantFieldFunction nu_f("nu", nu); - MAST::ConstantFieldFunction cp_f("cp", cp); - MAST::ConstantFieldFunction k_f("k_th", k); - - // Initialize the material - MAST::IsotropicMaterialPropertyCard material; - - // Add the material property constant field functions to the material card - material.add(rho_f); - material.add(k_f); - material.add(cp_f); - material.add(E_f); - material.add(nu_f); - - // Initialize the section - MAST::Solid1DI1SectionElementPropertyCard section; - - // Add the section property constant field functions to the section card - section.add(DIM1_f); - section.add(DIM2_f); - section.add(DIM3_f); - section.add(DIM4_f); - - section.add(offsety_f); - section.add(offsetz_f); - - // Add the material card to the section card - section.set_material(material); - - // Specify a section orientation point and add it to the section. - RealVectorX orientation = RealVectorX::Zero(3); - orientation(1) = 1.0; - section.y_vector() = orientation; - - // Now initialize the section - section.init(*p_global_init); + TEST::AluminumI1Section section(n_target_elems); REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional - REQUIRE( section.depends_on(DIM1) ); - REQUIRE( section.depends_on(offset_y) ); - REQUIRE( section.depends_on(offset_z) ); - REQUIRE( section.depends_on(k) ); - REQUIRE( section.depends_on(cp) ); - REQUIRE( section.depends_on(rho) ); + REQUIRE( section.depends_on(section.DIM1) ); + REQUIRE( section.depends_on(section.offset_y) ); + REQUIRE( section.depends_on(section.offset_z) ); + REQUIRE( section.depends_on(section.material.k) ); + REQUIRE( section.depends_on(section.material.cp) ); + REQUIRE( section.depends_on(section.material.rho) ); REQUIRE( section.if_isotropic() ); - // True values - const Real area_true = 2.6241000000000039e+00; - const Real torsion_constant_true = 3.4912416307463445e-02; - const Real first_area_moment_z_true = -2.0651667000000016e+00; - const Real first_area_moment_y_true = 1.8027567000000015e+00; - const Real second_area_moment_zz_true = 1.7639240550400139e+01; - const Real second_area_moment_yy_true = 3.4324069553999919e+00; - const Real second_area_moment_zy_true = -1.4187695228999926e+00; - const Real second_area_moment_polar_true = 2.1071647505800129e+01; - const Real Izzc_true = 1.6013954357500140e+01; - const Real Iyyc_true = 2.1939131024999914e+00; - const Real Izyc_true = 7.5495165674510645e-15; - const Real Ipc_true = 1.8207867460000131e+01; - const Real warping_constant_true = 1.7690289289249652e+01; - const Real kappa_z_true = 5.4403106725573769e-01; - const Real kappa_y_true = 3.5065087923352467e-01; - const Real xs_true = 6.8699874537432160e-01; - const Real ys_true = -7.8699671905199586e-01; - const Real xst_true = 6.8699874537432160e-01; - const Real yst_true = -7.8699671905199586e-01; - const Real xc_true = 6.8699999999999961e-01; - const Real yc_true = -7.8699999999999948e-01; - const libMesh::Point centroid_true(xc_true, yc_true); - const libMesh::Point shear_center_true(xs_true, ys_true); - const libMesh::Point point(4.3, -3.5, -6.7); const Real time = 8.22; @@ -1250,29 +635,30 @@ TEST_CASE("I1_element_property_card_constant_dynamic_1d", // Hard-coded value of the section's extension stiffness RealMatrixX D_sec_iner_true = RealMatrixX::Zero(6,6); + Real area; const MAST::FieldFunction& Area = section.A(); Area(point, time, area); - REQUIRE( area == Approx(area_true) ); - D_sec_iner_true(0,0) = D_sec_iner_true(1,1) = D_sec_iner_true(2,2) = area_true; + REQUIRE( area == Approx(section.area_true) ); + D_sec_iner_true(0,0) = D_sec_iner_true(1,1) = D_sec_iner_true(2,2) = section.area_true; Real Ip; const MAST::FieldFunction& PolarInertia = section.Ip(); PolarInertia(point, time, Ip); - CHECK( Ip == Approx(second_area_moment_polar_true) ); - D_sec_iner_true(3,3) = second_area_moment_polar_true; + CHECK( Ip == Approx(section.second_area_moment_polar_true) ); + D_sec_iner_true(3,3) = section.second_area_moment_polar_true; Real first_area_moment_y; const MAST::FieldFunction& Ay = section.Ay(); Ay(point, time, first_area_moment_y); - CHECK( first_area_moment_y == Approx(first_area_moment_y_true) ); - D_sec_iner_true(0,4) = D_sec_iner_true(4,0) = first_area_moment_y_true; + CHECK( first_area_moment_y == Approx(section.first_area_moment_y_true) ); + D_sec_iner_true(0,4) = D_sec_iner_true(4,0) = section.first_area_moment_y_true; Real first_area_moment_z; const MAST::FieldFunction& Az = section.Az(); Az(point, time, first_area_moment_z); - CHECK( first_area_moment_z == Approx(first_area_moment_z_true) ); - D_sec_iner_true(0,5) = D_sec_iner_true(5,0) = first_area_moment_z_true; + CHECK( first_area_moment_z == Approx(section.first_area_moment_z_true) ); + D_sec_iner_true(0,5) = D_sec_iner_true(5,0) = section.first_area_moment_z_true; RealMatrixX I; const MAST::FieldFunction& Inertias = section.I(); @@ -1281,26 +667,21 @@ TEST_CASE("I1_element_property_card_constant_dynamic_1d", Real Iyy = I(1,1); Real Izz = I(0,0); Real Izy = I(0,1); - REQUIRE( Izz == Approx(second_area_moment_zz_true) ); - REQUIRE( Iyy == Approx(second_area_moment_yy_true) ); - REQUIRE( Izy == Approx(second_area_moment_zy_true) ); + REQUIRE( Izz == Approx(section.second_area_moment_zz_true) ); + REQUIRE( Iyy == Approx(section.second_area_moment_yy_true) ); + REQUIRE( Izy == Approx(section.second_area_moment_zy_true) ); - D_sec_iner_true(4,4) = Iyy; + D_sec_iner_true(4,4) = Iyy; // Should this be Izz? D_sec_iner_true(4,5) = Izy; D_sec_iner_true(5,4) = Izy; - D_sec_iner_true(5,5) = Izz; + D_sec_iner_true(5,5) = Izz; // Should this by Iyy? - D_sec_iner_true *= rho(); - - // Convert the test and truth Eigen::Matrix objects to std::vector - // since Catch2 has built in methods to compare vectors - std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_iner); - std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_iner_true); + D_sec_iner_true *= section.material.rho(); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. // Therefore, we use the Approx comparison instead of Equals - CHECK_THAT( test, Catch::Approx(truth) ); + CHECK_THAT( TEST::eigen_matrix_to_std_vector(D_sec_iner), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_iner_true)) ); } } @@ -1309,112 +690,20 @@ TEST_CASE("I1_element_property_card_constant_structural_1d", "[structural],[1D],[isotropic],[constant],[property]") { const uint dim = 1; - - // Define Material Properties as MAST Parameters - MAST::Parameter rho("rho_param", 1420.5); // Density - MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity - MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio - MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity - MAST::Parameter k("k_param", 237.0); // Thermal Conductivity - - const Real G = E() / (2. * (1. + nu())); + const uint n_target_elems = 3000; - // Define Section Properties as MAST Parameters - MAST::Parameter DIM1("DIM1", 3.770); - MAST::Parameter DIM2("DIM2", 0.170); - MAST::Parameter DIM3("DIM3", 5.470); - MAST::Parameter DIM4("DIM4", 5.900); - - MAST::Parameter offset_y("offy_param", -0.787); // Section offset in y-direction - MAST::Parameter offset_z("offz_param", 0.687); // Section offset in z-direction - - // Define Sensitivity Parameters - std::vector sens_params = {&DIM1}; - uint n_s = sens_params.size(); - - // Create field functions to dsitribute these constant parameters throughout the model - // Section Property Field Functions - MAST::ConstantFieldFunction DIM1_f("DIM1", DIM1); - MAST::ConstantFieldFunction DIM2_f("DIM2", DIM2); - MAST::ConstantFieldFunction DIM3_f("DIM3", DIM3); - MAST::ConstantFieldFunction DIM4_f("DIM4", DIM4); - MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); - MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); - // Material Property Field Functions - MAST::ConstantFieldFunction rho_f("rho", rho); - MAST::ConstantFieldFunction E_f("E", E); - MAST::ConstantFieldFunction nu_f("nu", nu); - MAST::ConstantFieldFunction cp_f("cp", cp); - MAST::ConstantFieldFunction k_f("k_th", k); - - // Initialize the material - MAST::IsotropicMaterialPropertyCard material; - - // Add the material property constant field functions to the material card - material.add(rho_f); - material.add(k_f); - material.add(cp_f); - material.add(E_f); - material.add(nu_f); - - // Initialize the section - MAST::Solid1DI1SectionElementPropertyCard section; - - // Add the section property constant field functions to the section card - section.add(DIM1_f); - section.add(DIM2_f); - section.add(DIM3_f); - section.add(DIM4_f); - - section.add(offsety_f); - section.add(offsetz_f); - - // Add the material card to the section card - section.set_material(material); - - // Specify a section orientation point and add it to the section. - RealVectorX orientation = RealVectorX::Zero(3); - orientation(1) = 1.0; - section.y_vector() = orientation; - - // Now initialize the section - section.init(*p_global_init); + TEST::AluminumI1Section section(n_target_elems); REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional - REQUIRE( section.depends_on(DIM1) ); - REQUIRE( section.depends_on(offset_y) ); - REQUIRE( section.depends_on(offset_z) ); - REQUIRE( section.depends_on(k) ); - REQUIRE( section.depends_on(cp) ); - REQUIRE( section.depends_on(rho) ); + REQUIRE( section.depends_on(section.DIM1) ); + REQUIRE( section.depends_on(section.offset_y) ); + REQUIRE( section.depends_on(section.offset_z) ); + REQUIRE( section.depends_on(section.material.k) ); + REQUIRE( section.depends_on(section.material.cp) ); + REQUIRE( section.depends_on(section.material.rho) ); REQUIRE( section.if_isotropic() ); - // True values - const Real area_true = 2.6241000000000039e+00; - const Real torsion_constant_true = 3.4912416307463445e-02; - const Real first_area_moment_z_true = -2.0651667000000016e+00; - const Real first_area_moment_y_true = 1.8027567000000015e+00; - const Real second_area_moment_zz_true = 1.7639240550400139e+01; - const Real second_area_moment_yy_true = 3.4324069553999919e+00; - const Real second_area_moment_zy_true = -1.4187695228999926e+00; - const Real second_area_moment_polar_true = 2.1071647505800129e+01; - const Real Izzc_true = 1.6013954357500140e+01; - const Real Iyyc_true = 2.1939131024999914e+00; - const Real Izyc_true = 7.5495165674510645e-15; - const Real Ipc_true = 1.8207867460000131e+01; - const Real warping_constant_true = 1.7690289289249652e+01; - const Real kappa_z_true = 5.4403106725573769e-01; - const Real kappa_y_true = 3.5065087923352467e-01; - const Real xs_true = 6.8699874537432160e-01; - const Real ys_true = -7.8699671905199586e-01; - const Real xst_true = 6.8699874537432160e-01; - const Real yst_true = -7.8699671905199586e-01; - const Real xc_true = 6.8699999999999961e-01; - const Real yc_true = -7.8699999999999948e-01; - const libMesh::Point centroid_true(xc_true, yc_true); - const libMesh::Point shear_center_true(xs_true, ys_true); - const libMesh::Point point(4.3, -3.5, -6.7); const Real time = 8.22; @@ -1454,12 +743,12 @@ TEST_CASE("I1_element_property_card_constant_structural_1d", Real area; const MAST::FieldFunction& Area = section.A(); Area(point, time, area); - REQUIRE( area == Approx(area_true) ); + REQUIRE( area == Approx(section.area_true) ); Real torsion_constant; const MAST::FieldFunction& TorsionConstant = section.J(); TorsionConstant(point, time, torsion_constant); - REQUIRE( torsion_constant == Approx(torsion_constant_true).epsilon(0.05) ); + REQUIRE( torsion_constant == Approx(section.torsion_constant_true).epsilon(0.05) ); std::unique_ptr> extension_stiffness_mat = section.stiffness_A_matrix(); @@ -1472,19 +761,13 @@ TEST_CASE("I1_element_property_card_constant_structural_1d", // Hard-coded value of the section's extension stiffness RealMatrixX D_sec_ext_true = RealMatrixX::Zero(2,2); - D_sec_ext_true(0,0) = E() * area_true; - D_sec_ext_true(1,1) = G * torsion_constant_true; - - - // Convert the test and truth Eigen::Matrix objects to std::vector - // since Catch2 has built in methods to compare vectors - std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_ext); - std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_ext_true); + D_sec_ext_true(0,0) = section.material.E() * section.area_true; + D_sec_ext_true(1,1) = section.material.G() * section.torsion_constant_true; // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. // Therefore, we use the Approx comparison instead of Equals - CHECK_THAT( test, Catch::Approx(truth).epsilon(0.05) ); + CHECK_THAT( TEST::eigen_matrix_to_std_vector(D_sec_ext), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_ext_true)).epsilon(0.05) ); } @@ -1507,9 +790,9 @@ TEST_CASE("I1_element_property_card_constant_structural_1d", Real Izz = I(0,0); Real Iyy = I(1,1); Real Izy = I(0,1); - REQUIRE( Izz == Approx(second_area_moment_zz_true) ); - REQUIRE( Iyy == Approx(second_area_moment_yy_true) ); - REQUIRE( Izy == Approx(second_area_moment_zy_true) ); + REQUIRE( Izz == Approx(section.second_area_moment_zz_true) ); + REQUIRE( Iyy == Approx(section.second_area_moment_yy_true) ); + REQUIRE( Izy == Approx(section.second_area_moment_zy_true) ); std::unique_ptr> bending_stiffness_mat = section.stiffness_D_matrix(); @@ -1520,20 +803,15 @@ TEST_CASE("I1_element_property_card_constant_structural_1d", // Hard-coded value of the section's extension stiffness RealMatrixX D_sec_bnd_true = RealMatrixX::Zero(2,2); - D_sec_bnd_true(0,0) = E() * second_area_moment_zz_true; - D_sec_bnd_true(1,1) = E() * second_area_moment_yy_true; - D_sec_bnd_true(0,1) = E() * second_area_moment_zy_true; - D_sec_bnd_true(1,0) = E() * second_area_moment_zy_true; - - // Convert the test and truth Eigen::Matrix objects to std::vector - // since Catch2 has built in methods to compare vectors - std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_bnd); - std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_bnd_true); + D_sec_bnd_true(0,0) = section.material.E() * section.second_area_moment_zz_true; + D_sec_bnd_true(1,1) = section.material.E() * section.second_area_moment_yy_true; + D_sec_bnd_true(0,1) = section.material.E() * section.second_area_moment_zy_true; + D_sec_bnd_true(1,0) = section.material.E() * section.second_area_moment_zy_true; // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. // Therefore, we use the Approx comparison instead of Equals - CHECK_THAT( test, Catch::Approx(truth) ); + CHECK_THAT( TEST::eigen_matrix_to_std_vector(D_sec_bnd), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_bnd_true)) ); } SECTION("1D extension-bending section stiffness matrix") @@ -1551,12 +829,12 @@ TEST_CASE("I1_element_property_card_constant_structural_1d", Real first_area_moment_y; const MAST::FieldFunction& Ay = section.Ay(); Ay(point, time, first_area_moment_y); - CHECK( first_area_moment_y == Approx(first_area_moment_y_true) ); + CHECK( first_area_moment_y == Approx(section.first_area_moment_y_true) ); Real first_area_moment_z; const MAST::FieldFunction& Az = section.Az(); Az(point, time, first_area_moment_z); - CHECK( first_area_moment_z == Approx(first_area_moment_z_true) ); + CHECK( first_area_moment_z == Approx(section.first_area_moment_z_true) ); std::unique_ptr> bndext_stiffness_mat = section.stiffness_B_matrix(); @@ -1567,19 +845,14 @@ TEST_CASE("I1_element_property_card_constant_structural_1d", // Hard-coded value of the section's extension stiffness RealMatrixX D_sec_bndext_true = RealMatrixX::Zero(2,2); - D_sec_bndext_true(0,0) = E() * first_area_moment_z_true; - D_sec_bndext_true(0,1) = E() * first_area_moment_y_true; + D_sec_bndext_true(0,0) = section.material.E() * section.first_area_moment_z_true; + D_sec_bndext_true(0,1) = section.material.E() * section.first_area_moment_y_true; // TODO: Add checks for torsion bending coupling when added to MAST. - // Convert the test and truth Eigen::Matrix objects to std::vector - // since Catch2 has built in methods to compare vectors - std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_bndext); - std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_bndext_true); - // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. // Therefore, we use the Approx comparison instead of Equals - CHECK_THAT( test, Catch::Approx(truth) ); + CHECK_THAT( TEST::eigen_matrix_to_std_vector(D_sec_bndext), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_bndext_true)) ); } SECTION("1D transverse shear section stiffness matrix") @@ -1597,7 +870,7 @@ TEST_CASE("I1_element_property_card_constant_structural_1d", Real area; const MAST::FieldFunction& Area = section.A(); Area(point, time, area); - REQUIRE( area == Approx(area_true) ); + REQUIRE( area == Approx(section.area_true) ); std::unique_ptr> trans_shear_stiffness_mat = section.transverse_shear_stiffness_matrix(); @@ -1608,18 +881,13 @@ TEST_CASE("I1_element_property_card_constant_structural_1d", // Hard-coded value of the section's extension stiffness RealMatrixX D_sec_shr_true = RealMatrixX::Zero(2,2); - D_sec_shr_true(0,0) = G*area_true*kappa_z_true; - D_sec_shr_true(1,1) = G*area_true*kappa_y_true; - - // Convert the test and truth Eigen::Matrix objects to std::vector - // since Catch2 has built in methods to compare vectors - std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_shr); - std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_shr_true); + D_sec_shr_true(0,0) = section.material.G()*section.area_true*section.kappa_z_true; + D_sec_shr_true(1,1) = section.material.G()*section.area_true*section.kappa_y_true; // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. // Therefore, we use the Approx comparison instead of Equals - CHECK_THAT( test, Catch::Approx(truth).epsilon(0.005) ); + CHECK_THAT( TEST::eigen_matrix_to_std_vector(D_sec_shr), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_shr_true)).epsilon(0.005) ); } @@ -1646,14 +914,10 @@ TEST_CASE("I1_element_property_card_constant_structural_1d", // // NOTE: Should be all zero's for non-bushing sections // RealMatrixX D_sec_spring_true = RealMatrixX::Zero(4,6); // -// // Convert the test and truth Eigen::Matrix objects to std::vector -// // since Catch2 has built in methods to compare vectors -// std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_spring); -// std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_spring_true); // // // Floating point approximations are diffcult to compare since the // // values typically aren't exactly equal due to numerical error. // // Therefore, we use the Approx comparison instead of Equals -// CHECK_THAT( test, Catch::Approx(truth) ); +// CHECK_THAT( TEST::eigen_matrix_to_std_vector(D_sec_spring), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_spring_true)) ); // } } diff --git a/tests/property/mast_solid_1d_I1_section_element_property_card.h b/tests/property/mast_solid_1d_I1_section_element_property_card.h new file mode 100644 index 00000000..f6d3abab --- /dev/null +++ b/tests/property/mast_solid_1d_I1_section_element_property_card.h @@ -0,0 +1,95 @@ +#ifndef MAST_SOLID_1D_I1_SECTION_ELEMENT_PROPERTY_CARD_H_INCLUDED +#define MAST_SOLID_1D_I1_SECTION_ELEMENT_PROPERTY_CARD_H_INCLUDED + + +#include "property_cards/solid_1d_I1_section_element_property_card.h" +#include "material/mast_isotropic_material.h" + +extern libMesh::LibMeshInit* p_global_init; + +namespace TEST +{ + class AluminumI1Section : public MAST::Solid1DI1SectionElementPropertyCard + { + public: + AluminumI1Section(const uint n_target_elems=3500): + DIM1("DIM1", 3.770), DIM2("DIM2", 0.170), DIM3("DIM3", 5.470), + DIM4("DIM4", 5.900), offset_y("offy_param", -0.787), + offset_z("offz_param", 0.687), DIM1_f("DIM1", DIM1), + DIM2_f("DIM2", DIM2), DIM3_f("DIM3", DIM3), DIM4_f("DIM4", DIM4), + offsety_f("hy_off", offset_y), offsetz_f("hz_off", offset_z), + centroid_true(xc_true, yc_true), shear_center_true(xs_true, ys_true) + { + add(DIM1_f); + add(DIM2_f); + add(DIM3_f); + add(DIM4_f); + + add(offsety_f); + add(offsetz_f); + + // Add the material card to the section card + set_material(material); + + // Specify a section orientation point and add it to the + RealVectorX orientation = RealVectorX::Zero(3); + orientation(1) = 1.0; + y_vector() = orientation; + + // Now initialize the section + init(*p_global_init, n_target_elems); + } + + TEST::Aluminum7075T6 material; + + MAST::Parameter DIM1; + MAST::Parameter DIM2; + MAST::Parameter DIM3; + MAST::Parameter DIM4; + + MAST::Parameter offset_y; + MAST::Parameter offset_z; + + MAST::ConstantFieldFunction DIM1_f; + MAST::ConstantFieldFunction DIM2_f; + MAST::ConstantFieldFunction DIM3_f; + MAST::ConstantFieldFunction DIM4_f; + + MAST::ConstantFieldFunction offsety_f; + MAST::ConstantFieldFunction offsetz_f; + + // True values + const Real area_true = 2.6241000000000039e+00; + const Real torsion_constant_true = 3.4912416307463445e-02; + const Real first_area_moment_z_true = -2.0651667000000016e+00; + const Real first_area_moment_y_true = 1.8027567000000015e+00; + const Real second_area_moment_zz_true = 1.7639240550400139e+01; + const Real second_area_moment_yy_true = 3.4324069553999919e+00; + const Real second_area_moment_zy_true = -1.4187695228999926e+00; + const Real second_area_moment_polar_true = 2.1071647505800129e+01; + const Real Izzc_true = 1.6013954357500140e+01; + const Real Iyyc_true = 2.1939131024999914e+00; + const Real Izyc_true = 7.5495165674510645e-15; + const Real Ipc_true = 1.8207867460000131e+01; + const Real warping_constant_true = 1.7690289289249652e+01; + const Real kappa_z_true = 5.4403106725573769e-01; + const Real kappa_y_true = 3.5065087923352467e-01; + const Real xs_true = 6.8699874537432160e-01; + const Real ys_true = -7.8699671905199586e-01; + const Real xst_true = 6.8699874537432160e-01; + const Real yst_true = -7.8699671905199586e-01; + const Real xc_true = 6.8699999999999961e-01; + const Real yc_true = -7.8699999999999948e-01; + const std::vector stress_points_true = { + libMesh::Point(1.9700000000000000e+00, 2.9500000000000002e+00, 0.), + libMesh::Point(1.9700000000000000e+00, -2.9500000000000002e+00, 0.), + libMesh::Point(-1.9700000000000000e+00, -2.9500000000000002e+00, 0.), + libMesh::Point(-1.9700000000000000e+00, 2.9500000000000002e+00, 0.) + }; + + libMesh::Point centroid_true; + libMesh::Point shear_center_true; + + }; +} +#endif // MAST_SOLID_1D_I1_SECTION_ELEMENT_PROPERTY_CARD_H_INCLUDED diff --git a/tests/property/mast_solid_1d_L_section_element_property_card.cpp b/tests/property/mast_solid_1d_L_section_element_property_card.cpp index 11dc2057..88f6066f 100644 --- a/tests/property/mast_solid_1d_L_section_element_property_card.cpp +++ b/tests/property/mast_solid_1d_L_section_element_property_card.cpp @@ -632,7 +632,7 @@ TEST_CASE("L_element_property_card_constant_thermoelastic_1d", } } -// FIXME: I don't think this one is being run. + TEST_CASE("L_element_property_card_constant_dynamic_1d", "[dynamic],[1D],[isotropic],[constant],[property]") { diff --git a/tests/property/mast_solid_1d_bar_section_element_property_card.cpp b/tests/property/mast_solid_1d_bar_section_element_property_card.cpp index 22f660e9..2b876a57 100644 --- a/tests/property/mast_solid_1d_bar_section_element_property_card.cpp +++ b/tests/property/mast_solid_1d_bar_section_element_property_card.cpp @@ -12,6 +12,7 @@ // Custom includes #include "test_helpers.h" +#include "mast_solid_1d_bar_section_element_property_card.h" extern libMesh::LibMeshInit* p_global_init; @@ -24,170 +25,108 @@ TEST_CASE("bar_element_property_card_constant_base_1d", "[1D],[isotropic],[constant],[property]") { const uint dim = 1; + const uint n_target_elems = 3000; - // Define Material Properties as MAST Parameters - MAST::Parameter rho("rho_param", 1420.5); // Density - MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity - MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio - MAST::Parameter kappa("kappa_param", 5.0/6.0); // Shear coefficient - MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity - MAST::Parameter k("k_param", 237.0); // Thermal Conductivity - - // Define Section Properties as MAST Parameters - MAST::Parameter thickness_y("DIM1", 3.0); // Section thickness in z-direction - MAST::Parameter thickness_z("DIM2", 0.75); // Section thickness in y-direction - MAST::Parameter offset_y("offy_param", 0.287); // Section offset in y-direction - MAST::Parameter offset_z("offz_param", 1.654); // Section offset in z-direction - - // Create field functions to dsitribute these constant parameters throughout the model - // Section Property Field Functions - MAST::ConstantFieldFunction DIM1_f("DIM1", thickness_y); - MAST::ConstantFieldFunction DIM2_f("DIM2", thickness_z); - MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); - MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); - // Material Property Field Functions - MAST::ConstantFieldFunction rho_f("rho", rho); - MAST::ConstantFieldFunction E_f("E", E); - MAST::ConstantFieldFunction nu_f("nu", nu); - MAST::ConstantFieldFunction kappa_f("kappa", kappa); - MAST::ConstantFieldFunction cp_f("cp", cp); - MAST::ConstantFieldFunction k_f("k_th", k); - - // Initialize the material - MAST::IsotropicMaterialPropertyCard material; - - // Add the material property constant field functions to the material card - material.add(rho_f); - material.add(k_f); - material.add(cp_f); - material.add(E_f); - material.add(nu_f); - material.add(kappa_f); - - // Initialize the section - MAST::Solid1DBarSectionElementPropertyCard section; - - // Add the section property constant field functions to the section card - section.add(DIM1_f); - section.add(DIM2_f); - section.add(offsety_f); - section.add(offsetz_f); - - // Add the material card to the section card - section.set_material(material); - - // Specify a section orientation point and add it to the section. - RealVectorX orientation = RealVectorX::Zero(3); - orientation(1) = 1.0; - section.y_vector() = orientation; - - // Now initialize the section - section.init(*p_global_init); + TEST::AluminumBarSection section(n_target_elems); REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional - REQUIRE( section.depends_on(thickness_y) ); - REQUIRE( section.depends_on(offset_y) ); - REQUIRE( section.depends_on(thickness_z) ); - REQUIRE( section.depends_on(offset_z) ); - REQUIRE( section.depends_on(k) ); - REQUIRE( section.depends_on(cp) ); - REQUIRE( section.depends_on(rho) ); + REQUIRE( section.depends_on(section.DIM1) ); + REQUIRE( section.depends_on(section.DIM2) ); + + REQUIRE( section.depends_on(section.offset_y) ); + REQUIRE( section.depends_on(section.offset_z) ); + + REQUIRE( section.depends_on(section.material.k) ); + REQUIRE( section.depends_on(section.material.cp) ); + REQUIRE( section.depends_on(section.material.rho) ); + REQUIRE( section.depends_on(section.material.E) ); + REQUIRE( section.depends_on(section.material.nu) ); + REQUIRE( section.depends_on(section.material.alpha) ); + REQUIRE( section.if_isotropic() ); - // True values calculated using the sectionproperties module in python BAR.py - const Real area_true = 2.2500000000000004e+00; - const Real torsion_constant_true = 3.5540414988249380e-01; - const Real first_area_moment_z_true = 6.4574999999999994e-01; - const Real first_area_moment_y_true = 3.7214999999999945e+00; - const Real second_area_moment_zz_true = 2.9079899999999986e-01; - const Real second_area_moment_yy_true = 7.8428609999999814e+00; - const Real second_area_moment_zy_true = 1.0680705000000006e+00; - const Real second_area_moment_polar_true = 8.1336599999999812e+00; - const Real Izzc_true = 1.0546874999999994e-01; - const Real Iyyc_true = 1.6875000000000009e+00; - const Real Izyc_true = 2.4424906541753444e-15; - const Real warping_constant_true = 6.1030611538894504e-02; - const Real kappa_z_true = 8.3330248143102326e-01; - const Real kappa_y_true = 5.5763491072129889e-01; - const Real xs_true = 1.6540000458463804e+00; - const Real ys_true = 2.8700000023051281e-01; - const Real xst_true = 1.6540000458463804e+00; - const Real yst_true = 2.8700000023051281e-01; - const libMesh::Point shear_center_true(xs_true, ys_true, 0.); - const libMesh::Point centroid_true(1.654, 0.287, 0.); - - // NOTE: The default 1D section is rectangular const libMesh::Point point(4.3, -3.5, -6.7); const Real time = 8.22; - Real area; - const MAST::FieldFunction& Area = section.A(); - Area(point, time, area); - REQUIRE( area == Approx(area_true) ); - - Real first_area_moment_y; - const MAST::FieldFunction& Ay = section.Ay(); - Ay(point, time, first_area_moment_y); - CHECK( first_area_moment_y == Approx(first_area_moment_y_true) ); - - Real first_area_moment_z; - const MAST::FieldFunction& Az = section.Az(); - Az(point, time, first_area_moment_z); - CHECK( first_area_moment_z == Approx(first_area_moment_z_true) ); - - RealMatrixX I; - const MAST::FieldFunction& Inertias = section.I(); - Inertias(point, time, I); - REQUIRE( I(0,1) == I(1,0) ); - Real Iyy = I(1,1); - Real Izz = I(0,0); - Real Izy = I(0,1); - REQUIRE( Izz == Approx(second_area_moment_zz_true) ); - REQUIRE( Iyy == Approx(second_area_moment_yy_true) ); - REQUIRE( Izy == Approx(second_area_moment_zy_true) ); - - Real Ip; - const MAST::FieldFunction& PolarInertia = section.Ip(); - PolarInertia(point, time, Ip); - REQUIRE( Ip == Approx(second_area_moment_polar_true) ); - - const libMesh::Point p(0.5, 2.1, 1.6); - const Real t = 4.657; - RealVectorX Ic = section.cross_section->get_second_area_moments_about_centroid(p, t); - libMesh::out << "Izz = " << Ic(0) << std::endl; - libMesh::out << "Iyy = " << Ic(1) << std::endl; - REQUIRE( Ic(0) == Approx(Izzc_true) ); - REQUIRE( Ic(1) == Approx(Iyyc_true) ); - REQUIRE( Ic(2) == Approx(Izyc_true).margin(1e-09) ); - - Real torsion_constant; - const MAST::FieldFunction& TorsionConstant = section.J(); - TorsionConstant(point, time, torsion_constant); - REQUIRE( torsion_constant == Approx(torsion_constant_true)); - - Real warping_constant; - const MAST::FieldFunction& WarpingConstant = section.Gam(); - WarpingConstant(point, time, warping_constant); - REQUIRE( warping_constant == Approx(warping_constant_true) ); - - RealMatrixX shear_coefficients; - const MAST::FieldFunction& ShearCoefficientMatrix = section.Kap(); - ShearCoefficientMatrix(point, time, shear_coefficients); - REQUIRE( shear_coefficients(0,0) == Approx(kappa_z_true) ); - REQUIRE( shear_coefficients(1,1) == Approx(kappa_y_true) ); - - libMesh::Point centroid = section.cross_section->get_centroid(p, t); - REQUIRE( centroid(0) == Approx(centroid_true(0)) ); - REQUIRE( centroid(1) == Approx(centroid_true(1)) ); - - libMesh::Point shear_center = section.cross_section->get_shear_center(p, t); - REQUIRE(shear_center(0) == Approx(xs_true)); - REQUIRE(shear_center(1) == Approx(ys_true)); - - REQUIRE_FALSE( section.if_diagonal_mass_matrix() ); - - section.set_diagonal_mass_matrix(true); - REQUIRE( section.if_diagonal_mass_matrix() ); + SECTION("section_properties") + { + Real area; + const MAST::FieldFunction& Area = section.A(); + Area(point, time, area); + CHECK( area == Approx(section.area_true) ); + + Real first_area_moment_y; + const MAST::FieldFunction& Ay = section.Ay(); + Ay(point, time, first_area_moment_y); + CHECK( first_area_moment_y == Approx(section.first_area_moment_y_true) ); + + Real first_area_moment_z; + const MAST::FieldFunction& Az = section.Az(); + Az(point, time, first_area_moment_z); + CHECK( first_area_moment_z == Approx(section.first_area_moment_z_true) ); + + RealMatrixX I; + const MAST::FieldFunction& Inertias = section.I(); + Inertias(point, time, I); + CHECK( I(0,1) == I(1,0) ); + Real Iyy = I(1,1); + Real Izz = I(0,0); + Real Izy = I(0,1); + CHECK( Izz == Approx(section.second_area_moment_zz_true) ); + CHECK( Iyy == Approx(section.second_area_moment_yy_true) ); + CHECK( Izy == Approx(section.second_area_moment_zy_true) ); + + Real Ip; + const MAST::FieldFunction& PolarInertia = section.Ip(); + PolarInertia(point, time, Ip); + CHECK( Ip == Approx(section.second_area_moment_polar_true) ); + + Real torsion_constant; + const MAST::FieldFunction& TorsionConstant = section.J(); + TorsionConstant(point, time, torsion_constant); + CHECK( torsion_constant == Approx(section.torsion_constant_true).epsilon(0.005)); + + libMesh::Point centroid = section.get_centroid(point, time); + CHECK( centroid(0) == Approx(section.centroid_true(0)) ); + CHECK( centroid(1) == Approx(section.centroid_true(1)) ); + + libMesh::Point shear_center = section.get_shear_center(point, time); + CHECK(shear_center(0) == Approx(section.xs_true).epsilon(0.005)); + CHECK(shear_center(1) == Approx(section.ys_true).epsilon(0.005)); + + RealMatrixX shear_coefficients; + const MAST::FieldFunction& ShearCoefficientMatrix = section.Kap(); + ShearCoefficientMatrix(point, time, shear_coefficients); + CHECK( shear_coefficients(0,0) == Approx(section.kappa_z_true).epsilon(0.005) ); + CHECK( shear_coefficients(1,1) == Approx(section.kappa_y_true).epsilon(0.005) ); + + Real warping_constant; + const MAST::FieldFunction& WarpingConstant = section.Gam(); + WarpingConstant(point, time, warping_constant); + CHECK( warping_constant == Approx(section.warping_constant_true).epsilon(0.005) ); + } + + SECTION("stress_points") + { + libMesh::Point centroid = section.get_centroid(point, time); + CHECK( centroid(0) == Approx(section.centroid_true(0)) ); + CHECK( centroid(1) == Approx(section.centroid_true(1)) ); + std::vector stress_points = section.get_stress_points(point, time, centroid); + + for (uint i=0; i sens_params = {&DIM1, &DIM2}; + std::vector sens_params = {§ion.DIM1}; uint n_s = sens_params.size(); - // Create field functions to dsitribute these constant parameters throughout the model - // Section Property Field Functions - MAST::ConstantFieldFunction DIM1_f("DIM1", DIM1); - MAST::ConstantFieldFunction DIM2_f("DIM2", DIM2); - MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); - MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); - // Material Property Field Functions - MAST::ConstantFieldFunction rho_f("rho", rho); - MAST::ConstantFieldFunction E_f("E", E); - MAST::ConstantFieldFunction nu_f("nu", nu); - MAST::ConstantFieldFunction kappa_f("kappa", kappa); - MAST::ConstantFieldFunction cp_f("cp", cp); - MAST::ConstantFieldFunction k_f("k_th", k); - - // Initialize the material - MAST::IsotropicMaterialPropertyCard material; - - // Add the material property constant field functions to the material card - material.add(rho_f); - material.add(k_f); - material.add(cp_f); - material.add(E_f); - material.add(nu_f); - material.add(kappa_f); - - // Initialize the section - MAST::Solid1DBarSectionElementPropertyCard section; - - // Add the section property constant field functions to the section card - section.add(DIM1_f); - section.add(DIM2_f); - section.add(offsety_f); - section.add(offsetz_f); - - // Add the material card to the section card - section.set_material(material); - - // Specify a section orientation point and add it to the section. - RealVectorX orientation = RealVectorX::Zero(3); - orientation(1) = 1.0; - section.y_vector() = orientation; - - // Now initialize the section - section.init(*p_global_init); - - REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional - REQUIRE( section.depends_on(DIM1) ); - REQUIRE( section.depends_on(offset_y) ); - REQUIRE( section.depends_on(DIM2) ); - REQUIRE( section.depends_on(offset_z) ); - REQUIRE( section.depends_on(k) ); - REQUIRE( section.depends_on(cp) ); - REQUIRE( section.depends_on(rho) ); REQUIRE( section.if_isotropic() ); - // True values calculated using the sectionproperties module in python BAR.py - const Real area_true = 2.2500000000000004e+00; - const Real torsion_constant_true = 3.5540414988249380e-01; - const Real first_area_moment_z_true = 6.4574999999999994e-01; - const Real first_area_moment_y_true = 3.7214999999999945e+00; - const Real second_area_moment_zz_true = 2.9079899999999986e-01; - const Real second_area_moment_yy_true = 7.8428609999999814e+00; - const Real second_area_moment_zy_true = 1.0680705000000006e+00; - const Real second_area_moment_polar_true = 8.1336599999999812e+00; - const Real Izzc_true = 1.0546874999999994e-01; - const Real Iyyc_true = 1.6875000000000009e+00; - const Real Izyc_true = 2.4424906541753444e-15; - const Real warping_constant_true = 6.1030611538894504e-02; - const Real kappa_z_true = 8.3330248143102326e-01; - const Real kappa_y_true = 5.5763491072129889e-01; - const Real xs_true = 1.6540000458463804e+00; - const Real ys_true = 2.8700000023051281e-01; - const Real xst_true = 1.6540000458463804e+00; - const Real yst_true = 2.8700000023051281e-01; - const libMesh::Point shear_center_true(xs_true, ys_true, 0.); - - const libMesh::Point centroid_true(1.654, 0.287); - Real stress_C_x, stress_C_y, stress_D_x, stress_D_y; - Real stress_E_x, stress_E_y, stress_F_x, stress_F_y; - const libMesh::Point point(4.3, -3.5, -6.7); const Real time = 8.22; @@ -326,7 +175,6 @@ TEST_CASE("bar_element_property_card_constant_base_sensitivity_1d", const Real delta = 1.220703125e-04; // (np.spacing(1))**(0.25) // Area Sensitivity Check - libMesh::out << "\tArea Sensitivity Check..." << std::endl; const MAST::FieldFunction& Area = section.A(); std::vector dA(n_s); for (uint i=0; iname() << " = " << dA[i] << "\tdA_cd = " << dA_cd[i] << std::endl; + //libMesh::out << "dA_d" << sens_params[i]->name() << " = " << dA[i] << "\tdA_cd = " << dA_cd[i] << std::endl; REQUIRE(dA[i] == Approx(dA_cd[i])); } // Centroid Sensitivity Check - libMesh::out << "\tCentroid Sensitivity Check..." << std::endl; std::vector dC(n_s); for (uint i=0; iget_centroid_derivative(*sens_params[i], point, time); + dC[i] = section.get_centroid_derivative(*sens_params[i], point, time); } libMesh::Point fp_h, fp_2h, fp_n, fp_2n; @@ -357,16 +204,16 @@ TEST_CASE("bar_element_property_card_constant_base_sensitivity_1d", for (uint i=0; iget_centroid(point, time); + fp_h = section.get_centroid(point, time); (*sens_params[i])() += delta; - fp_2h = section.cross_section->get_centroid(point, time); + fp_2h = section.get_centroid(point, time); (*sens_params[i])() -= 3.0*delta; - fp_n = section.cross_section->get_centroid(point, time); + fp_n = section.get_centroid(point, time); (*sens_params[i])() -= delta; - fp_2n = section.cross_section->get_centroid(point, time); + fp_2n = section.get_centroid(point, time); (*sens_params[i])() += 2.0*delta; @@ -378,7 +225,6 @@ TEST_CASE("bar_element_property_card_constant_base_sensitivity_1d", } // First Area Moments Sensitivity Check - libMesh::out << "\tFirst Area Moment Y Sensitivity Check..." << std::endl; const MAST::FieldFunction& Area_y = section.Ay(); std::vector dAy(n_s); for (uint i=0; i& Area_z = section.Az(); std::vector dAz(n_s); for (uint i=0; i& Inertia = section.I(); std::vector dI(n_s); for (uint i=0; i& PolarInertia = section.Ip(); std::vector dIp(n_s); for (uint i=0; i dIp_cd(n_s); for (uint i=0; iname() << " = " << dIp[i] << "\tdIp_cd = " << dIp_cd[i] << std::endl; REQUIRE(dIp[i] == Approx(dIp_cd[i])); @@ -481,27 +311,26 @@ TEST_CASE("bar_element_property_card_constant_base_sensitivity_1d", // // Shear Center Sensitivity Check -// libMesh::out << "\tShear Center Sensitivity Check..." << std::endl; // std::vector dCs(n_s); // for (uint i=0; iget_shear_center_derivative(*sens_params[i], point, time); +// dCs[i] = section.get_shear_center_derivative(*sens_params[i], point, time); // } // // std::vector dCs_cd(n_s); // for (uint i=0; iget_shear_center(point, time); +// fp_h = section.get_shear_center(point, time); // // (*sens_params[i])() += delta; -// fp_2h = section.cross_section->get_shear_center(point, time); +// fp_2h = section.get_shear_center(point, time); // // (*sens_params[i])() -= 3.0*delta; -// fp_n = section.cross_section->get_shear_center(point, time); +// fp_n = section.get_shear_center(point, time); // // (*sens_params[i])() -= delta; -// fp_2n = section.cross_section->get_shear_center(point, time); +// fp_2n = section.get_shear_center(point, time); // // (*sens_params[i])() += 2.0*delta; // @@ -515,7 +344,6 @@ TEST_CASE("bar_element_property_card_constant_base_sensitivity_1d", // Torsion Constant Sensitivity Check // NOTE: The field function below is not made constant because currently a finite difference is used to calculate sensitivity. - libMesh::out << "\tTorsion Constant Sensitivity Check..." << std::endl; MAST::FieldFunction& TorsionConstant = section.J(); std::vector dJ(n_s); for (uint i=0; i dJ_cd(n_s); for (uint i=0; iname() << " = " << dJ[i] << "\tdJ_cd = " << dJ_cd[i] << std::endl; REQUIRE(dJ[i] == Approx(dJ_cd[i]).epsilon(0.1) ); @@ -550,7 +364,6 @@ TEST_CASE("bar_element_property_card_constant_base_sensitivity_1d", // Shear Coefficient Sensitivity Check // NOTE: The field function below is not made constant because currently a finite difference is used to calculate sensitivity. - libMesh::out << "\tShear Coefficients Sensitivity Check..." << std::endl; MAST::FieldFunction& Kappa = section.Kap(); std::vector dK(n_s); for (uint i=0; i dK_cd(n_s); for (uint i=0; iname() << " =\n" << dK[i] << "\ndK_cd = \n" << dK_cd[i] << std::endl; @@ -600,7 +399,6 @@ TEST_CASE("bar_element_property_card_constant_base_sensitivity_1d", // Warping Constant Sensitivity Check // NOTE: The field function below is not made constant because currently a finite difference is used to calculate sensitivity. - libMesh::out << "\tWarping Constant Sensitivity Check..." << std::endl; MAST::FieldFunction& WarpingConstant = section.Gam(); std::vector dW(n_s); for (uint i=0; i dW_cd(n_s); for (uint i=0; iname() << " = " << dW[i] << "\tdW_cd = " << dW_cd[i] << std::endl; REQUIRE(dW[i] == Approx(dW_cd[i]).epsilon(0.1) ); @@ -634,82 +418,32 @@ TEST_CASE("bar_element_property_card_constant_base_sensitivity_1d", } + TEST_CASE("bar_element_property_card_constant_heat_transfer_1d", "[heat_transfer],[1D],[isotropic],[constant],[property]") { const uint dim = 1; + const uint n_target_elems = 3000; - // Define Material Properties as MAST Parameters - MAST::Parameter rho("rho_param", 1420.5); // Density - MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity - MAST::Parameter k("k_param", 237.0); // Thermal Conductivity - - // Define Section Properties as MAST Parameters - MAST::Parameter thickness_y("DIM1", 0.04); // Section thickness in z-direction - MAST::Parameter thickness_z("DIM2", 0.06); // Section thickness in y-direction - MAST::Parameter offset_y("offy_param", 0.035); // Section offset in y-direction - MAST::Parameter offset_z("offz_param", 0.026); // Section offset in z-direction - - // Create field functions to dsitribute these constant parameters throughout the model - // Section Property Field Functions - MAST::ConstantFieldFunction DIM1_f("DIM1", thickness_y); - MAST::ConstantFieldFunction DIM2_f("DIM2", thickness_z); - MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); - MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); - // Material Property Field Functions - MAST::ConstantFieldFunction rho_f("rho", rho); - MAST::ConstantFieldFunction cp_f("cp", cp); - MAST::ConstantFieldFunction k_f("k_th", k); - - // Initialize the material - MAST::IsotropicMaterialPropertyCard material; - - // Add the material property constant field functions to the material card - material.add(rho_f); - material.add(k_f); - material.add(cp_f); - - // Initialize the section - MAST::Solid1DBarSectionElementPropertyCard section; - - // Add the section property constant field functions to the section card - section.add(DIM1_f); - section.add(DIM2_f); - section.add(offsety_f); - section.add(offsetz_f); - - // Add the material card to the section card - section.set_material(material); - -// // Specify a section orientation point and add it to the section. -// RealVectorX orientation = RealVectorX::Zero(3); -// orientation(1) = 1.0; -// section.y_vector() = orientation; - - // Now initialize the section - section.init(*p_global_init); + TEST::AluminumBarSection section(n_target_elems); REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional - REQUIRE( section.depends_on(thickness_y) ); - REQUIRE( section.depends_on(offset_y) ); - REQUIRE( section.depends_on(thickness_z) ); - REQUIRE( section.depends_on(offset_z) ); - REQUIRE( section.depends_on(k) ); - REQUIRE( section.depends_on(cp) ); - REQUIRE( section.depends_on(rho) ); - REQUIRE( section.if_isotropic() ); + REQUIRE( section.depends_on(section.DIM1) ); + REQUIRE( section.depends_on(section.offset_y) ); + REQUIRE( section.depends_on(section.offset_z) ); + REQUIRE( section.depends_on(section.material.k) ); + REQUIRE( section.depends_on(section.material.cp) ); + REQUIRE( section.depends_on(section.material.rho) ); - // True values calculated using the sectionproperties module in python BAR.py - Real area_true = 2.3999999999999963e-03; + REQUIRE( section.if_isotropic() ); - // NOTE: The default 1D section is rectangular const libMesh::Point point(4.3, -3.5, -6.7); const Real time = 8.22; Real area; const MAST::FieldFunction& Area = section.A(); Area(point, time, area); - REQUIRE( area == Approx(area_true) ); + REQUIRE( area == Approx(section.area_true) ); SECTION("1D section thermal conductance matrix") @@ -733,17 +467,12 @@ TEST_CASE("bar_element_property_card_constant_heat_transfer_1d", // Hard-coded value of the section's extension stiffness RealMatrixX D_sec_conduc_true = RealMatrixX::Zero(1,1); - D_sec_conduc_true(0,0) = 237.0*0.06*0.04; - - // Convert the test and truth Eigen::Matrix objects to std::vector - // since Catch2 has built in methods to compare vectors - std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_conduc); - std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_conduc_true); + D_sec_conduc_true(0,0) = section.material.k() * section.area_true; // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. // Therefore, we use the Approx comparison instead of Equals - CHECK_THAT( test, Catch::Approx(truth) ); + CHECK_THAT( TEST::eigen_matrix_to_std_vector(D_sec_conduc), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_conduc_true)) ); } SECTION("1D section thermal capacitance matrix") @@ -767,17 +496,12 @@ TEST_CASE("bar_element_property_card_constant_heat_transfer_1d", // Hard-coded value of the section's extension stiffness RealMatrixX D_sec_capac_true = RealMatrixX::Zero(1,1); - D_sec_capac_true(0,0) = 908.0*1420.5*0.06*0.04; - - // Convert the test and truth Eigen::Matrix objects to std::vector - // since Catch2 has built in methods to compare vectors - std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_capac); - std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_capac_true); + D_sec_capac_true(0,0) = section.material.rho() * section.material.cp() * section.area_true; // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. // Therefore, we use the Approx comparison instead of Equals - CHECK_THAT( test, Catch::Approx(truth) ); + CHECK_THAT( TEST::eigen_matrix_to_std_vector(D_sec_capac), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_capac_true)) ); } } @@ -786,76 +510,23 @@ TEST_CASE("bar_element_property_card_constant_thermoelastic_1d", "[thermoelastic],[1D],[isotropic],[constant],[property]") { const uint dim = 1; + const uint n_target_elems = 3000; - // Define Material Properties as MAST Parameters - MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity - MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio - MAST::Parameter alpha("alpha_param", 5.43e-05); // Coefficient of thermal expansion - - // Define Section Properties as MAST Parameters - MAST::Parameter thickness_y("DIM1", 0.04); // Section thickness in z-direction - MAST::Parameter thickness_z("DIM2", 0.06); // Section thickness in y-direction - MAST::Parameter offset_y("offy_param", 0.035); // Section offset in y-direction - MAST::Parameter offset_z("offz_param", 0.026); // Section offset in z-direction - - // Create field functions to dsitribute these constant parameters throughout the model - // Section Property Field Functions - MAST::ConstantFieldFunction DIM1_f("DIM1", thickness_y); - MAST::ConstantFieldFunction DIM2_f("DIM2", thickness_z); - MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); - MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); - // Material Property Field Functions - MAST::ConstantFieldFunction E_f("E", E); - MAST::ConstantFieldFunction nu_f("nu", nu); - MAST::ConstantFieldFunction alpha_f("alpha_expansion", alpha); - - // Initialize the material - MAST::IsotropicMaterialPropertyCard material; - - // Add the material property constant field functions to the material card - material.add(E_f); - material.add(nu_f); - material.add(alpha_f); - - // Initialize the section - MAST::Solid1DBarSectionElementPropertyCard section; - - // Add the section property constant field functions to the section card - section.add(DIM1_f); - section.add(DIM2_f); - section.add(offsety_f); - section.add(offsetz_f); - - // Add the material card to the section card - section.set_material(material); - - // Specify a section orientation point and add it to the section. - RealVectorX orientation = RealVectorX::Zero(3); - orientation(1) = 1.0; - section.y_vector() = orientation; - - // Now initialize the section - section.init(*p_global_init); + TEST::AluminumBarSection section(n_target_elems); REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional - REQUIRE( section.depends_on(thickness_y) ); - REQUIRE( section.depends_on(offset_y) ); - REQUIRE( section.depends_on(thickness_z) ); - REQUIRE( section.depends_on(offset_z) ); - REQUIRE( section.depends_on(E) ); - REQUIRE( section.depends_on(nu) ); - REQUIRE( section.depends_on(alpha) ); + REQUIRE( section.depends_on(section.DIM1) ); + REQUIRE( section.depends_on(section.offset_y) ); + REQUIRE( section.depends_on(section.offset_z) ); + REQUIRE( section.depends_on(section.material.k) ); + REQUIRE( section.depends_on(section.material.cp) ); + REQUIRE( section.depends_on(section.material.rho) ); + REQUIRE( section.if_isotropic() ); - // True values calculated using the sectionproperties module in python BAR.py - // NOTE: The default 1D section is rectangular const libMesh::Point point(4.3, -3.5, -6.7); const Real time = 8.22; - Real area_true = 2.3999999999999963e-03; - Real first_area_moment_y_true = 6.2399999999999741e-05; - Real first_area_moment_z_true = 8.3999999999999887e-05; - SECTION("1D thermal expansion A matrix") { /** @@ -872,7 +543,7 @@ TEST_CASE("bar_element_property_card_constant_thermoelastic_1d", Real area; const MAST::FieldFunction& Area = section.A(); Area(point, time, area); - CHECK( area == Approx(area_true) ); + CHECK( area == Approx(section.area_true) ); std::unique_ptr> texp_A_mat = section.thermal_expansion_A_matrix(); @@ -883,18 +554,12 @@ TEST_CASE("bar_element_property_card_constant_thermoelastic_1d", // Hard-coded value of the section's extension stiffness RealMatrixX D_sec_texpA_true = RealMatrixX::Zero(2,1); - D_sec_texpA_true(0,0) = 9383.04; - - // Convert the test and truth Eigen::Matrix objects to std::vector - // since Catch2 has built in methods to compare vectors - std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_texpA); - std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_texpA_true); - + D_sec_texpA_true(0,0) = section.material.E() * section.material.alpha() * section.area_true; // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. // Therefore, we use the Approx comparison instead of Equals - CHECK_THAT( test, Catch::Approx(truth) ); + CHECK_THAT( TEST::eigen_matrix_to_std_vector(D_sec_texpA), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_texpA_true)) ); } SECTION("1D thermal expansion B matrix") @@ -913,12 +578,12 @@ TEST_CASE("bar_element_property_card_constant_thermoelastic_1d", Real first_area_moment_y; const MAST::FieldFunction& Ay = section.Ay(); Ay(point, time, first_area_moment_y); - CHECK( first_area_moment_y == Approx(first_area_moment_y_true) ); + CHECK( first_area_moment_y == Approx(section.first_area_moment_y_true) ); Real first_area_moment_z; const MAST::FieldFunction& Az = section.Az(); Az(point, time, first_area_moment_z); - CHECK( first_area_moment_z == Approx(first_area_moment_z_true) ); + CHECK( first_area_moment_z == Approx(section.first_area_moment_z_true) ); std::unique_ptr> texp_B_mat = section.thermal_expansion_B_matrix(); @@ -931,19 +596,13 @@ TEST_CASE("bar_element_property_card_constant_thermoelastic_1d", // Hard-coded value of the section's extension stiffness RealMatrixX D_sec_texpB_true = RealMatrixX::Zero(2,1); - D_sec_texpB_true(0,0) = 328.40639999999956; - D_sec_texpB_true(1,0) = 243.959039999999; - - - // Convert the test and truth Eigen::Matrix objects to std::vector - // since Catch2 has built in methods to compare vectors - std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_texpB); - std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_texpB_true); + D_sec_texpB_true(0,0) = section.material.E() * section.material.alpha() * section.first_area_moment_z_true; + D_sec_texpB_true(1,0) = section.material.E() * section.material.alpha() * section.first_area_moment_y_true; // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. // Therefore, we use the Approx comparison instead of Equals - CHECK_THAT( test, Catch::Approx(truth) ); + CHECK_THAT( TEST::eigen_matrix_to_std_vector(D_sec_texpB), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_texpB_true)) ); } } @@ -952,99 +611,20 @@ TEST_CASE("bar_element_property_card_constant_dynamic_1d", "[dynamic],[1D],[isotropic],[constant],[property]") { const uint dim = 1; + const uint n_target_elems = 3000; - // Define Material Properties as MAST Parameters - MAST::Parameter rho("rho_param", 1420.5); // Density - MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity - MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio - MAST::Parameter kappa("kappa_param", 5.0/6.0); // Shear coefficient - MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity - MAST::Parameter k("k_param", 237.0); // Thermal Conductivity - - // Define Section Properties as MAST Parameters - MAST::Parameter thickness_y("DIM1", 3.0); // Section thickness in z-direction - MAST::Parameter thickness_z("DIM2", 0.75); // Section thickness in y-direction - MAST::Parameter offset_y("offy_param", 0.287); // Section offset in y-direction - MAST::Parameter offset_z("offz_param", 1.654); // Section offset in z-direction - - // Create field functions to dsitribute these constant parameters throughout the model - // Section Property Field Functions - MAST::ConstantFieldFunction DIM1_f("DIM1", thickness_y); - MAST::ConstantFieldFunction DIM2_f("DIM2", thickness_z); - MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); - MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); - // Material Property Field Functions - MAST::ConstantFieldFunction rho_f("rho", rho); - MAST::ConstantFieldFunction E_f("E", E); - MAST::ConstantFieldFunction nu_f("nu", nu); - MAST::ConstantFieldFunction kappa_f("kappa", kappa); - MAST::ConstantFieldFunction cp_f("cp", cp); - MAST::ConstantFieldFunction k_f("k_th", k); - - // Initialize the material - MAST::IsotropicMaterialPropertyCard material; - - // Add the material property constant field functions to the material card - material.add(rho_f); - material.add(k_f); - material.add(cp_f); - material.add(E_f); - material.add(nu_f); - material.add(kappa_f); - - // Initialize the section - MAST::Solid1DBarSectionElementPropertyCard section; - - // Add the section property constant field functions to the section card - section.add(DIM1_f); - section.add(DIM2_f); - section.add(offsety_f); - section.add(offsetz_f); - - // Add the material card to the section card - section.set_material(material); - - // Specify a section orientation point and add it to the section. - RealVectorX orientation = RealVectorX::Zero(3); - orientation(1) = 1.0; - section.y_vector() = orientation; - - // Now initialize the section - section.init(*p_global_init); + TEST::AluminumBarSection section(n_target_elems); REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional - REQUIRE( section.depends_on(thickness_y) ); - REQUIRE( section.depends_on(offset_y) ); - REQUIRE( section.depends_on(thickness_z) ); - REQUIRE( section.depends_on(offset_z) ); - REQUIRE( section.depends_on(k) ); - REQUIRE( section.depends_on(cp) ); - REQUIRE( section.depends_on(rho) ); + REQUIRE( section.depends_on(section.DIM1) ); + REQUIRE( section.depends_on(section.offset_y) ); + REQUIRE( section.depends_on(section.offset_z) ); + REQUIRE( section.depends_on(section.material.k) ); + REQUIRE( section.depends_on(section.material.cp) ); + REQUIRE( section.depends_on(section.material.rho) ); + REQUIRE( section.if_isotropic() ); - // True values calculated using the sectionproperties module in python BAR.py - const Real area_true = 2.2500000000000004e+00; - const Real torsion_constant_true = 3.5540414988249380e-01; - const Real first_area_moment_z_true = 6.4574999999999994e-01; - const Real first_area_moment_y_true = 3.7214999999999945e+00; - const Real second_area_moment_zz_true = 2.9079899999999986e-01; - const Real second_area_moment_yy_true = 7.8428609999999814e+00; - const Real second_area_moment_zy_true = 1.0680705000000006e+00; - const Real second_area_moment_polar_true = 8.1336599999999812e+00; - const Real Izzc_true = 1.0546874999999994e-01; - const Real Iyyc_true = 1.6875000000000009e+00; - const Real Izyc_true = 2.4424906541753444e-15; - const Real warping_constant_true = 6.1030611538894504e-02; - const Real kappa_z_true = 8.3330248143102326e-01; - const Real kappa_y_true = 5.5763491072129889e-01; - const Real xs_true = 1.6540000458463804e+00; - const Real ys_true = 2.8700000023051281e-01; - const Real xst_true = 1.6540000458463804e+00; - const Real yst_true = 2.8700000023051281e-01; - const libMesh::Point shear_center_true(xs_true, ys_true, 0.); - const libMesh::Point centroid_true(1.654, 0.287, 0.); - - // NOTE: The default 1D section is rectangular const libMesh::Point point(4.3, -3.5, -6.7); const Real time = 8.22; @@ -1074,26 +654,26 @@ TEST_CASE("bar_element_property_card_constant_dynamic_1d", Real area; const MAST::FieldFunction& Area = section.A(); Area(point, time, area); - REQUIRE( area == Approx(area_true) ); - D_sec_iner_true(0,0) = D_sec_iner_true(1,1) = D_sec_iner_true(2,2) = area_true; + REQUIRE( area == Approx(section.area_true) ); + D_sec_iner_true(0,0) = D_sec_iner_true(1,1) = D_sec_iner_true(2,2) = section.area_true; Real Ip; const MAST::FieldFunction& PolarInertia = section.Ip(); PolarInertia(point, time, Ip); - CHECK( Ip == Approx(second_area_moment_polar_true) ); - D_sec_iner_true(3,3) = second_area_moment_polar_true; + CHECK( Ip == Approx(section.second_area_moment_polar_true) ); + D_sec_iner_true(3,3) = section.second_area_moment_polar_true; Real first_area_moment_y; const MAST::FieldFunction& Ay = section.Ay(); Ay(point, time, first_area_moment_y); - CHECK( first_area_moment_y == Approx(first_area_moment_y_true) ); - D_sec_iner_true(0,4) = D_sec_iner_true(4,0) = first_area_moment_y_true; + CHECK( first_area_moment_y == Approx(section.first_area_moment_y_true) ); + D_sec_iner_true(0,4) = D_sec_iner_true(4,0) = section.first_area_moment_y_true; Real first_area_moment_z; const MAST::FieldFunction& Az = section.Az(); Az(point, time, first_area_moment_z); - CHECK( first_area_moment_z == Approx(first_area_moment_z_true) ); - D_sec_iner_true(0,5) = D_sec_iner_true(5,0) = first_area_moment_z_true; + CHECK( first_area_moment_z == Approx(section.first_area_moment_z_true) ); + D_sec_iner_true(0,5) = D_sec_iner_true(5,0) = section.first_area_moment_z_true; RealMatrixX I; const MAST::FieldFunction& Inertias = section.I(); @@ -1102,26 +682,21 @@ TEST_CASE("bar_element_property_card_constant_dynamic_1d", Real Iyy = I(1,1); Real Izz = I(0,0); Real Izy = I(0,1); - REQUIRE( Izz == Approx(second_area_moment_zz_true) ); - REQUIRE( Iyy == Approx(second_area_moment_yy_true) ); - REQUIRE( Izy == Approx(second_area_moment_zy_true) ); + REQUIRE( Izz == Approx(section.second_area_moment_zz_true) ); + REQUIRE( Iyy == Approx(section.second_area_moment_yy_true) ); + REQUIRE( Izy == Approx(section.second_area_moment_zy_true) ); - D_sec_iner_true(4,4) = Iyy; + D_sec_iner_true(4,4) = Iyy; // Should this be Izz? D_sec_iner_true(4,5) = Izy; D_sec_iner_true(5,4) = Izy; - D_sec_iner_true(5,5) = Izz; + D_sec_iner_true(5,5) = Izz; // Should this by Iyy? - D_sec_iner_true *= rho(); - - // Convert the test and truth Eigen::Matrix objects to std::vector - // since Catch2 has built in methods to compare vectors - std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_iner); - std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_iner_true); + D_sec_iner_true *= section.material.rho(); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. // Therefore, we use the Approx comparison instead of Equals - CHECK_THAT( test, Catch::Approx(truth) ); + CHECK_THAT( TEST::eigen_matrix_to_std_vector(D_sec_iner), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_iner_true)) ); } } @@ -1130,95 +705,20 @@ TEST_CASE("bar_element_property_card_constant_structural_1d", "[structural],[1D],[isotropic],[constant],[property]") { const uint dim = 1; + const uint n_target_elems = 3000; - // Define Material Properties as MAST Parameters - MAST::Parameter rho("rho_param", 1420.5); // Density - MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity - MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio - MAST::Parameter kappa("kappa_param", 5.0/6.0); // Shear coefficient - const Real G = E() / (2.0 * (1.0+nu())); - - // Define Section Properties as MAST Parameters - MAST::Parameter thickness_y("DIM1", 3.0); // Section thickness in z-direction - MAST::Parameter thickness_z("DIM2", 0.75); // Section thickness in y-direction - MAST::Parameter offset_y("offy_param", 0.287); // Section offset in y-direction - MAST::Parameter offset_z("offz_param", 1.654); // Section offset in z-direction - - // Create field functions to dsitribute these constant parameters throughout the model - // Section Property Field Functions - MAST::ConstantFieldFunction DIM1_f("DIM1", thickness_y); - MAST::ConstantFieldFunction DIM2_f("DIM2", thickness_z); - MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); - MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); - // Material Property Field Functions - MAST::ConstantFieldFunction rho_f("rho", rho); - MAST::ConstantFieldFunction E_f("E", E); - MAST::ConstantFieldFunction nu_f("nu", nu); - MAST::ConstantFieldFunction kappa_f("kappa", kappa); - - // Initialize the material - MAST::IsotropicMaterialPropertyCard material; - - // Add the material property constant field functions to the material card - material.add(rho_f); - material.add(E_f); - material.add(nu_f); - material.add(kappa_f); - - // Initialize the section - MAST::Solid1DBarSectionElementPropertyCard section; - - // Add the section property constant field functions to the section card - section.add(DIM1_f); - section.add(DIM2_f); - section.add(offsety_f); - section.add(offsetz_f); - - // Add the material card to the section card - section.set_material(material); - - // Specify a section orientation point and add it to the section. - RealVectorX orientation = RealVectorX::Zero(3); - orientation(1) = 1.0; - section.y_vector() = orientation; - - // Now initialize the section - section.init(*p_global_init); + TEST::AluminumBarSection section(n_target_elems); REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional - REQUIRE( section.depends_on(thickness_y) ); - REQUIRE( section.depends_on(offset_y) ); - REQUIRE( section.depends_on(thickness_z) ); - REQUIRE( section.depends_on(offset_z) ); - REQUIRE( section.depends_on(E) ); - REQUIRE( section.depends_on(nu) ); - REQUIRE( section.depends_on(kappa) ); - REQUIRE( section.depends_on(rho) ); + REQUIRE( section.depends_on(section.DIM1) ); + REQUIRE( section.depends_on(section.offset_y) ); + REQUIRE( section.depends_on(section.offset_z) ); + REQUIRE( section.depends_on(section.material.k) ); + REQUIRE( section.depends_on(section.material.cp) ); + REQUIRE( section.depends_on(section.material.rho) ); + REQUIRE( section.if_isotropic() ); - // True values calculated using the sectionproperties module in python BAR.py - const Real area_true = 2.2500000000000004e+00; - const Real torsion_constant_true = 3.5540414988249380e-01; - const Real first_area_moment_z_true = 6.4574999999999994e-01; - const Real first_area_moment_y_true = 3.7214999999999945e+00; - const Real second_area_moment_zz_true = 2.9079899999999986e-01; - const Real second_area_moment_yy_true = 7.8428609999999814e+00; - const Real second_area_moment_zy_true = 1.0680705000000006e+00; - const Real second_area_moment_polar_true = 8.1336599999999812e+00; - const Real Izzc_true = 1.0546874999999994e-01; - const Real Iyyc_true = 1.6875000000000009e+00; - const Real Izyc_true = 2.4424906541753444e-15; - const Real warping_constant_true = 6.1030611538894504e-02; - const Real kappa_z_true = 8.3330248143102326e-01; - const Real kappa_y_true = 5.5763491072129889e-01; - const Real xs_true = 1.6540000458463804e+00; - const Real ys_true = 2.8700000023051281e-01; - const Real xst_true = 1.6540000458463804e+00; - const Real yst_true = 2.8700000023051281e-01; - const libMesh::Point shear_center_true(xs_true, ys_true, 0.); - const libMesh::Point centroid_true(1.654, 0.287, 0.); - - // NOTE: The default 1D section is rectangular const libMesh::Point point(4.3, -3.5, -6.7); const Real time = 8.22; @@ -1258,12 +758,12 @@ TEST_CASE("bar_element_property_card_constant_structural_1d", Real area; const MAST::FieldFunction& Area = section.A(); Area(point, time, area); - REQUIRE( area == Approx(area_true) ); + REQUIRE( area == Approx(section.area_true) ); Real torsion_constant; const MAST::FieldFunction& TorsionConstant = section.J(); TorsionConstant(point, time, torsion_constant); - REQUIRE( torsion_constant == Approx(torsion_constant_true).epsilon(0.05) ); + REQUIRE( torsion_constant == Approx(section.torsion_constant_true).epsilon(0.05) ); std::unique_ptr> extension_stiffness_mat = section.stiffness_A_matrix(); @@ -1276,19 +776,13 @@ TEST_CASE("bar_element_property_card_constant_structural_1d", // Hard-coded value of the section's extension stiffness RealMatrixX D_sec_ext_true = RealMatrixX::Zero(2,2); - D_sec_ext_true(0,0) = E() * area_true; - D_sec_ext_true(1,1) = G * torsion_constant_true; - - - // Convert the test and truth Eigen::Matrix objects to std::vector - // since Catch2 has built in methods to compare vectors - std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_ext); - std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_ext_true); + D_sec_ext_true(0,0) = section.material.E() * section.area_true; + D_sec_ext_true(1,1) = section.material.G() * section.torsion_constant_true; // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. // Therefore, we use the Approx comparison instead of Equals - CHECK_THAT( test, Catch::Approx(truth).epsilon(0.05) ); + CHECK_THAT( TEST::eigen_matrix_to_std_vector(D_sec_ext), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_ext_true)).epsilon(0.05) ); } @@ -1311,9 +805,9 @@ TEST_CASE("bar_element_property_card_constant_structural_1d", Real Izz = I(0,0); Real Iyy = I(1,1); Real Izy = I(0,1); - REQUIRE( Izz == Approx(second_area_moment_zz_true) ); - REQUIRE( Iyy == Approx(second_area_moment_yy_true) ); - REQUIRE( Izy == Approx(second_area_moment_zy_true) ); + REQUIRE( Izz == Approx(section.second_area_moment_zz_true) ); + REQUIRE( Iyy == Approx(section.second_area_moment_yy_true) ); + REQUIRE( Izy == Approx(section.second_area_moment_zy_true) ); std::unique_ptr> bending_stiffness_mat = section.stiffness_D_matrix(); @@ -1324,20 +818,15 @@ TEST_CASE("bar_element_property_card_constant_structural_1d", // Hard-coded value of the section's extension stiffness RealMatrixX D_sec_bnd_true = RealMatrixX::Zero(2,2); - D_sec_bnd_true(0,0) = E() * second_area_moment_zz_true; - D_sec_bnd_true(1,1) = E() * second_area_moment_yy_true; - D_sec_bnd_true(0,1) = E() * second_area_moment_zy_true; - D_sec_bnd_true(1,0) = E() * second_area_moment_zy_true; - - // Convert the test and truth Eigen::Matrix objects to std::vector - // since Catch2 has built in methods to compare vectors - std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_bnd); - std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_bnd_true); + D_sec_bnd_true(0,0) = section.material.E() * section.second_area_moment_zz_true; + D_sec_bnd_true(1,1) = section.material.E() * section.second_area_moment_yy_true; + D_sec_bnd_true(0,1) = section.material.E() * section.second_area_moment_zy_true; + D_sec_bnd_true(1,0) = section.material.E() * section.second_area_moment_zy_true; // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. // Therefore, we use the Approx comparison instead of Equals - CHECK_THAT( test, Catch::Approx(truth) ); + CHECK_THAT( TEST::eigen_matrix_to_std_vector(D_sec_bnd), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_bnd_true)) ); } SECTION("1D extension-bending section stiffness matrix") @@ -1355,12 +844,12 @@ TEST_CASE("bar_element_property_card_constant_structural_1d", Real first_area_moment_y; const MAST::FieldFunction& Ay = section.Ay(); Ay(point, time, first_area_moment_y); - CHECK( first_area_moment_y == Approx(first_area_moment_y_true) ); + CHECK( first_area_moment_y == Approx(section.first_area_moment_y_true) ); Real first_area_moment_z; const MAST::FieldFunction& Az = section.Az(); Az(point, time, first_area_moment_z); - CHECK( first_area_moment_z == Approx(first_area_moment_z_true) ); + CHECK( first_area_moment_z == Approx(section.first_area_moment_z_true) ); std::unique_ptr> bndext_stiffness_mat = section.stiffness_B_matrix(); @@ -1371,19 +860,14 @@ TEST_CASE("bar_element_property_card_constant_structural_1d", // Hard-coded value of the section's extension stiffness RealMatrixX D_sec_bndext_true = RealMatrixX::Zero(2,2); - D_sec_bndext_true(0,0) = E() * first_area_moment_z_true; - D_sec_bndext_true(0,1) = E() * first_area_moment_y_true; + D_sec_bndext_true(0,0) = section.material.E() * section.first_area_moment_z_true; + D_sec_bndext_true(0,1) = section.material.E() * section.first_area_moment_y_true; // TODO: Add checks for torsion bending coupling when added to MAST. - // Convert the test and truth Eigen::Matrix objects to std::vector - // since Catch2 has built in methods to compare vectors - std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_bndext); - std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_bndext_true); - // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. // Therefore, we use the Approx comparison instead of Equals - CHECK_THAT( test, Catch::Approx(truth) ); + CHECK_THAT( TEST::eigen_matrix_to_std_vector(D_sec_bndext), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_bndext_true)) ); } SECTION("1D transverse shear section stiffness matrix") @@ -1401,7 +885,7 @@ TEST_CASE("bar_element_property_card_constant_structural_1d", Real area; const MAST::FieldFunction& Area = section.A(); Area(point, time, area); - REQUIRE( area == Approx(area_true) ); + REQUIRE( area == Approx(section.area_true) ); std::unique_ptr> trans_shear_stiffness_mat = section.transverse_shear_stiffness_matrix(); @@ -1412,18 +896,13 @@ TEST_CASE("bar_element_property_card_constant_structural_1d", // Hard-coded value of the section's extension stiffness RealMatrixX D_sec_shr_true = RealMatrixX::Zero(2,2); - D_sec_shr_true(0,0) = G*area_true*kappa_z_true; - D_sec_shr_true(1,1) = G*area_true*kappa_y_true; - - // Convert the test and truth Eigen::Matrix objects to std::vector - // since Catch2 has built in methods to compare vectors - std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_shr); - std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_shr_true); + D_sec_shr_true(0,0) = section.material.G()*section.area_true*section.kappa_z_true; + D_sec_shr_true(1,1) = section.material.G()*section.area_true*section.kappa_y_true; // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. // Therefore, we use the Approx comparison instead of Equals - CHECK_THAT( test, Catch::Approx(truth) ); + CHECK_THAT( TEST::eigen_matrix_to_std_vector(D_sec_shr), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_shr_true)).epsilon(0.005) ); } @@ -1450,14 +929,10 @@ TEST_CASE("bar_element_property_card_constant_structural_1d", // // NOTE: Should be all zero's for non-bushing sections // RealMatrixX D_sec_spring_true = RealMatrixX::Zero(4,6); // -// // Convert the test and truth Eigen::Matrix objects to std::vector -// // since Catch2 has built in methods to compare vectors -// std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_spring); -// std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_spring_true); // // // Floating point approximations are diffcult to compare since the // // values typically aren't exactly equal due to numerical error. // // Therefore, we use the Approx comparison instead of Equals -// CHECK_THAT( test, Catch::Approx(truth) ); +// CHECK_THAT( TEST::eigen_matrix_to_std_vector(D_sec_spring), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_spring_true)) ); // } } diff --git a/tests/property/mast_solid_1d_bar_section_element_property_card.h b/tests/property/mast_solid_1d_bar_section_element_property_card.h new file mode 100644 index 00000000..e9949280 --- /dev/null +++ b/tests/property/mast_solid_1d_bar_section_element_property_card.h @@ -0,0 +1,87 @@ +#ifndef MAST_SOLID_1D_BAR_SECTION_ELEMENT_PROPERTY_CARD_H_INCLUDED +#define MAST_SOLID_1D_BAR_SECTION_ELEMENT_PROPERTY_CARD_H_INCLUDED + +#include "property_cards/solid_1d_bar_section_element_property_card.h" +#include "material/mast_isotropic_material.h" + +extern libMesh::LibMeshInit* p_global_init; + +namespace TEST +{ + class AluminumBarSection : public MAST::Solid1DBarSectionElementPropertyCard + { + public: + + AluminumBarSection(const uint n_target_elems=3500): + DIM1("DIM1", 3.0), DIM2("DIM2", 0.75), + offset_y("offy_param", 0.287), offset_z("offz_param", 1.654), + DIM1_f("DIM1", DIM1), DIM2_f("DIM2", DIM2), + offsety_f("hy_off", offset_y), offsetz_f("hz_off", offset_z), + centroid_true(xc_true, yc_true), shear_center_true(xs_true, ys_true) + { + add(DIM1_f); + add(DIM2_f); + + add(offsety_f); + add(offsetz_f); + + // Add the material card to the section card + set_material(material); + + // Specify a section orientation point and add it to the + RealVectorX orientation = RealVectorX::Zero(3); + orientation(1) = 1.0; + y_vector() = orientation; + + // Now initialize the section + init(*p_global_init, n_target_elems); + } + + TEST::Aluminum7075T6 material; + + MAST::Parameter DIM1; + MAST::Parameter DIM2; + + MAST::Parameter offset_y; + MAST::Parameter offset_z; + + MAST::ConstantFieldFunction DIM1_f; + MAST::ConstantFieldFunction DIM2_f; + + MAST::ConstantFieldFunction offsety_f; + MAST::ConstantFieldFunction offsetz_f; + + // True values calculated using the sectionproperties module in python BAR.py + const Real area_true = 2.2500000000000004e+00; + const Real torsion_constant_true = 3.5540414988249380e-01; + const Real first_area_moment_z_true = 6.4574999999999994e-01; + const Real first_area_moment_y_true = 3.7214999999999945e+00; + const Real second_area_moment_zz_true = 2.9079899999999986e-01; + const Real second_area_moment_yy_true = 7.8428609999999814e+00; + const Real second_area_moment_zy_true = 1.0680705000000006e+00; + const Real second_area_moment_polar_true = 8.1336599999999812e+00; + const Real Izzc_true = 1.0546874999999994e-01; + const Real Iyyc_true = 1.6875000000000009e+00; + const Real Izyc_true = 2.4424906541753444e-15; + const Real warping_constant_true = 6.1030611538894504e-02; + const Real kappa_z_true = 8.3330248143102326e-01; + const Real kappa_y_true = 5.5763491072129889e-01; + const Real xs_true = 1.6540000458463804e+00; + const Real ys_true = 2.8700000023051281e-01; + const Real xst_true = 1.6540000458463804e+00; + const Real yst_true = 2.8700000023051281e-01; + const Real xc_true = 1.654; + const Real yc_true = 0.287; + const std::vector stress_points_true = { + libMesh::Point(1.5, 0.375, 0.), + libMesh::Point(1.5, -0.375, 0.), + libMesh::Point(-1.5, -0.375, 0.), + libMesh::Point(-1.5, 0.375, 0.) + }; + + libMesh::Point centroid_true; + libMesh::Point shear_center_true; + + }; +} +#endif // MAST_SOLID_1D_BAR_SECTION_ELEMENT_PROPERTY_CARD_H_INCLUDED diff --git a/tests/property/mast_solid_1d_rod_section_element_property_card.cpp b/tests/property/mast_solid_1d_rod_section_element_property_card.cpp index 5096c38e..eaad500f 100644 --- a/tests/property/mast_solid_1d_rod_section_element_property_card.cpp +++ b/tests/property/mast_solid_1d_rod_section_element_property_card.cpp @@ -1,187 +1,116 @@ // Catch2 includes #include "catch.hpp" -// libMesh includes -#include "libmesh/point.h" - -// MAST includes -#include "base/parameter.h" -#include "base/constant_field_function.h" -#include "property_cards/isotropic_material_property_card.h" -#include "property_cards/solid_1d_rod_section_element_property_card.h" - // Custom includes #include "test_helpers.h" +#include "mast_solid_1d_rod_section_element_property_card.h" -extern libMesh::LibMeshInit* p_global_init; - -#define PI 3.1415926535897932 -/** - * A BAR is defined as a solid rectangular cross section defined by two - * parameters. - */ TEST_CASE("rod_element_property_card_constant_base_1d", "[1D],[isotropic],[constant],[property]") { const uint dim = 1; - - // Define Material Properties as MAST Parameters - MAST::Parameter rho("rho_param", 1420.5); // Density - MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity - MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio - MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity - MAST::Parameter k("k_param", 237.0); // Thermal Conductivity - - const Real G = E() / (2. * (1. + nu())); - - // Define Section Properties as MAST Parameters - MAST::Parameter DIM1("DIM1", 3.234); // Section thickness in z-direction - MAST::Parameter offset_y("offy_param", 0.287); // Section offset in y-direction - MAST::Parameter offset_z("offz_param", -1.654); // Section offset in z-direction - - // Define Sensitivity Parameters - std::vector sens_params = {&DIM1}; - uint n_s = sens_params.size(); - - // Create field functions to dsitribute these constant parameters throughout the model - // Section Property Field Functions - MAST::ConstantFieldFunction DIM1_f("DIM1", DIM1); - MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); - MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); - // Material Property Field Functions - MAST::ConstantFieldFunction rho_f("rho", rho); - MAST::ConstantFieldFunction E_f("E", E); - MAST::ConstantFieldFunction nu_f("nu", nu); - MAST::ConstantFieldFunction cp_f("cp", cp); - MAST::ConstantFieldFunction k_f("k_th", k); + const uint n_target_elems = 3000; - // Initialize the material - MAST::IsotropicMaterialPropertyCard material; + TEST::AluminumRodSection section(n_target_elems); - // Add the material property constant field functions to the material card - material.add(rho_f); - material.add(k_f); - material.add(cp_f); - material.add(E_f); - material.add(nu_f); - - // Initialize the section - MAST::Solid1DRodSectionElementPropertyCard section; - - // Add the section property constant field functions to the section card - section.add(DIM1_f); - - section.add(offsety_f); - section.add(offsetz_f); - - // Add the material card to the section card - section.set_material(material); + REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional + REQUIRE( section.depends_on(section.DIM1) ); - // Specify a section orientation point and add it to the section. - RealVectorX orientation = RealVectorX::Zero(3); - orientation(1) = 1.0; - section.y_vector() = orientation; + REQUIRE( section.depends_on(section.offset_y) ); + REQUIRE( section.depends_on(section.offset_z) ); - // Now initialize the section - section.init(*p_global_init); - - REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional - REQUIRE( section.depends_on(DIM1) ); - REQUIRE( section.depends_on(offset_y) ); - REQUIRE( section.depends_on(offset_z) ); - REQUIRE( section.depends_on(k) ); - REQUIRE( section.depends_on(cp) ); - REQUIRE( section.depends_on(rho) ); + REQUIRE( section.depends_on(section.material.k) ); + REQUIRE( section.depends_on(section.material.cp) ); + REQUIRE( section.depends_on(section.material.rho) ); + REQUIRE( section.depends_on(section.material.E) ); + REQUIRE( section.depends_on(section.material.nu) ); + REQUIRE( section.depends_on(section.material.alpha) ); REQUIRE( section.if_isotropic() ); - // True values - const Real r = DIM1(); - const Real area_true = PI*r*r; - const Real torsion_constant_true = PI*pow(r, 4.0)/2.0; - const Real first_area_moment_z_true = area_true * offset_y(); - const Real first_area_moment_y_true = area_true * offset_z(); - const Real Izzc_true = PI*pow(r, 4.0)/4.0; - const Real Iyyc_true = PI*pow(r, 4.0)/4.0; - const Real Izyc_true = 0.0; - const Real Ipc_true = PI*pow(r, 4.0)/2.0; - const Real second_area_moment_zz_true = Izzc_true + area_true * pow(offset_y(), 2.); - const Real second_area_moment_yy_true = Iyyc_true + area_true * pow(offset_z(), 2.); - const Real second_area_moment_zy_true = Izyc_true + area_true * offset_y() * offset_z(); - const Real second_area_moment_polar_true = second_area_moment_zz_true + second_area_moment_yy_true; - const Real warping_constant_true = 0.0; - const Real kappa_z_true = 8.4967018479575718e-01; - const Real kappa_y_true = 8.4967018474199052e-01; - const Real xs_true = offset_z(); - const Real ys_true = offset_y(); - const Real xc_true = offset_z(); - const Real yc_true = offset_y(); - const libMesh::Point shear_center_true(xs_true, ys_true, 0.); - const libMesh::Point centroid_true(xc_true, yc_true, 0.); - const libMesh::Point point(4.3, -3.5, -6.7); const Real time = 8.22; - Real area; - const MAST::FieldFunction& Area = section.A(); - Area(point, time, area); - REQUIRE( area == Approx(area_true) ); - - Real first_area_moment_y; - const MAST::FieldFunction& Ay = section.Ay(); - Ay(point, time, first_area_moment_y); - CHECK( first_area_moment_y == Approx(first_area_moment_y_true) ); - - Real first_area_moment_z; - const MAST::FieldFunction& Az = section.Az(); - Az(point, time, first_area_moment_z); - CHECK( first_area_moment_z == Approx(first_area_moment_z_true) ); - - RealMatrixX I; - const MAST::FieldFunction& Inertias = section.I(); - Inertias(point, time, I); - REQUIRE( I(0,1) == I(1,0) ); - Real Iyy = I(1,1); - Real Izz = I(0,0); - Real Izy = I(0,1); - REQUIRE( Izz == Approx(second_area_moment_zz_true) ); - REQUIRE( Iyy == Approx(second_area_moment_yy_true) ); - REQUIRE( Izy == Approx(second_area_moment_zy_true) ); - - Real Ip; - const MAST::FieldFunction& PolarInertia = section.Ip(); - PolarInertia(point, time, Ip); - REQUIRE( Ip == Approx(second_area_moment_polar_true) ); - - Real torsion_constant; - const MAST::FieldFunction& TorsionConstant = section.J(); - TorsionConstant(point, time, torsion_constant); - REQUIRE( torsion_constant == Approx(torsion_constant_true)); - - Real warping_constant; - const MAST::FieldFunction& WarpingConstant = section.Gam(); - WarpingConstant(point, time, warping_constant); - REQUIRE( warping_constant == Approx(warping_constant_true) ); - - RealMatrixX shear_coefficients; - const MAST::FieldFunction& ShearCoefficientMatrix = section.Kap(); - ShearCoefficientMatrix(point, time, shear_coefficients); - REQUIRE( shear_coefficients(0,0) == Approx(kappa_z_true) ); - REQUIRE( shear_coefficients(1,1) == Approx(kappa_y_true) ); - - libMesh::Point centroid = section.get_centroid(point, time); - REQUIRE( centroid(0) == Approx(centroid_true(0)) ); - REQUIRE( centroid(1) == Approx(centroid_true(1)) ); - - libMesh::Point shear_center = section.get_shear_center(point, time); - REQUIRE(shear_center(0) == Approx(xs_true)); - REQUIRE(shear_center(1) == Approx(ys_true)); + SECTION("section_properties") + { + Real area; + const MAST::FieldFunction& Area = section.A(); + Area(point, time, area); + CHECK( area == Approx(section.area_true) ); + + Real first_area_moment_y; + const MAST::FieldFunction& Ay = section.Ay(); + Ay(point, time, first_area_moment_y); + CHECK( first_area_moment_y == Approx(section.first_area_moment_y_true) ); + + Real first_area_moment_z; + const MAST::FieldFunction& Az = section.Az(); + Az(point, time, first_area_moment_z); + CHECK( first_area_moment_z == Approx(section.first_area_moment_z_true) ); + + RealMatrixX I; + const MAST::FieldFunction& Inertias = section.I(); + Inertias(point, time, I); + CHECK( I(0,1) == I(1,0) ); + Real Iyy = I(1,1); + Real Izz = I(0,0); + Real Izy = I(0,1); + CHECK( Izz == Approx(section.second_area_moment_zz_true) ); + CHECK( Iyy == Approx(section.second_area_moment_yy_true) ); + CHECK( Izy == Approx(section.second_area_moment_zy_true) ); + + Real Ip; + const MAST::FieldFunction& PolarInertia = section.Ip(); + PolarInertia(point, time, Ip); + CHECK( Ip == Approx(section.second_area_moment_polar_true) ); + + Real torsion_constant; + const MAST::FieldFunction& TorsionConstant = section.J(); + TorsionConstant(point, time, torsion_constant); + CHECK( torsion_constant == Approx(section.torsion_constant_true).epsilon(0.005)); + + libMesh::Point centroid = section.get_centroid(point, time); + CHECK( centroid(0) == Approx(section.centroid_true(0)) ); + CHECK( centroid(1) == Approx(section.centroid_true(1)) ); + + libMesh::Point shear_center = section.get_shear_center(point, time); + CHECK(shear_center(0) == Approx(section.xs_true).epsilon(0.005)); + CHECK(shear_center(1) == Approx(section.ys_true).epsilon(0.005)); + + RealMatrixX shear_coefficients; + const MAST::FieldFunction& ShearCoefficientMatrix = section.Kap(); + ShearCoefficientMatrix(point, time, shear_coefficients); + CHECK( shear_coefficients(0,0) == Approx(section.kappa_z_true).epsilon(0.005) ); + CHECK( shear_coefficients(1,1) == Approx(section.kappa_y_true).epsilon(0.005) ); + + Real warping_constant; + const MAST::FieldFunction& WarpingConstant = section.Gam(); + WarpingConstant(point, time, warping_constant); + CHECK( warping_constant == Approx(section.warping_constant_true).epsilon(0.005) ); + } - REQUIRE_FALSE( section.if_diagonal_mass_matrix() ); + SECTION("stress_points") + { + libMesh::Point centroid = section.get_centroid(point, time); + CHECK( centroid(0) == Approx(section.centroid_true(0)) ); + CHECK( centroid(1) == Approx(section.centroid_true(1)) ); + std::vector stress_points = section.get_stress_points(point, time, centroid); + + for (uint i=0; i sens_params = {&DIM1}; + std::vector sens_params = {§ion.DIM1}; uint n_s = sens_params.size(); - // Create field functions to dsitribute these constant parameters throughout the model - // Section Property Field Functions - MAST::ConstantFieldFunction DIM1_f("DIM1", DIM1); - MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); - MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); - // Material Property Field Functions - MAST::ConstantFieldFunction rho_f("rho", rho); - MAST::ConstantFieldFunction E_f("E", E); - MAST::ConstantFieldFunction nu_f("nu", nu); - MAST::ConstantFieldFunction cp_f("cp", cp); - MAST::ConstantFieldFunction k_f("k_th", k); - - // Initialize the material - MAST::IsotropicMaterialPropertyCard material; - - // Add the material property constant field functions to the material card - material.add(rho_f); - material.add(k_f); - material.add(cp_f); - material.add(E_f); - material.add(nu_f); - - // Initialize the section - MAST::Solid1DRodSectionElementPropertyCard section; - - // Add the section property constant field functions to the section card - section.add(DIM1_f); - section.add(offsety_f); - section.add(offsetz_f); - - // Add the material card to the section card - section.set_material(material); - - // Specify a section orientation point and add it to the section. - RealVectorX orientation = RealVectorX::Zero(3); - orientation(1) = 1.0; - section.y_vector() = orientation; - - // Now initialize the section - section.init(*p_global_init); - - REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional - REQUIRE( section.depends_on(DIM1) ); - REQUIRE( section.depends_on(offset_y) ); - REQUIRE( section.depends_on(offset_z) ); - REQUIRE( section.depends_on(k) ); - REQUIRE( section.depends_on(cp) ); - REQUIRE( section.depends_on(rho) ); - REQUIRE( section.if_isotropic() ); - // True values - const Real r = DIM1(); - const Real area_true = PI*r*r; - const Real torsion_constant_true = PI*pow(r, 4.0)/2.0; - const Real first_area_moment_z_true = area_true * offset_y(); - const Real first_area_moment_y_true = area_true * offset_z(); - const Real Izzc_true = PI*pow(r, 4.0)/4.0; - const Real Iyyc_true = PI*pow(r, 4.0)/4.0; - const Real Izyc_true = 0.0; - const Real Ipc_true = PI*pow(r, 4.0)/2.0; - const Real second_area_moment_zz_true = Izzc_true + area_true * pow(offset_y(), 2.); - const Real second_area_moment_yy_true = Iyyc_true + area_true * pow(offset_z(), 2.); - const Real second_area_moment_zy_true = Izyc_true + area_true * offset_y() * offset_z(); - const Real second_area_moment_polar_true = second_area_moment_zz_true + second_area_moment_yy_true; - const Real warping_constant_true = 0.0; - const Real kappa_z_true = 8.4967018479575718e-01; - const Real kappa_y_true = 8.4967018474199052e-01; - const Real xs_true = offset_z(); - const Real ys_true = offset_y(); - const Real xc_true = offset_z(); - const Real yc_true = offset_y(); - const libMesh::Point shear_center_true(xs_true, ys_true, 0.); - const libMesh::Point centroid_true(xc_true, yc_true, 0.); - const libMesh::Point point(4.3, -3.5, -6.7); const Real time = 8.22; @@ -315,7 +159,6 @@ TEST_CASE("rod_element_property_card_constant_base_sensitivity_1d", const Real delta = 1.220703125e-04; // (np.spacing(1))**(0.25) // Area Sensitivity Check - libMesh::out << "\tArea Sensitivity Check..." << std::endl; const MAST::FieldFunction& Area = section.A(); std::vector dA(n_s); for (uint i=0; i dA_cd(n_s); for (uint i=0; iname() << " = " << dA[i] << "\tdA_cd = " << dA_cd[i] << std::endl; REQUIRE(dA[i] == Approx(dA_cd[i])); } // Centroid Sensitivity Check - libMesh::out << "\tCentroid Sensitivity Check..." << std::endl; std::vector dC(n_s); for (uint i=0; iname() << " = " << dC[i] << "\tdC_cd = " << dC_cd[i] << std::endl; REQUIRE(dC[i](0) == Approx(dC_cd[i](0)).margin(1.49e-08) ); REQUIRE(dC[i](1) == Approx(dC_cd[i](1)).margin(1.49e-08) ); } // First Area Moments Sensitivity Check - libMesh::out << "\tArea Moment Y Sensitivity Check..." << std::endl; const MAST::FieldFunction& Area_y = section.Ay(); std::vector dAy(n_s); for (uint i=0; i dAy_cd(n_s); for (uint i=0; iname() << " = " << dAy[i] << "\tdAy_cd = " << dAy_cd[i] << std::endl; REQUIRE(dAy[i] == Approx(dAy_cd[i])); } - libMesh::out << "\tArea Momemnt Z Sensitivity Check..." << std::endl; + const MAST::FieldFunction& Area_z = section.Az(); std::vector dAz(n_s); for (uint i=0; i dAz_cd(n_s); for (uint i=0; iname() << " = " << dAz[i] << "\tdAz_cd = " << dAz_cd[i] << std::endl; REQUIRE(dAz[i] == Approx(dAz_cd[i])); } // Second Area Moments Sensitivity Check - libMesh::out << "\tSecond Area Moments Sensitivity Check..." << std::endl; const MAST::FieldFunction& Inertia = section.I(); std::vector dI(n_s); for (uint i=0; i dI_cd(n_s); for (uint i=0; iname() << " =\n" << dI[i] << "\ndI_cd = \n" << dI_cd[i] << std::endl; - (*sens_params[i])() -= delta; - Inertia(point, time, fm_2n); - - (*sens_params[i])() += 2.0*delta; - - dI_cd[i] = (fm_2n - 8.*fm_n + 8*fm_h - fm_2h)/(12.*delta); - Real dIzz = dI[i](0,0); Real dIyy = dI[i](1,1); Real dIyz = dI[i](1,0); @@ -487,7 +277,6 @@ TEST_CASE("rod_element_property_card_constant_base_sensitivity_1d", // Second Area Polar Moment Sensitivity Check - libMesh::out << "\tArea Polar Moment Sensitivity Check..." << std::endl; const MAST::FieldFunction& PolarInertia = section.Ip(); std::vector dIp(n_s); for (uint i=0; i dIp_cd(n_s); for (uint i=0; iname() << " = " << dIp[i] << "\tdIp_cd = " << dIp_cd[i] << std::endl; REQUIRE(dIp[i] == Approx(dIp_cd[i])); } @@ -552,7 +328,6 @@ TEST_CASE("rod_element_property_card_constant_base_sensitivity_1d", // Torsion Constant Sensitivity Check // NOTE: The field function below is not made constant because currently a finite difference is used to calculate sensitivity. - libMesh::out << "\tTorsion Constant Sensitivity Check..." << std::endl; MAST::FieldFunction& TorsionConstant = section.J(); std::vector dJ(n_s); for (uint i=0; i dJ_cd(n_s); for (uint i=0; iname() << " = " << dJ[i] << "\tdJ_cd = " << dJ_cd[i] << std::endl; REQUIRE(dJ[i] == Approx(dJ_cd[i]).epsilon(0.1) ); // NOTE: 10% error margin due to 'exact' sensitivity being calculated using finite difference } @@ -586,7 +348,6 @@ TEST_CASE("rod_element_property_card_constant_base_sensitivity_1d", // // Shear Coefficient Sensitivity Check // // NOTE: The field function below is not made constant because currently a finite difference is used to calculate sensitivity. -// libMesh::out << "\tShear Coefficient Sensitivity Check..." << std::endl; // MAST::FieldFunction& Kappa = section.Kap(); // std::vector dK(n_s); // for (uint i=0; i dK_cd(n_s); // for (uint i=0; iname() << " =\n" << dK[i] << "\ndK_cd = \n" << dK_cd[i] << std::endl; // -// (*sens_params[i])() -= 3.0*delta; -// Kappa(point, time, fm_n); -// -// (*sens_params[i])() -= delta; -// Kappa(point, time, fm_2n); -// -// (*sens_params[i])() += 2.0*delta; -// -// dK_cd[i] = (fm_2n + 8.*(fm_h - fm_n) - fm_2h)/(12.*delta); -// // Real dKzz = dK[i](0,0); // Real dKyy = dK[i](1,1); // Real dKyz = dK[i](1,0); @@ -634,7 +383,6 @@ TEST_CASE("rod_element_property_card_constant_base_sensitivity_1d", // Warping Constant Sensitivity Check // NOTE: The field function below is not made constant because currently a finite difference is used to calculate sensitivity. - libMesh::out << "\tWarping Constant Sensitivity Check..." << std::endl; MAST::FieldFunction& WarpingConstant = section.Gam(); std::vector dW(n_s); for (uint i=0; i dW_cd(n_s); for (uint i=0; iname() << " = " << dW[i] << "\tdW_cd = " << dW_cd[i] << std::endl; REQUIRE(dW[i] == Approx(dW_cd[i]).epsilon(0.1) ); @@ -668,107 +402,32 @@ TEST_CASE("rod_element_property_card_constant_base_sensitivity_1d", } + TEST_CASE("rod_element_property_card_constant_heat_transfer_1d", "[heat_transfer],[1D],[isotropic],[constant],[property]") { const uint dim = 1; - - // Define Material Properties as MAST Parameters - MAST::Parameter rho("rho_param", 1420.5); // Density - MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity - MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio - MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity - MAST::Parameter k("k_param", 237.0); // Thermal Conductivity - - const Real G = E() / (2. * (1. + nu())); - - // Define Section Properties as MAST Parameters - MAST::Parameter DIM1("DIM1", 3.234); // Section thickness in z-direction - MAST::Parameter offset_y("offy_param", 0.287); // Section offset in y-direction - MAST::Parameter offset_z("offz_param", -1.654); // Section offset in z-direction - - // Create field functions to dsitribute these constant parameters throughout the model - // Section Property Field Functions - MAST::ConstantFieldFunction DIM1_f("DIM1", DIM1); - MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); - MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); - // Material Property Field Functions - MAST::ConstantFieldFunction rho_f("rho", rho); - MAST::ConstantFieldFunction E_f("E", E); - MAST::ConstantFieldFunction nu_f("nu", nu); - MAST::ConstantFieldFunction cp_f("cp", cp); - MAST::ConstantFieldFunction k_f("k_th", k); - - // Initialize the material - MAST::IsotropicMaterialPropertyCard material; - - // Add the material property constant field functions to the material card - material.add(rho_f); - material.add(k_f); - material.add(cp_f); - material.add(E_f); - material.add(nu_f); - - // Initialize the section - MAST::Solid1DRodSectionElementPropertyCard section; - - // Add the section property constant field functions to the section card - section.add(DIM1_f); - section.add(offsety_f); - section.add(offsetz_f); - - // Add the material card to the section card - section.set_material(material); - - // Specify a section orientation point and add it to the section. - RealVectorX orientation = RealVectorX::Zero(3); - orientation(1) = 1.0; - section.y_vector() = orientation; - - // Now initialize the section - section.init(*p_global_init); + const uint n_target_elems = 3000; + + TEST::AluminumRodSection section(n_target_elems); REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional - REQUIRE( section.depends_on(DIM1) ); - REQUIRE( section.depends_on(offset_y) ); - REQUIRE( section.depends_on(offset_z) ); - REQUIRE( section.depends_on(k) ); - REQUIRE( section.depends_on(cp) ); - REQUIRE( section.depends_on(rho) ); + REQUIRE( section.depends_on(section.DIM1) ); + REQUIRE( section.depends_on(section.offset_y) ); + REQUIRE( section.depends_on(section.offset_z) ); + REQUIRE( section.depends_on(section.material.k) ); + REQUIRE( section.depends_on(section.material.cp) ); + REQUIRE( section.depends_on(section.material.rho) ); REQUIRE( section.if_isotropic() ); - // True values - const Real r = DIM1(); - const Real area_true = PI*r*r; - const Real torsion_constant_true = PI*pow(r, 4.0)/2.0; - const Real first_area_moment_z_true = area_true * offset_y(); - const Real first_area_moment_y_true = area_true * offset_z(); - const Real Izzc_true = PI*pow(r, 4.0)/4.0; - const Real Iyyc_true = PI*pow(r, 4.0)/4.0; - const Real Izyc_true = 0.0; - const Real Ipc_true = PI*pow(r, 4.0)/2.0; - const Real second_area_moment_zz_true = Izzc_true + area_true * pow(offset_y(), 2.); - const Real second_area_moment_yy_true = Iyyc_true + area_true * pow(offset_z(), 2.); - const Real second_area_moment_zy_true = Izyc_true + area_true * offset_y() * offset_z(); - const Real second_area_moment_polar_true = second_area_moment_zz_true + second_area_moment_yy_true; - const Real warping_constant_true = 0.0; - const Real kappa_z_true = 8.4967018479575718e-01; - const Real kappa_y_true = 8.4967018474199052e-01; - const Real xs_true = offset_z(); - const Real ys_true = offset_y(); - const Real xc_true = offset_z(); - const Real yc_true = offset_y(); - const libMesh::Point shear_center_true(xs_true, ys_true, 0.); - const libMesh::Point centroid_true(xc_true, yc_true, 0.); - const libMesh::Point point(4.3, -3.5, -6.7); const Real time = 8.22; Real area; const MAST::FieldFunction& Area = section.A(); Area(point, time, area); - REQUIRE( area == Approx(area_true) ); + REQUIRE( area == Approx(section.area_true) ); SECTION("1D section thermal conductance matrix") @@ -792,17 +451,12 @@ TEST_CASE("rod_element_property_card_constant_heat_transfer_1d", // Hard-coded value of the section's extension stiffness RealMatrixX D_sec_conduc_true = RealMatrixX::Zero(1,1); - D_sec_conduc_true(0,0) = k() * area_true; - - // Convert the test and truth Eigen::Matrix objects to std::vector - // since Catch2 has built in methods to compare vectors - std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_conduc); - std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_conduc_true); + D_sec_conduc_true(0,0) = section.material.k() * section.area_true; // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. // Therefore, we use the Approx comparison instead of Equals - CHECK_THAT( test, Catch::Approx(truth) ); + CHECK_THAT( TEST::eigen_matrix_to_std_vector(D_sec_conduc), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_conduc_true)) ); } SECTION("1D section thermal capacitance matrix") @@ -826,17 +480,12 @@ TEST_CASE("rod_element_property_card_constant_heat_transfer_1d", // Hard-coded value of the section's extension stiffness RealMatrixX D_sec_capac_true = RealMatrixX::Zero(1,1); - D_sec_capac_true(0,0) = rho() * cp() * area_true; - - // Convert the test and truth Eigen::Matrix objects to std::vector - // since Catch2 has built in methods to compare vectors - std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_capac); - std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_capac_true); + D_sec_capac_true(0,0) = section.material.rho() * section.material.cp() * section.area_true; // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. // Therefore, we use the Approx comparison instead of Equals - CHECK_THAT( test, Catch::Approx(truth) ); + CHECK_THAT( TEST::eigen_matrix_to_std_vector(D_sec_capac), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_capac_true)) ); } } @@ -845,99 +494,20 @@ TEST_CASE("rod_element_property_card_constant_thermoelastic_1d", "[thermoelastic],[1D],[isotropic],[constant],[property]") { const uint dim = 1; - - // Define Material Properties as MAST Parameters - MAST::Parameter rho("rho_param", 1420.5); // Density - MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity - MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio - MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity - MAST::Parameter k("k_param", 237.0); // Thermal Conductivity - MAST::Parameter alpha("alpha_param", 5.73e-05); // Coeff. of Thermal Exp. - - const Real G = E() / (2. * (1. + nu())); - - // Define Section Properties as MAST Parameters - MAST::Parameter DIM1("DIM1", 3.234); // Section thickness in z-direction - MAST::Parameter offset_y("offy_param", 0.287); // Section offset in y-direction - MAST::Parameter offset_z("offz_param", -1.654); // Section offset in z-direction - - // Create field functions to dsitribute these constant parameters throughout the model - // Section Property Field Functions - MAST::ConstantFieldFunction DIM1_f("DIM1", DIM1); - MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); - MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); - // Material Property Field Functions - MAST::ConstantFieldFunction rho_f("rho", rho); - MAST::ConstantFieldFunction E_f("E", E); - MAST::ConstantFieldFunction nu_f("nu", nu); - MAST::ConstantFieldFunction cp_f("cp", cp); - MAST::ConstantFieldFunction k_f("k_th", k); - MAST::ConstantFieldFunction alpha_f("alpha_expansion", alpha); - - // Initialize the material - MAST::IsotropicMaterialPropertyCard material; - - // Add the material property constant field functions to the material card - material.add(rho_f); - material.add(k_f); - material.add(cp_f); - material.add(E_f); - material.add(nu_f); - material.add(alpha_f); - - // Initialize the section - MAST::Solid1DRodSectionElementPropertyCard section; - - // Add the section property constant field functions to the section card - section.add(DIM1_f); - section.add(offsety_f); - section.add(offsetz_f); - - // Add the material card to the section card - section.set_material(material); - - // Specify a section orientation point and add it to the section. - RealVectorX orientation = RealVectorX::Zero(3); - orientation(1) = 1.0; - section.y_vector() = orientation; - - // Now initialize the section - section.init(*p_global_init); + const uint n_target_elems = 3000; + + TEST::AluminumRodSection section(n_target_elems); REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional - REQUIRE( section.depends_on(DIM1) ); - REQUIRE( section.depends_on(offset_y) ); - REQUIRE( section.depends_on(offset_z) ); - REQUIRE( section.depends_on(k) ); - REQUIRE( section.depends_on(cp) ); - REQUIRE( section.depends_on(rho) ); + REQUIRE( section.depends_on(section.DIM1) ); + REQUIRE( section.depends_on(section.offset_y) ); + REQUIRE( section.depends_on(section.offset_z) ); + REQUIRE( section.depends_on(section.material.k) ); + REQUIRE( section.depends_on(section.material.cp) ); + REQUIRE( section.depends_on(section.material.rho) ); REQUIRE( section.if_isotropic() ); - // True values - const Real r = DIM1(); - const Real area_true = PI*r*r; - const Real torsion_constant_true = PI*pow(r, 4.0)/2.0; - const Real first_area_moment_z_true = area_true * offset_y(); - const Real first_area_moment_y_true = area_true * offset_z(); - const Real Izzc_true = PI*pow(r, 4.0)/4.0; - const Real Iyyc_true = PI*pow(r, 4.0)/4.0; - const Real Izyc_true = 0.0; - const Real Ipc_true = PI*pow(r, 4.0)/2.0; - const Real second_area_moment_zz_true = Izzc_true + area_true * pow(offset_y(), 2.); - const Real second_area_moment_yy_true = Iyyc_true + area_true * pow(offset_z(), 2.); - const Real second_area_moment_zy_true = Izyc_true + area_true * offset_y() * offset_z(); - const Real second_area_moment_polar_true = second_area_moment_zz_true + second_area_moment_yy_true; - const Real warping_constant_true = 0.0; - const Real kappa_z_true = 8.4967018479575718e-01; - const Real kappa_y_true = 8.4967018474199052e-01; - const Real xs_true = offset_z(); - const Real ys_true = offset_y(); - const Real xc_true = offset_z(); - const Real yc_true = offset_y(); - const libMesh::Point shear_center_true(xs_true, ys_true, 0.); - const libMesh::Point centroid_true(xc_true, yc_true, 0.); - const libMesh::Point point(4.3, -3.5, -6.7); const Real time = 8.22; @@ -957,7 +527,7 @@ TEST_CASE("rod_element_property_card_constant_thermoelastic_1d", Real area; const MAST::FieldFunction& Area = section.A(); Area(point, time, area); - CHECK( area == Approx(area_true) ); + CHECK( area == Approx(section.area_true) ); std::unique_ptr> texp_A_mat = section.thermal_expansion_A_matrix(); @@ -968,18 +538,12 @@ TEST_CASE("rod_element_property_card_constant_thermoelastic_1d", // Hard-coded value of the section's extension stiffness RealMatrixX D_sec_texpA_true = RealMatrixX::Zero(2,1); - D_sec_texpA_true(0,0) = E() * alpha() * area_true; - - // Convert the test and truth Eigen::Matrix objects to std::vector - // since Catch2 has built in methods to compare vectors - std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_texpA); - std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_texpA_true); - + D_sec_texpA_true(0,0) = section.material.E() * section.material.alpha() * section.area_true; // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. // Therefore, we use the Approx comparison instead of Equals - CHECK_THAT( test, Catch::Approx(truth) ); + CHECK_THAT( TEST::eigen_matrix_to_std_vector(D_sec_texpA), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_texpA_true)) ); } SECTION("1D thermal expansion B matrix") @@ -998,12 +562,12 @@ TEST_CASE("rod_element_property_card_constant_thermoelastic_1d", Real first_area_moment_y; const MAST::FieldFunction& Ay = section.Ay(); Ay(point, time, first_area_moment_y); - CHECK( first_area_moment_y == Approx(first_area_moment_y_true) ); + CHECK( first_area_moment_y == Approx(section.first_area_moment_y_true) ); Real first_area_moment_z; const MAST::FieldFunction& Az = section.Az(); Az(point, time, first_area_moment_z); - CHECK( first_area_moment_z == Approx(first_area_moment_z_true) ); + CHECK( first_area_moment_z == Approx(section.first_area_moment_z_true) ); std::unique_ptr> texp_B_mat = section.thermal_expansion_B_matrix(); @@ -1016,19 +580,13 @@ TEST_CASE("rod_element_property_card_constant_thermoelastic_1d", // Hard-coded value of the section's extension stiffness RealMatrixX D_sec_texpB_true = RealMatrixX::Zero(2,1); - D_sec_texpB_true(0,0) = E() * alpha() * first_area_moment_z_true; - D_sec_texpB_true(1,0) = E() * alpha() * first_area_moment_y_true; - - - // Convert the test and truth Eigen::Matrix objects to std::vector - // since Catch2 has built in methods to compare vectors - std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_texpB); - std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_texpB_true); + D_sec_texpB_true(0,0) = section.material.E() * section.material.alpha() * section.first_area_moment_z_true; + D_sec_texpB_true(1,0) = section.material.E() * section.material.alpha() * section.first_area_moment_y_true; // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. // Therefore, we use the Approx comparison instead of Equals - CHECK_THAT( test, Catch::Approx(truth) ); + CHECK_THAT( TEST::eigen_matrix_to_std_vector(D_sec_texpB), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_texpB_true)) ); } } @@ -1037,96 +595,20 @@ TEST_CASE("rod_element_property_card_constant_dynamic_1d", "[dynamic],[1D],[isotropic],[constant],[property]") { const uint dim = 1; - - // Define Material Properties as MAST Parameters - MAST::Parameter rho("rho_param", 1420.5); // Density - MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity - MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio - MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity - MAST::Parameter k("k_param", 237.0); // Thermal Conductivity - - const Real G = E() / (2. * (1. + nu())); - - // Define Section Properties as MAST Parameters - MAST::Parameter DIM1("DIM1", 3.234); // Section thickness in z-direction - MAST::Parameter offset_y("offy_param", 0.287); // Section offset in y-direction - MAST::Parameter offset_z("offz_param", -1.654); // Section offset in z-direction - - // Create field functions to dsitribute these constant parameters throughout the model - // Section Property Field Functions - MAST::ConstantFieldFunction DIM1_f("DIM1", DIM1); - MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); - MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); - // Material Property Field Functions - MAST::ConstantFieldFunction rho_f("rho", rho); - MAST::ConstantFieldFunction E_f("E", E); - MAST::ConstantFieldFunction nu_f("nu", nu); - MAST::ConstantFieldFunction cp_f("cp", cp); - MAST::ConstantFieldFunction k_f("k_th", k); - - // Initialize the material - MAST::IsotropicMaterialPropertyCard material; - - // Add the material property constant field functions to the material card - material.add(rho_f); - material.add(k_f); - material.add(cp_f); - material.add(E_f); - material.add(nu_f); - - // Initialize the section - MAST::Solid1DRodSectionElementPropertyCard section; - - // Add the section property constant field functions to the section card - section.add(DIM1_f); - section.add(offsety_f); - section.add(offsetz_f); - - // Add the material card to the section card - section.set_material(material); - - // Specify a section orientation point and add it to the section. - RealVectorX orientation = RealVectorX::Zero(3); - orientation(1) = 1.0; - section.y_vector() = orientation; - - // Now initialize the section - section.init(*p_global_init); + const uint n_target_elems = 3000; + + TEST::AluminumRodSection section(n_target_elems); REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional - REQUIRE( section.depends_on(DIM1) ); - REQUIRE( section.depends_on(offset_y) ); - REQUIRE( section.depends_on(offset_z) ); - REQUIRE( section.depends_on(k) ); - REQUIRE( section.depends_on(cp) ); - REQUIRE( section.depends_on(rho) ); + REQUIRE( section.depends_on(section.DIM1) ); + REQUIRE( section.depends_on(section.offset_y) ); + REQUIRE( section.depends_on(section.offset_z) ); + REQUIRE( section.depends_on(section.material.k) ); + REQUIRE( section.depends_on(section.material.cp) ); + REQUIRE( section.depends_on(section.material.rho) ); REQUIRE( section.if_isotropic() ); - // True values - const Real r = DIM1(); - const Real area_true = PI*r*r; - const Real torsion_constant_true = PI*pow(r, 4.0)/2.0; - const Real first_area_moment_z_true = area_true * offset_y(); - const Real first_area_moment_y_true = area_true * offset_z(); - const Real Izzc_true = PI*pow(r, 4.0)/4.0; - const Real Iyyc_true = PI*pow(r, 4.0)/4.0; - const Real Izyc_true = 0.0; - const Real Ipc_true = PI*pow(r, 4.0)/2.0; - const Real second_area_moment_zz_true = Izzc_true + area_true * pow(offset_y(), 2.); - const Real second_area_moment_yy_true = Iyyc_true + area_true * pow(offset_z(), 2.); - const Real second_area_moment_zy_true = Izyc_true + area_true * offset_y() * offset_z(); - const Real second_area_moment_polar_true = second_area_moment_zz_true + second_area_moment_yy_true; - const Real warping_constant_true = 0.0; - const Real kappa_z_true = 8.4967018479575718e-01; - const Real kappa_y_true = 8.4967018474199052e-01; - const Real xs_true = offset_z(); - const Real ys_true = offset_y(); - const Real xc_true = offset_z(); - const Real yc_true = offset_y(); - const libMesh::Point shear_center_true(xs_true, ys_true, 0.); - const libMesh::Point centroid_true(xc_true, yc_true, 0.); - const libMesh::Point point(4.3, -3.5, -6.7); const Real time = 8.22; @@ -1156,26 +638,26 @@ TEST_CASE("rod_element_property_card_constant_dynamic_1d", Real area; const MAST::FieldFunction& Area = section.A(); Area(point, time, area); - REQUIRE( area == Approx(area_true) ); - D_sec_iner_true(0,0) = D_sec_iner_true(1,1) = D_sec_iner_true(2,2) = area_true; + REQUIRE( area == Approx(section.area_true) ); + D_sec_iner_true(0,0) = D_sec_iner_true(1,1) = D_sec_iner_true(2,2) = section.area_true; Real Ip; const MAST::FieldFunction& PolarInertia = section.Ip(); PolarInertia(point, time, Ip); - CHECK( Ip == Approx(second_area_moment_polar_true) ); - D_sec_iner_true(3,3) = second_area_moment_polar_true; + CHECK( Ip == Approx(section.second_area_moment_polar_true) ); + D_sec_iner_true(3,3) = section.second_area_moment_polar_true; Real first_area_moment_y; const MAST::FieldFunction& Ay = section.Ay(); Ay(point, time, first_area_moment_y); - CHECK( first_area_moment_y == Approx(first_area_moment_y_true) ); - D_sec_iner_true(0,4) = D_sec_iner_true(4,0) = first_area_moment_y_true; + CHECK( first_area_moment_y == Approx(section.first_area_moment_y_true) ); + D_sec_iner_true(0,4) = D_sec_iner_true(4,0) = section.first_area_moment_y_true; Real first_area_moment_z; const MAST::FieldFunction& Az = section.Az(); Az(point, time, first_area_moment_z); - CHECK( first_area_moment_z == Approx(first_area_moment_z_true) ); - D_sec_iner_true(0,5) = D_sec_iner_true(5,0) = first_area_moment_z_true; + CHECK( first_area_moment_z == Approx(section.first_area_moment_z_true) ); + D_sec_iner_true(0,5) = D_sec_iner_true(5,0) = section.first_area_moment_z_true; RealMatrixX I; const MAST::FieldFunction& Inertias = section.I(); @@ -1184,26 +666,21 @@ TEST_CASE("rod_element_property_card_constant_dynamic_1d", Real Iyy = I(1,1); Real Izz = I(0,0); Real Izy = I(0,1); - REQUIRE( Izz == Approx(second_area_moment_zz_true) ); - REQUIRE( Iyy == Approx(second_area_moment_yy_true) ); - REQUIRE( Izy == Approx(second_area_moment_zy_true) ); - - D_sec_iner_true(4,4) = Iyy; // TODO: Should this be Izz? + REQUIRE( Izz == Approx(section.second_area_moment_zz_true) ); + REQUIRE( Iyy == Approx(section.second_area_moment_yy_true) ); + REQUIRE( Izy == Approx(section.second_area_moment_zy_true) ); + + D_sec_iner_true(4,4) = Iyy; // Should this be Izz? D_sec_iner_true(4,5) = Izy; D_sec_iner_true(5,4) = Izy; - D_sec_iner_true(5,5) = Izz; // TODO: Should this be Iyy?? + D_sec_iner_true(5,5) = Izz; // Should this by Iyy? - D_sec_iner_true *= rho(); - - // Convert the test and truth Eigen::Matrix objects to std::vector - // since Catch2 has built in methods to compare vectors - std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_iner); - std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_iner_true); + D_sec_iner_true *= section.material.rho(); // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. // Therefore, we use the Approx comparison instead of Equals - CHECK_THAT( test, Catch::Approx(truth) ); + CHECK_THAT( TEST::eigen_matrix_to_std_vector(D_sec_iner), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_iner_true)) ); } } @@ -1212,96 +689,20 @@ TEST_CASE("rod_element_property_card_constant_structural_1d", "[structural],[1D],[isotropic],[constant],[property]") { const uint dim = 1; - - // Define Material Properties as MAST Parameters - MAST::Parameter rho("rho_param", 1420.5); // Density - MAST::Parameter E("E_param", 72.0e9); // Modulus of Elasticity - MAST::Parameter nu("nu_param", 0.33); // Poisson's ratio - MAST::Parameter cp("cp_param", 908.0); // Specific Heat Capacity - MAST::Parameter k("k_param", 237.0); // Thermal Conductivity - - const Real G = E() / (2. * (1. + nu())); - - // Define Section Properties as MAST Parameters - MAST::Parameter DIM1("DIM1", 3.234); // Section thickness in z-direction - MAST::Parameter offset_y("offy_param", 0.287); // Section offset in y-direction - MAST::Parameter offset_z("offz_param", -1.654); // Section offset in z-direction - - // Create field functions to dsitribute these constant parameters throughout the model - // Section Property Field Functions - MAST::ConstantFieldFunction DIM1_f("DIM1", DIM1); - MAST::ConstantFieldFunction offsety_f("hy_off", offset_y); - MAST::ConstantFieldFunction offsetz_f("hz_off", offset_z); - // Material Property Field Functions - MAST::ConstantFieldFunction rho_f("rho", rho); - MAST::ConstantFieldFunction E_f("E", E); - MAST::ConstantFieldFunction nu_f("nu", nu); - MAST::ConstantFieldFunction cp_f("cp", cp); - MAST::ConstantFieldFunction k_f("k_th", k); - - // Initialize the material - MAST::IsotropicMaterialPropertyCard material; - - // Add the material property constant field functions to the material card - material.add(rho_f); - material.add(k_f); - material.add(cp_f); - material.add(E_f); - material.add(nu_f); - - // Initialize the section - MAST::Solid1DRodSectionElementPropertyCard section; - - // Add the section property constant field functions to the section card - section.add(DIM1_f); - section.add(offsety_f); - section.add(offsetz_f); - - // Add the material card to the section card - section.set_material(material); - - // Specify a section orientation point and add it to the section. - RealVectorX orientation = RealVectorX::Zero(3); - orientation(1) = 1.0; - section.y_vector() = orientation; - - // Now initialize the section - section.init(*p_global_init); + const uint n_target_elems = 3000; + + TEST::AluminumRodSection section(n_target_elems); REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional - REQUIRE( section.depends_on(DIM1) ); - REQUIRE( section.depends_on(offset_y) ); - REQUIRE( section.depends_on(offset_z) ); - REQUIRE( section.depends_on(k) ); - REQUIRE( section.depends_on(cp) ); - REQUIRE( section.depends_on(rho) ); + REQUIRE( section.depends_on(section.DIM1) ); + REQUIRE( section.depends_on(section.offset_y) ); + REQUIRE( section.depends_on(section.offset_z) ); + REQUIRE( section.depends_on(section.material.k) ); + REQUIRE( section.depends_on(section.material.cp) ); + REQUIRE( section.depends_on(section.material.rho) ); REQUIRE( section.if_isotropic() ); - // True values - const Real r = DIM1(); - const Real area_true = PI*r*r; - const Real torsion_constant_true = PI*pow(r, 4.0)/2.0; - const Real first_area_moment_z_true = area_true * offset_y(); - const Real first_area_moment_y_true = area_true * offset_z(); - const Real Izzc_true = PI*pow(r, 4.0)/4.0; - const Real Iyyc_true = PI*pow(r, 4.0)/4.0; - const Real Izyc_true = 0.0; - const Real Ipc_true = PI*pow(r, 4.0)/2.0; - const Real second_area_moment_zz_true = Izzc_true + area_true * pow(offset_y(), 2.); - const Real second_area_moment_yy_true = Iyyc_true + area_true * pow(offset_z(), 2.); - const Real second_area_moment_zy_true = Izyc_true + area_true * offset_y() * offset_z(); - const Real second_area_moment_polar_true = second_area_moment_zz_true + second_area_moment_yy_true; - const Real warping_constant_true = 0.0; - const Real kappa_z_true = 8.4967018479575718e-01; - const Real kappa_y_true = 8.4967018474199052e-01; - const Real xs_true = offset_z(); - const Real ys_true = offset_y(); - const Real xc_true = offset_z(); - const Real yc_true = offset_y(); - const libMesh::Point shear_center_true(xs_true, ys_true, 0.); - const libMesh::Point centroid_true(xc_true, yc_true, 0.); - const libMesh::Point point(4.3, -3.5, -6.7); const Real time = 8.22; @@ -1341,12 +742,12 @@ TEST_CASE("rod_element_property_card_constant_structural_1d", Real area; const MAST::FieldFunction& Area = section.A(); Area(point, time, area); - REQUIRE( area == Approx(area_true) ); + REQUIRE( area == Approx(section.area_true) ); Real torsion_constant; const MAST::FieldFunction& TorsionConstant = section.J(); TorsionConstant(point, time, torsion_constant); - REQUIRE( torsion_constant == Approx(torsion_constant_true).epsilon(0.05) ); + REQUIRE( torsion_constant == Approx(section.torsion_constant_true).epsilon(0.05) ); std::unique_ptr> extension_stiffness_mat = section.stiffness_A_matrix(); @@ -1359,19 +760,13 @@ TEST_CASE("rod_element_property_card_constant_structural_1d", // Hard-coded value of the section's extension stiffness RealMatrixX D_sec_ext_true = RealMatrixX::Zero(2,2); - D_sec_ext_true(0,0) = E() * area_true; - D_sec_ext_true(1,1) = G * torsion_constant_true; - - - // Convert the test and truth Eigen::Matrix objects to std::vector - // since Catch2 has built in methods to compare vectors - std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_ext); - std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_ext_true); + D_sec_ext_true(0,0) = section.material.E() * section.area_true; + D_sec_ext_true(1,1) = section.material.G() * section.torsion_constant_true; // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. // Therefore, we use the Approx comparison instead of Equals - CHECK_THAT( test, Catch::Approx(truth).epsilon(0.05) ); + CHECK_THAT( TEST::eigen_matrix_to_std_vector(D_sec_ext), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_ext_true)).epsilon(0.05) ); } @@ -1394,9 +789,9 @@ TEST_CASE("rod_element_property_card_constant_structural_1d", Real Izz = I(0,0); Real Iyy = I(1,1); Real Izy = I(0,1); - REQUIRE( Izz == Approx(second_area_moment_zz_true) ); - REQUIRE( Iyy == Approx(second_area_moment_yy_true) ); - REQUIRE( Izy == Approx(second_area_moment_zy_true) ); + REQUIRE( Izz == Approx(section.second_area_moment_zz_true) ); + REQUIRE( Iyy == Approx(section.second_area_moment_yy_true) ); + REQUIRE( Izy == Approx(section.second_area_moment_zy_true) ); std::unique_ptr> bending_stiffness_mat = section.stiffness_D_matrix(); @@ -1407,20 +802,15 @@ TEST_CASE("rod_element_property_card_constant_structural_1d", // Hard-coded value of the section's extension stiffness RealMatrixX D_sec_bnd_true = RealMatrixX::Zero(2,2); - D_sec_bnd_true(0,0) = E() * second_area_moment_zz_true; - D_sec_bnd_true(1,1) = E() * second_area_moment_yy_true; - D_sec_bnd_true(0,1) = E() * second_area_moment_zy_true; - D_sec_bnd_true(1,0) = E() * second_area_moment_zy_true; - - // Convert the test and truth Eigen::Matrix objects to std::vector - // since Catch2 has built in methods to compare vectors - std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_bnd); - std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_bnd_true); + D_sec_bnd_true(0,0) = section.material.E() * section.second_area_moment_zz_true; + D_sec_bnd_true(1,1) = section.material.E() * section.second_area_moment_yy_true; + D_sec_bnd_true(0,1) = section.material.E() * section.second_area_moment_zy_true; + D_sec_bnd_true(1,0) = section.material.E() * section.second_area_moment_zy_true; // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. // Therefore, we use the Approx comparison instead of Equals - CHECK_THAT( test, Catch::Approx(truth) ); + CHECK_THAT( TEST::eigen_matrix_to_std_vector(D_sec_bnd), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_bnd_true)) ); } SECTION("1D extension-bending section stiffness matrix") @@ -1438,12 +828,12 @@ TEST_CASE("rod_element_property_card_constant_structural_1d", Real first_area_moment_y; const MAST::FieldFunction& Ay = section.Ay(); Ay(point, time, first_area_moment_y); - CHECK( first_area_moment_y == Approx(first_area_moment_y_true) ); + CHECK( first_area_moment_y == Approx(section.first_area_moment_y_true) ); Real first_area_moment_z; const MAST::FieldFunction& Az = section.Az(); Az(point, time, first_area_moment_z); - CHECK( first_area_moment_z == Approx(first_area_moment_z_true) ); + CHECK( first_area_moment_z == Approx(section.first_area_moment_z_true) ); std::unique_ptr> bndext_stiffness_mat = section.stiffness_B_matrix(); @@ -1454,19 +844,14 @@ TEST_CASE("rod_element_property_card_constant_structural_1d", // Hard-coded value of the section's extension stiffness RealMatrixX D_sec_bndext_true = RealMatrixX::Zero(2,2); - D_sec_bndext_true(0,0) = E() * first_area_moment_z_true; - D_sec_bndext_true(0,1) = E() * first_area_moment_y_true; + D_sec_bndext_true(0,0) = section.material.E() * section.first_area_moment_z_true; + D_sec_bndext_true(0,1) = section.material.E() * section.first_area_moment_y_true; // TODO: Add checks for torsion bending coupling when added to MAST. - // Convert the test and truth Eigen::Matrix objects to std::vector - // since Catch2 has built in methods to compare vectors - std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_bndext); - std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_bndext_true); - // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. // Therefore, we use the Approx comparison instead of Equals - CHECK_THAT( test, Catch::Approx(truth) ); + CHECK_THAT( TEST::eigen_matrix_to_std_vector(D_sec_bndext), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_bndext_true)) ); } SECTION("1D transverse shear section stiffness matrix") @@ -1484,7 +869,7 @@ TEST_CASE("rod_element_property_card_constant_structural_1d", Real area; const MAST::FieldFunction& Area = section.A(); Area(point, time, area); - REQUIRE( area == Approx(area_true) ); + REQUIRE( area == Approx(section.area_true) ); std::unique_ptr> trans_shear_stiffness_mat = section.transverse_shear_stiffness_matrix(); @@ -1495,18 +880,13 @@ TEST_CASE("rod_element_property_card_constant_structural_1d", // Hard-coded value of the section's extension stiffness RealMatrixX D_sec_shr_true = RealMatrixX::Zero(2,2); - D_sec_shr_true(0,0) = G*area_true*kappa_z_true; - D_sec_shr_true(1,1) = G*area_true*kappa_y_true; - - // Convert the test and truth Eigen::Matrix objects to std::vector - // since Catch2 has built in methods to compare vectors - std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_shr); - std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_shr_true); + D_sec_shr_true(0,0) = section.material.G()*section.area_true*section.kappa_z_true; + D_sec_shr_true(1,1) = section.material.G()*section.area_true*section.kappa_y_true; // Floating point approximations are diffcult to compare since the // values typically aren't exactly equal due to numerical error. // Therefore, we use the Approx comparison instead of Equals - CHECK_THAT( test, Catch::Approx(truth) ); + CHECK_THAT( TEST::eigen_matrix_to_std_vector(D_sec_shr), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_shr_true)).epsilon(0.005) ); } @@ -1529,18 +909,15 @@ TEST_CASE("rod_element_property_card_constant_structural_1d", // RealMatrixX D_sec_spring; // spring_stiffness_mat->operator()(point, time, D_sec_spring); // -// Hard-coded value of the section's extension stiffness -// NOTE: Should be all zero's for non-bushing sections +// // Hard-coded value of the section's extension stiffness +// // NOTE: Should be all zero's for non-bushing sections // RealMatrixX D_sec_spring_true = RealMatrixX::Zero(4,6); // -// Convert the test and truth Eigen::Matrix objects to std::vector -// since Catch2 has built in methods to compare vectors -// std::vector test = TEST::eigen_matrix_to_std_vector(D_sec_spring); -// std::vector truth = TEST::eigen_matrix_to_std_vector(D_sec_spring_true); // -// Floating point approximations are diffcult to compare since the -// values typically aren't exactly equal due to numerical error. -// Therefore, we use the Approx comparison instead of Equals -// CHECK_THAT( test, Catch::Approx(truth) ); +// // Floating point approximations are diffcult to compare since the +// // values typically aren't exactly equal due to numerical error. +// // Therefore, we use the Approx comparison instead of Equals +// CHECK_THAT( TEST::eigen_matrix_to_std_vector(D_sec_spring), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_spring_true)) ); // } } + diff --git a/tests/property/mast_solid_1d_rod_section_element_property_card.h b/tests/property/mast_solid_1d_rod_section_element_property_card.h new file mode 100644 index 00000000..9cbba965 --- /dev/null +++ b/tests/property/mast_solid_1d_rod_section_element_property_card.h @@ -0,0 +1,87 @@ +#ifndef MAST_SOLID_1D_ROD_SECTION_ELEMENT_PROPERTY_CARD_H_INCLUDED +#define MAST_SOLID_1D_ROD_SECTION_ELEMENT_PROPERTY_CARD_H_INCLUDED + +#include "property_cards/solid_1d_rod_section_element_property_card.h" +#include "material/mast_isotropic_material.h" + +extern libMesh::LibMeshInit* p_global_init; + +#define PI 3.1415926535897932 + +namespace TEST +{ + class AluminumRodSection : public MAST::Solid1DRodSectionElementPropertyCard + { + public: + + AluminumRodSection(const uint n_target_elems=3500): + DIM1("DIM1", 3.234), + offset_y("offy_param", 0.287), offset_z("offz_param", -1.654), + DIM1_f("DIM1", DIM1), + offsety_f("hy_off", offset_y), offsetz_f("hz_off", offset_z), + centroid_true(xc_true, yc_true), shear_center_true(xs_true, ys_true) + { + add(DIM1_f); + + add(offsety_f); + add(offsetz_f); + + // Add the material card to the section card + set_material(material); + + // Specify a section orientation point and add it to the + RealVectorX orientation = RealVectorX::Zero(3); + orientation(1) = 1.0; + y_vector() = orientation; + + // Now initialize the section + init(*p_global_init, n_target_elems); + } + + TEST::Aluminum7075T6 material; + + MAST::Parameter DIM1; + + MAST::Parameter offset_y; + MAST::Parameter offset_z; + + MAST::ConstantFieldFunction DIM1_f; + + MAST::ConstantFieldFunction offsety_f; + MAST::ConstantFieldFunction offsetz_f; + + // True values calculated using the sectionproperties module in python BAR.py + const Real r = DIM1(); + const Real area_true = PI*r*r; + const Real torsion_constant_true = PI*pow(r, 4.0)/2.0; + const Real first_area_moment_z_true = area_true * offset_y(); + const Real first_area_moment_y_true = area_true * offset_z(); + const Real Izzc_true = PI*pow(r, 4.0)/4.0; + const Real Iyyc_true = PI*pow(r, 4.0)/4.0; + const Real Izyc_true = 0.0; + const Real Ipc_true = PI*pow(r, 4.0)/2.0; + const Real second_area_moment_zz_true = Izzc_true + area_true * pow(offset_y(), 2.); + const Real second_area_moment_yy_true = Iyyc_true + area_true * pow(offset_z(), 2.); + const Real second_area_moment_zy_true = Izyc_true + area_true * offset_y() * offset_z(); + const Real second_area_moment_polar_true = second_area_moment_zz_true + second_area_moment_yy_true; + const Real warping_constant_true = 0.0; + const Real kappa_z_true = 8.4967018479575718e-01; + const Real kappa_y_true = 8.4967018474199052e-01; + const Real xs_true = offset_z(); + const Real ys_true = offset_y(); + const Real xc_true = offset_z(); + const Real yc_true = offset_y(); + const std::vector stress_points_true = { + libMesh::Point(0., r, 0.), + libMesh::Point(r, 0., 0.), + libMesh::Point(0., -r, 0.), + libMesh::Point(-r, 0., 0.) + }; + + + libMesh::Point centroid_true; + libMesh::Point shear_center_true; + + }; +} +#endif // MAST_SOLID_1D_ROD_SECTION_ELEMENT_PROPERTY_CARD_H_INCLUDED From 7762279590b0d1168393e48ac4e5720bcd58ba1a Mon Sep 17 00:00:00 2001 From: David John Neiferd <13425967+JohnDN90@users.noreply.github.com> Date: Wed, 11 Mar 2020 10:47:00 -0400 Subject: [PATCH 21/27] Changed PCFactorSetMatSolverType to PCFactorSetMatSolverPackage. This was done to maintain compatibility with PETSc versions older than 3.9. --- src/property_cards/cross_section_property_pilkey.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/property_cards/cross_section_property_pilkey.cpp b/src/property_cards/cross_section_property_pilkey.cpp index 7867e538..98a69060 100644 --- a/src/property_cards/cross_section_property_pilkey.cpp +++ b/src/property_cards/cross_section_property_pilkey.cpp @@ -64,7 +64,10 @@ class PetscLinearSolverConfiguration : public libMesh::SolverConfiguration /** * Have MUMPS perform the preconditioner factorization. */ - ierr = PCFactorSetMatSolverType(_petsc_linear_solver.pc(), MATSOLVERMUMPS); + // TODO: PCFactorSetMatSolverPackage is deprecated and should be replaced + // by PCFactorSetMatSolverType. Currently, this old version is used to + // maintain comaptibility with older versions of PETSc. + ierr = PCFactorSetMatSolverPackage(_petsc_linear_solver.pc(), MATSOLVERMUMPS); CHKERRABORT(_petsc_linear_solver.comm().get(), ierr); /** @@ -156,7 +159,10 @@ class PetscNonlinearSolverConfiguration : public libMesh::SolverConfiguration ierr = PCSetType(pc, PCLU); CHKERRABORT(_petsc_nonlinear_solver.comm().get(), ierr); - ierr = PCFactorSetMatSolverType(pc, MATSOLVERMUMPS); + // TODO: PCFactorSetMatSolverPackage is deprecated and should be replaced + // by PCFactorSetMatSolverType. Currently, this old version is used to + // maintain comaptibility with older versions of PETSc. + ierr = PCFactorSetMatSolverPackage(pc, MATSOLVERMUMPS); CHKERRABORT(_petsc_nonlinear_solver.comm().get(), ierr); // Now set these values from options in case the user wants to override From 8be048045d1ccfd3c6726b34c14b6f7ce863ca89 Mon Sep 17 00:00:00 2001 From: David John Neiferd <13425967+JohnDN90@users.noreply.github.com> Date: Tue, 31 Mar 2020 14:15:37 -0400 Subject: [PATCH 22/27] Added a missing header which was necessary for libMesh 1.3.1, but not 1.4.1 and newer. --- src/property_cards/cross_section_property_pilkey.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/property_cards/cross_section_property_pilkey.h b/src/property_cards/cross_section_property_pilkey.h index 5132d76e..f34b5b28 100644 --- a/src/property_cards/cross_section_property_pilkey.h +++ b/src/property_cards/cross_section_property_pilkey.h @@ -24,7 +24,7 @@ #include "property_cards/solid_2d_section_element_property_card.h" #include "base/physics_discipline_base.h" - +#include "libmesh/petsc_vector.h" // This is necessary for compatibility with libMesh v1.3.1 namespace MAST { From 51f3fcfb87d5f9cfc25694f2c3df925eb6c29471 Mon Sep 17 00:00:00 2001 From: David John Neiferd <13425967+JohnDN90@users.noreply.github.com> Date: Wed, 12 Aug 2020 10:24:57 -0400 Subject: [PATCH 23/27] Added PointLoad class for simpler definition of point loads. In other words, this moves the defintion of the PointLoad class definition from the examples into the library itself. This was implemented a long time ago but was never merged into master. --- .../point_load_condition.cpp | 27 ++++++++++++++++++ src/boundary_condition/point_load_condition.h | 28 +++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/src/boundary_condition/point_load_condition.cpp b/src/boundary_condition/point_load_condition.cpp index 14395a0f..e93b9359 100644 --- a/src/boundary_condition/point_load_condition.cpp +++ b/src/boundary_condition/point_load_condition.cpp @@ -58,4 +58,31 @@ MAST::PointLoadCondition::get_nodes() { } +MAST::PointLoad::PointLoad(MAST::Parameter& magnitude, RealVectorX direction): +MAST::FieldFunction("load"), _magnitude(magnitude), +_direction(direction) {} + +MAST::PointLoad::~PointLoad() { } + + +void MAST::PointLoad::operator()(const libMesh::Point& p, const Real t, + RealVectorX& v) const +{ + v = _magnitude() * _direction; +} + + +void MAST::PointLoad::derivative(const MAST::FunctionBase& f, + const libMesh::Point& p, const Real t, + RealVectorX& v) const +{ + v = RealVectorX::Zero(6); + if (&f == &_magnitude) + { + for (uint64_t i=0; i<_direction.size(); i++) + { + v(i) = _direction(i); + } + } +} diff --git a/src/boundary_condition/point_load_condition.h b/src/boundary_condition/point_load_condition.h index 888d29be..e75ad85b 100644 --- a/src/boundary_condition/point_load_condition.h +++ b/src/boundary_condition/point_load_condition.h @@ -25,6 +25,8 @@ // MAST includes #include "base/boundary_condition_base.h" +#include "base/field_function_base.h" +#include "base/parameter.h" // libMesh includes #include "libmesh/node.h" @@ -74,6 +76,32 @@ namespace MAST { std::set _nodes; }; + + + /** + * This class is used in the conjuction with the class above. Added by DJN + * to enhance compatability with NASTRAN interface. + */ + class PointLoad: public MAST::FieldFunction + { + public: + PointLoad(MAST::Parameter& magnitude, RealVectorX direction); + + virtual ~PointLoad(); + + virtual void operator()(const libMesh::Point& p, const Real t, + RealVectorX& v) const; + + virtual void derivative(const MAST::FunctionBase& f, + const libMesh::Point& p, const Real t, + RealVectorX& v) const; + + protected: + + MAST::Parameter& _magnitude; + RealVectorX _direction; + + }; } #endif // __mast__point_load_condition__ From 3818b9c3e571629f9776343010b64b6f2b48dfd9 Mon Sep 17 00:00:00 2001 From: David John Neiferd <13425967+JohnDN90@users.noreply.github.com> Date: Tue, 25 Aug 2020 15:56:41 -0400 Subject: [PATCH 24/27] Added method to define zero and non-zero boundary conditons on individual degrees of freedom. This was implemented a long time ago, but is just now being moved to GitHub. --- src/base/boundary_condition_base.h | 3 ++- src/base/physics_discipline_base.cpp | 23 +++++++++++++++++++++++ src/base/physics_discipline_base.h | 26 ++++++++++++++++++++++++++ src/boundary_condition/CMakeLists.txt | 4 +++- 4 files changed, 54 insertions(+), 2 deletions(-) diff --git a/src/base/boundary_condition_base.h b/src/base/boundary_condition_base.h index 3c2cd645..c287ddcb 100644 --- a/src/base/boundary_condition_base.h +++ b/src/base/boundary_condition_base.h @@ -47,7 +47,8 @@ namespace MAST { EXHAUST, ISOTHERMAL, ADIABATIC, - BOUNDARY_VELOCITY + BOUNDARY_VELOCITY, + DOF_DIRICHLET }; diff --git a/src/base/physics_discipline_base.cpp b/src/base/physics_discipline_base.cpp index e76d6893..502fd219 100644 --- a/src/base/physics_discipline_base.cpp +++ b/src/base/physics_discipline_base.cpp @@ -23,6 +23,7 @@ #include "base/parameter.h" #include "base/nonlinear_system.h" #include "boundary_condition/dirichlet_boundary_condition.h" +#include "boundary_condition/dirichlet_dof_boundary_condition.h" #include "mesh/geom_elem.h" // libMesh includes @@ -88,6 +89,13 @@ MAST::PhysicsDisciplineBase::add_dirichlet_bc(libMesh::boundary_id_type bid, } +void +MAST::PhysicsDisciplineBase::add_dirichlet_dof_bc(MAST::DOFDirichletBoundaryCondition& load) +{ + libmesh_assert(!_dirichlet_dof_bcs.count(&load)); + _dirichlet_dof_bcs.insert(&load); +} + void MAST::PhysicsDisciplineBase:: @@ -229,6 +237,21 @@ init_system_dirichlet_bc(MAST::NonlinearSystem& sys) const { } +void +MAST::PhysicsDisciplineBase:: +init_system_dirichlet_dof_bc(MAST::NonlinearSystem& sys) { + + // give the set of all dirichlet dof BCs to the MAST::DOFConstraint object + // (a child class of libMesh::System:Constraint) + _dof_constraint.reset(new MAST::DOFConstraint(_dirichlet_dof_bcs)); + + // tell the MAST::DOFConstraint which system it is acting on + _dof_constraint->setNonlinearSystem(sys); + + // attach the MAST::DOFConstraint object to the system + sys.attach_constraint_object(*_dof_constraint); + +} void diff --git a/src/base/physics_discipline_base.h b/src/base/physics_discipline_base.h index 171c8d93..dbb02227 100644 --- a/src/base/physics_discipline_base.h +++ b/src/base/physics_discipline_base.h @@ -25,6 +25,7 @@ // MAST includes #include "base/mast_data_types.h" +#include "boundary_condition/dirichlet_dof_boundary_condition.h" // libMesh includes #include "libmesh/equation_systems.h" @@ -35,6 +36,7 @@ namespace MAST { // Forward declerations class BoundaryConditionBase; class DirichletBoundaryCondition; + class DOFDirichletBoundaryCondition; class PropertyCardBase; class FunctionBase; class FunctionSetBase; @@ -52,6 +54,7 @@ namespace MAST { typedef std::map PropertyCardMapType; typedef std::map DirichletBCMapType; typedef std::set PointLoadSetType; + typedef std::set DOFDirichletBCSetType; class PhysicsDisciplineBase { public: @@ -106,6 +109,11 @@ namespace MAST { */ void add_dirichlet_bc(libMesh::boundary_id_type bid, MAST::DirichletBoundaryCondition& load); + + /*! + * adds the specified Dirichlet DOF boundary condition + */ + void add_dirichlet_dof_bc(MAST::DOFDirichletBoundaryCondition& load); /*! * @returns a const reference to the side boundary conditions @@ -172,6 +180,12 @@ namespace MAST { return _point_loads; } + /*! + * @returns a reference to the dirichlet dof boundary conditions + */ + MAST::DOFDirichletBCSetType& dirichlet_dof_bc() { + return _dirichlet_dof_bcs; + } /*! @@ -185,6 +199,12 @@ namespace MAST { * initializes the system for dirichlet boundary conditions */ void init_system_dirichlet_bc(MAST::NonlinearSystem& sys) const; + + + /*! + * initializes the system for dirichlet dof boundary conditions + */ + void init_system_dirichlet_dof_bc(MAST::NonlinearSystem& sys); /*! @@ -260,6 +280,12 @@ namespace MAST { * point loads */ MAST::PointLoadSetType _point_loads; + + /*! + * degree of freedom dirichlet boundary conditions + */ + MAST::DOFDirichletBCSetType _dirichlet_dof_bcs; + std::unique_ptr _dof_constraint; }; } diff --git a/src/boundary_condition/CMakeLists.txt b/src/boundary_condition/CMakeLists.txt index 59d74c49..c35864b5 100644 --- a/src/boundary_condition/CMakeLists.txt +++ b/src/boundary_condition/CMakeLists.txt @@ -2,9 +2,11 @@ target_sources(mast PRIVATE ${CMAKE_CURRENT_LIST_DIR}/dirichlet_boundary_condition.cpp ${CMAKE_CURRENT_LIST_DIR}/dirichlet_boundary_condition.h + ${CMAKE_CURRENT_LIST_DIR}/dirichlet_dof_boundary_condition.cpp + ${CMAKE_CURRENT_LIST_DIR}/dirichlet_dof_boundary_condition.h ${CMAKE_CURRENT_LIST_DIR}/point_load_condition.cpp ${CMAKE_CURRENT_LIST_DIR}/point_load_condition.h) # Install MAST headers for this directory. install(DIRECTORY ./ DESTINATION include/boundary_condition - FILES_MATCHING PATTERN "*.h") \ No newline at end of file + FILES_MATCHING PATTERN "*.h") From 856a50e9388f4416c4b9e4e5dad5f992060e10cd Mon Sep 17 00:00:00 2001 From: David John Neiferd <13425967+JohnDN90@users.noreply.github.com> Date: Tue, 25 Aug 2020 16:11:55 -0400 Subject: [PATCH 25/27] Added missing new files from last commit. --- .../dirichlet_dof_boundary_condition.cpp | 90 +++++++++++ .../dirichlet_dof_boundary_condition.h | 140 ++++++++++++++++++ 2 files changed, 230 insertions(+) create mode 100644 src/boundary_condition/dirichlet_dof_boundary_condition.cpp create mode 100644 src/boundary_condition/dirichlet_dof_boundary_condition.h diff --git a/src/boundary_condition/dirichlet_dof_boundary_condition.cpp b/src/boundary_condition/dirichlet_dof_boundary_condition.cpp new file mode 100644 index 00000000..b4e68d0f --- /dev/null +++ b/src/boundary_condition/dirichlet_dof_boundary_condition.cpp @@ -0,0 +1,90 @@ +/* + * MAST: Multidisciplinary-design Adaptation and Sensitivity Toolkit + * Copyright (C) 2013-2019 Manav Bhatia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +// MAST includes +#include "boundary_condition/dirichlet_dof_boundary_condition.h" +#include "base/nonlinear_system.h" + +// libMesh Includes +#include "libmesh/dof_map.h" + + +void MAST::DOFDirichletBoundaryCondition::init(std::vector bc_nodes_in, + std::vector bc_dofs_in, + std::vector bc_vals_in) +{ + _bc_nodes = bc_nodes_in; + _bc_dofs = bc_dofs_in; + _bc_vals = bc_vals_in; +} + + + + +MAST::DOFConstraint::DOFConstraint(std::set dof_bcs): + libMesh::System::Constraint(), _dof_bcs(dof_bcs) {} + +MAST::DOFConstraint::~DOFConstraint() {} + +/*! + * This method is called by libMesh prior to the solve command. It loops through + * all the MAST::DOFDirichletBoundaryCondition objects, and applies the + * boundary condition (defined by nodes, DOFs, and values stores in the + * MAST::DOFDirichletBoundaryCondition object) to the system. + */ +void MAST::DOFConstraint::constrain() +{ + libMesh::DofConstraintRow c_row; + libMesh::DofMap& dof_map = nonlinear_system->get_dof_map(); + std::vector di; + + std::set::iterator it = _dof_bcs.begin(); + + for ( ; it != _dof_bcs.end(); it++) + { + std::vector& bc_nodes = (*it)->bc_nodes(); + std::vector& bc_dofs = (*it)->bc_dofs(); + std::vector& bc_vals = (*it)->bc_vals(); + + for (uint j=0; jid()*6+dof; +// libMesh::out << "(" << node->id() << ",(" << dof << "," << global_dof << ")," << val << ")" << std::endl; + di.clear(); + dof_map.dof_indices(bc_nodes[j], di, bc_dofs[i]); + libmesh_assert_equal_to(di.size(), 1); + dof_map.add_constraint_row(di[0], c_row, bc_vals[i], true); + } + } + } +} + +/*! + * This method is used to set the MAST::NonlinearSystem object that the + * constraints are acting on. + */ +void MAST::DOFConstraint::setNonlinearSystem(MAST::NonlinearSystem& nonlinear_system_in) +{ + nonlinear_system = &nonlinear_system_in; +} diff --git a/src/boundary_condition/dirichlet_dof_boundary_condition.h b/src/boundary_condition/dirichlet_dof_boundary_condition.h new file mode 100644 index 00000000..38272472 --- /dev/null +++ b/src/boundary_condition/dirichlet_dof_boundary_condition.h @@ -0,0 +1,140 @@ +/* + * MAST: Multidisciplinary-design Adaptation and Sensitivity Toolkit + * Copyright (C) 2013-2019 Manav Bhatia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __mast__dirichlet_dof_boundary_condition_h__ +#define __mast__dirichlet_dof_boundary_condition_h__ + +// C++ includes +#include + +// MAST includes +#include "base/boundary_condition_base.h" + + +// libmesh includes +#include "libmesh/system.h" +#include "libmesh/node.h" + +/*! + * CONCISE USAGE EXAMPLE + * --------------------- + * Define a std::vector of the nodes the boundary conditoin applies to + * std::vector bc_nodes{mesh.point_locator().locate_node(libMesh::Point(L0, W0+0.5*W, 0.)), mesh.point_locator().locate_node(libMesh::Point(L0+L, W0+0.5*W, 0.)) }; + * + * Define the local degrees of freedom the boundary condition applies to + * std::vector bc_dofs{0, 1, 2, 3}; + * + * Define the value of the boundary condition at each degree of freedom + * std::vector bc_vals{0., 0., 0.}; + * + * Create the boundary condition object for dirichlet dof BCs + * MAST::DOFDirichletBoundaryCondition dof_bc; + * + * Initialize the boundary condition with the vectors of nodes, dofs, and values + * dof_bc.init(bc_nodes, bc_dofs, bc_vals); + * + * Add the boundary condition to the discipline + * discipline.add_dirichlet_dof_bc(dof_bc); + * + * Repeat for another boundary condition + * std::vector bc_nodes3{mesh.point_locator().locate_node(libMesh::Point(L0, W0, 0.)) }; + * std::vector bc_dofs3{0, 1, 2, 3, 4, 5}; + * std::vector bc_vals3{0., 0., 0., 0., 0., 0.}; + * MAST::DOFDirichletBoundaryCondition dof_bc3; + * dof_bc3.init(bc_nodes3, bc_dofs3, bc_vals3); + * discipline.add_dirichlet_dof_bc(dof_bc3); + * + * Initialize the boundary conditions within the system + * discipline.init_system_dirichlet_dof_bc(system); + */ + + +namespace MAST { + + // Forward declerations + class NonlinearSystem; + + + /*! + * This is a boundary condition class which stores the a vector of the + * pointers to libMesh::Node's that the BC is acting on, a vector of the + * local degrees of freedom (0-5) the BC acts on, and a vector of the + * constrain values (which can be nonzero). + */ + class DOFDirichletBoundaryCondition: public MAST::BoundaryConditionBase + { + public: + DOFDirichletBoundaryCondition(): + MAST::BoundaryConditionBase(MAST::DOF_DIRICHLET) + { } + + virtual ~DOFDirichletBoundaryCondition() { } + + + void init(std::vector bc_nodes_in, + std::vector bc_dofs_in, + std::vector bc_vals_in); + + + std::vector& bc_nodes(){ + return _bc_nodes; + } + + std::vector& bc_dofs(){ + return _bc_dofs; + } + + std::vector& bc_vals(){ + return _bc_vals; + } + + protected: + std::vector _bc_nodes; + std::vector _bc_dofs; + std::vector _bc_vals; + }; + + + + /*! + * This class is used by libMesh to impose the constraints by calling + * the constrain() function before solving. The object created from this + * class is added to the system through the attach_constraint_object + * method. + */ + class DOFConstraint: public libMesh::System::Constraint + { + public: + DOFConstraint(std::set dof_bcs); + + virtual ~DOFConstraint(); + + virtual void constrain(); + + virtual void setNonlinearSystem(MAST::NonlinearSystem& nonlinear_system_in); + + protected: + MAST::NonlinearSystem* nonlinear_system = nullptr; + const std::set _dof_bcs; + }; + + +} + +#endif // __mast__dirichlet_dof_boundary_condition_h__ From c4072047564f7475b3359bc615dbaf84b0be8ece Mon Sep 17 00:00:00 2001 From: David John Neiferd <13425967+JohnDN90@users.noreply.github.com> Date: Thu, 3 Sep 2020 09:47:58 -0400 Subject: [PATCH 26/27] Added clearing of point loads to "clear_loads()" method. --- src/base/physics_discipline_base.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/base/physics_discipline_base.cpp b/src/base/physics_discipline_base.cpp index e76d6893..73137938 100644 --- a/src/base/physics_discipline_base.cpp +++ b/src/base/physics_discipline_base.cpp @@ -38,6 +38,7 @@ void MAST::PhysicsDisciplineBase::clear_loads() { _side_bc_map.clear(); _vol_bc_map.clear(); + _point_loads.clear(); } From e0eb779bb665b1d4f3eda4e884ff40ef90b4a17a Mon Sep 17 00:00:00 2001 From: David John Neiferd <13425967+JohnDN90@users.noreply.github.com> Date: Tue, 8 Sep 2020 21:44:44 -0400 Subject: [PATCH 27/27] Modified "adjoint_solve" method to allow user to explicitly set adjoint RHS. Backwards compatibility of the adjoint_solve method is maintained. --- src/base/nonlinear_system.cpp | 16 ++++++++++------ src/base/nonlinear_system.h | 4 +++- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/base/nonlinear_system.cpp b/src/base/nonlinear_system.cpp index 97bb83f8..6e765cc9 100644 --- a/src/base/nonlinear_system.cpp +++ b/src/base/nonlinear_system.cpp @@ -801,7 +801,9 @@ MAST::NonlinearSystem::adjoint_solve(const libMesh::NumericVector& X, MAST::AssemblyElemOperations& elem_ops, MAST::OutputAssemblyElemOperations& output, MAST::AssemblyBase& assembly, - bool if_assemble_jacobian) { + bool if_assemble_jacobian, + bool compute_adjoint_rhs, + unsigned int i) { libmesh_assert(_operation == MAST::NonlinearSystem::NONE); @@ -812,19 +814,21 @@ MAST::NonlinearSystem::adjoint_solve(const libMesh::NumericVector& X, LOG_SCOPE("adjoint_solve()", "NonlinearSystem"); libMesh::NumericVector - &dsol = this->add_adjoint_solution(), - &rhs = this->add_adjoint_rhs(); + &dsol = this->add_adjoint_solution(i), + &rhs = this->add_adjoint_rhs(i); assembly.set_elem_operation_object(elem_ops); if (if_assemble_jacobian) assembly.residual_and_jacobian(*solution, nullptr, matrix, *this); - assembly.calculate_output_derivative(X, if_localize_sol, output, rhs); + if (compute_adjoint_rhs) + { + assembly.calculate_output_derivative(X, if_localize_sol, output, rhs); + rhs.scale(-1.); + } assembly.clear_elem_operation_object(); - - rhs.scale(-1.); // Our iteration counts and residuals will be sums of the individual // results diff --git a/src/base/nonlinear_system.h b/src/base/nonlinear_system.h index baea7a49..041a1408 100644 --- a/src/base/nonlinear_system.h +++ b/src/base/nonlinear_system.h @@ -157,7 +157,9 @@ namespace MAST { MAST::AssemblyElemOperations& elem_ops, MAST::OutputAssemblyElemOperations& output, MAST::AssemblyBase& assembly, - bool if_assemble_jacobian = true); + bool if_assemble_jacobian = true, + bool compute_adjoint_rhs = true, + unsigned int i = 0); /**