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..dd7b2058 --- /dev/null +++ b/examples/structural/example_9/example_9.cpp @@ -0,0 +1,194 @@ +// 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); + + // 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 + // 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 + + // 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 nu_f("nu", nu); + + // Initialize the material + MAST::IsotropicMaterialPropertyCard material; + + // Add the material property constant field functions to the material card + 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, n_target_elements); + + 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; + + // 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; + + return 0; +} 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/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/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/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); /** diff --git a/src/base/physics_discipline_base.cpp b/src/base/physics_discipline_base.cpp index e76d6893..8401f3ef 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 @@ -38,6 +39,7 @@ void MAST::PhysicsDisciplineBase::clear_loads() { _side_bc_map.clear(); _vol_bc_map.clear(); + _point_loads.clear(); } @@ -88,6 +90,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 +238,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/base/warping_assembly.cpp b/src/base/warping_assembly.cpp new file mode 100644 index 00000000..aa4610f4 --- /dev/null +++ b/src/base/warping_assembly.cpp @@ -0,0 +1,852 @@ +/* + * 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(); + + /** + * 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(); + + const libMesh::MeshBase::const_element_iterator end_el = nonlin_sys.get_mesh().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"); + + 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().elements_end(); + + 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; + 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]); + 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 + for (unsigned int qp=0; qpdot(*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()) +// { +// 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"); + + 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); + + 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 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; isystem().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); + } + + // 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(); + + //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:: +linearized_jacobian_solution_product (const libMesh::NumericVector& X, + const libMesh::NumericVector& dX, + libMesh::NumericVector& JdX, + libMesh::NonlinearImplicitSystem& S) +{ + libmesh_error_msg("Not implemented.; " << __PRETTY_FUNCTION__ << " in " << __FILE__ << " at line " << __LINE__); +} + + +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("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("Not implemented.; " << __PRETTY_FUNCTION__ << " in " << __FILE__ << " at line " << __LINE__); + + 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; +} + + +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 new file mode 100644 index 00000000..cac5738a --- /dev/null +++ b/src/base/warping_assembly.h @@ -0,0 +1,240 @@ +/* + * 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; + + 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 + */ + 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/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") 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__ 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__ diff --git a/src/elasticity/CMakeLists.txt b/src/elasticity/CMakeLists.txt index 9e49637f..8d904221 100644 --- a/src/elasticity/CMakeLists.txt +++ b/src/elasticity/CMakeLists.txt @@ -64,7 +64,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_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); diff --git a/src/elasticity/structural_element_2d.cpp b/src/elasticity/structural_element_2d.cpp index 14e05437..d29b0c3b 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. + */ + // 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); + + /** + * 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); + + // 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 + * 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); + + // 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 + // 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; +}; + + +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; + } +} + + +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(); + //_equation_systems->print_info(); + + _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); + + /** + * 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 + _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..f34b5b28 --- /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" + +#include "libmesh/petsc_vector.h" // This is necessary for compatibility with libMesh v1.3.1 + +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/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; diff --git a/src/property_cards/element_property_card_base.h b/src/property_cards/element_property_card_base.h index 1cb6c1f1..b7c2c3a2 100644 --- a/src/property_cards/element_property_card_base.h +++ b/src/property_cards/element_property_card_base.h @@ -124,7 +124,146 @@ 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__); + } + + + /*! + * 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("Must be implemented in derived class; " << __PRETTY_FUNCTION__ << " in " << __FILE__ << " at line number " << __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("Must be implemented in derived class; " << __PRETTY_FUNCTION__ << " in " << __FILE__ << " at line number " << __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("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("Must be implemented in derived class; " << __PRETTY_FUNCTION__ << " in " << __FILE__ << " at line number " << __LINE__); } 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_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_I1_section_element_property_card.cpp b/src/property_cards/solid_1d_I1_section_element_property_card.cpp new file mode 100644 index 00000000..18ffc598 --- /dev/null +++ b/src/property_cards/solid_1d_I1_section_element_property_card.cpp @@ -0,0 +1,601 @@ +/* + * 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, + 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"); + + // 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, n_target_elems, *this, element_type)); + +// _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..7f75b28d --- /dev/null +++ b/src/property_cards/solid_1d_I1_section_element_property_card.h @@ -0,0 +1,153 @@ +/* + * 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, + 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(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_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/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/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..6f1ace01 --- /dev/null +++ b/src/property_cards/solid_1d_bar_section_element_property_card.cpp @@ -0,0 +1,322 @@ +/* + * 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, + const uint n_target_elems, + const libMesh::ElemType element_type) +{ + 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, n_target_elems, *this, element_type)); + + _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..e641e8eb --- /dev/null +++ b/src/property_cards/solid_1d_bar_section_element_property_card.h @@ -0,0 +1,121 @@ +/* + * 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, + 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 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/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..5f2f37d5 --- /dev/null +++ b/src/property_cards/solid_1d_rod_section_element_property_card.cpp @@ -0,0 +1,347 @@ +/* + * 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, + const uint n_target_elems, + const libMesh::ElemType element_type) { + + 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, n_target_elems, *this, element_type)); + + _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..20100630 --- /dev/null +++ b/src/property_cards/solid_1d_rod_section_element_property_card.h @@ -0,0 +1,141 @@ +/* + * 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, + 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(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 3d8a3285..e9ea94fc 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; + } }; @@ -2086,3 +2131,226 @@ section() const { return _A.get(); } + + +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 70b46eaa..9f1e3960 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 */ @@ -255,6 +265,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; 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..a96db0db --- /dev/null +++ b/src/property_cards/solid_1d_tube2_section_element_property_card.cpp @@ -0,0 +1,392 @@ +/* + * 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, + const uint n_target_elems, + const libMesh::ElemType element_type) +{ + 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, n_target_elems, *this, element_type)); + + _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..08edbd9f --- /dev/null +++ b/src/property_cards/solid_1d_tube2_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_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, + 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(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/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..80ab326d --- /dev/null +++ b/src/property_cards/solid_1d_tube_section_element_property_card.cpp @@ -0,0 +1,411 @@ +/* + * 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, const uint n_target_elems, + const libMesh::ElemType element_type) +{ + 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, n_target_elems, *this, element_type)); + +// _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..fda7f790 --- /dev/null +++ b/src/property_cards/solid_1d_tube_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_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, + 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(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/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 88e0046c..9e819184 100644 --- a/tests/property/CMakeLists.txt +++ b/tests/property/CMakeLists.txt @@ -1,6 +1,13 @@ 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 + ${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 ${CMAKE_CURRENT_LIST_DIR}/mast_solid_2d_section_element_property_card.cpp ${CMAKE_CURRENT_LIST_DIR}/mast_3d_isotropic_element_property_card.cpp) @@ -284,230 +291,547 @@ 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) +## ============================================================================ -# ## ============================================================================ -# # 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) +## ============================================================================ -# ## ============================================================================ -# # 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_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 + PROPERTIES + 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 + PROPERTIES + 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 + PROPERTIES + 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) +## ============================================================================ -# ## ============================================================================ -# # 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 $ -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 $ -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 $ -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 $ -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 $ -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) + +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 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") -# ## ============================================================================ +## ============================================================================ +# 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) +## ============================================================================ # ## ============================================================================ -# # 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_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") +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_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 + PROPERTIES + 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_I1_section_element_property_card.cpp b/tests/property/mast_solid_1d_I1_section_element_property_card.cpp new file mode 100644 index 00000000..457cb5e2 --- /dev/null +++ b/tests/property/mast_solid_1d_I1_section_element_property_card.cpp @@ -0,0 +1,923 @@ +// Catch2 includes +#include "catch.hpp" + +// Custom includes +#include "test_helpers.h" +#include "mast_solid_1d_I1_section_element_property_card.h" + + +TEST_CASE("I1_element_property_card_constant_base_1d", + "[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + const uint n_target_elems = 3000; + + TEST::AluminumI1Section section(n_target_elems); + + REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional + 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() ); + + 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(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 = {§ion.DIM1}; + uint n_s = sens_params.size(); + + REQUIRE( section.if_isotropic() ); + + 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; + const uint n_target_elems = 3000; + + TEST::AluminumI1Section section(n_target_elems); + + REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional + 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() ); + + 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(section.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) = 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::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") + { + /** + * 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) = 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::eigen_matrix_to_std_vector(D_sec_capac), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_capac_true)) ); + } +} + + +TEST_CASE("I1_element_property_card_constant_thermoelastic_1d", + "[thermoelastic],[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + const uint n_target_elems = 3000; + + TEST::AluminumI1Section section(n_target_elems); + + REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional + 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() ); + + 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(section.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) = 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::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") + { + /** + * 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(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) ); + + 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) = 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::eigen_matrix_to_std_vector(D_sec_texpB), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_texpB_true)) ); + } +} + + +TEST_CASE("I1_element_property_card_constant_dynamic_1d", + "[dynamic],[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + const uint n_target_elems = 3000; + + TEST::AluminumI1Section section(n_target_elems); + + REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional + 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() ); + + 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(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(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(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(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(); + 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(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 *= 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::eigen_matrix_to_std_vector(D_sec_iner), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_iner_true)) ); + } +} + + +TEST_CASE("I1_element_property_card_constant_structural_1d", + "[structural],[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + const uint n_target_elems = 3000; + + TEST::AluminumI1Section section(n_target_elems); + + REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional + 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() ); + + 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(section.area_true) ); + + Real torsion_constant; + const MAST::FieldFunction& TorsionConstant = section.J(); + TorsionConstant(point, time, torsion_constant); + REQUIRE( torsion_constant == Approx(section.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) = 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::eigen_matrix_to_std_vector(D_sec_ext), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_ext_true)).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(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(); + + 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) = 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::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") + { + /** + * 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(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) ); + + 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) = 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. + + // 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_bndext), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_bndext_true)) ); + } + + 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(section.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) = 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::eigen_matrix_to_std_vector(D_sec_shr), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_shr_true)).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); +// +// +// // 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_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 new file mode 100644 index 00000000..88f6066f --- /dev/null +++ b/tests/property/mast_solid_1d_L_section_element_property_card.cpp @@ -0,0 +1,994 @@ +// 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" +#include "material/mast_isotropic_material.h" +#include "mast_solid_1d_L_section_element_property_card.h" + +extern libMesh::LibMeshInit* p_global_init; + + +TEST_CASE("L_element_property_card_constant_base_1d", + "[1D][isotropic][constant][property]") +{ + const uint dim = 1; + const uint n_target_elems = 3500; // 14657 + + TEST::AluminumLSection section(n_target_elems); + + REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional + 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.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() ); + + 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(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)) ); + + 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(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 = {§ion.DIM1}; + uint n_s = sens_params.size(); + + REQUIRE( section.if_isotropic() ); + + 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; + const uint n_target_elems = 3500; + + TEST::AluminumLSection section(n_target_elems); + + REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional + 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() ); + + 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(section.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) = 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 + 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. + // 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) = 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 + 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. + // 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; + const uint n_target_elems = 3500; + + TEST::AluminumLSection section(n_target_elems); + + REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional + 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() ); + + 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(section.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) = 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 + 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 + // 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(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) ); + + 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) = 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 + // 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); + + // 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_dynamic_1d", + "[dynamic],[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + const uint n_target_elems = 3500; + + TEST::AluminumLSection section(n_target_elems); + + REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional + 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() ); + + 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(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(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(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(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(); + 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(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 *= section.material.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); + + // 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; + const uint n_target_elems = 3500; + + TEST::AluminumLSection section(n_target_elems); + + REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional + 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() ); + + 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(section.area_true) ); + + Real torsion_constant; + const MAST::FieldFunction& TorsionConstant = section.J(); + TorsionConstant(point, time, torsion_constant); + REQUIRE( torsion_constant == Approx(section.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) = 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 + // 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); + + // 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(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(); + + 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) = 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 + 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. + // 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(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) ); + + 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) = 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) ); + } + + 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(section.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) = 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 + 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. + // 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 = 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) ); +// } +} 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_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& 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 = {§ion.DIM1}; + uint n_s = sens_params.size(); + + REQUIRE( section.if_isotropic() ); + + 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("bar_element_property_card_constant_heat_transfer_1d", + "[heat_transfer],[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + const uint n_target_elems = 3000; + + TEST::AluminumBarSection section(n_target_elems); + + REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional + 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() ); + + 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(section.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) = 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::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") + { + /** + * 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) = 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::eigen_matrix_to_std_vector(D_sec_capac), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_capac_true)) ); + } +} + + +TEST_CASE("bar_element_property_card_constant_thermoelastic_1d", + "[thermoelastic],[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + const uint n_target_elems = 3000; + + TEST::AluminumBarSection section(n_target_elems); + + REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional + 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() ); + + 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(section.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) = 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::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") + { + /** + * 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(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) ); + + 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) = 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::eigen_matrix_to_std_vector(D_sec_texpB), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_texpB_true)) ); + } +} + + +TEST_CASE("bar_element_property_card_constant_dynamic_1d", + "[dynamic],[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + const uint n_target_elems = 3000; + + TEST::AluminumBarSection section(n_target_elems); + + REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional + 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() ); + + 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(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(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(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(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(); + 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(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 *= 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::eigen_matrix_to_std_vector(D_sec_iner), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_iner_true)) ); + } +} + + +TEST_CASE("bar_element_property_card_constant_structural_1d", + "[structural],[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + const uint n_target_elems = 3000; + + TEST::AluminumBarSection section(n_target_elems); + + REQUIRE( section.dim() == dim); // Ensure section is 1 dimensional + 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() ); + + 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(section.area_true) ); + + Real torsion_constant; + const MAST::FieldFunction& TorsionConstant = section.J(); + TorsionConstant(point, time, torsion_constant); + REQUIRE( torsion_constant == Approx(section.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) = 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::eigen_matrix_to_std_vector(D_sec_ext), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_ext_true)).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(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(); + + 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) = 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::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") + { + /** + * 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(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) ); + + 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) = 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. + + // 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_bndext), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_bndext_true)) ); + } + + 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(section.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) = 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::eigen_matrix_to_std_vector(D_sec_shr), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_shr_true)).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); +// +// +// // 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_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 new file mode 100644 index 00000000..eaad500f --- /dev/null +++ b/tests/property/mast_solid_1d_rod_section_element_property_card.cpp @@ -0,0 +1,923 @@ +// Catch2 includes +#include "catch.hpp" + +// Custom includes +#include "test_helpers.h" +#include "mast_solid_1d_rod_section_element_property_card.h" + + +TEST_CASE("rod_element_property_card_constant_base_1d", + "[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + 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(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.depends_on(section.material.E) ); + REQUIRE( section.depends_on(section.material.nu) ); + REQUIRE( section.depends_on(section.material.alpha) ); + + REQUIRE( section.if_isotropic() ); + + 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(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 = {§ion.DIM1}; + uint n_s = sens_params.size(); + + REQUIRE( section.if_isotropic() ); + + 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("rod_element_property_card_constant_heat_transfer_1d", + "[heat_transfer],[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + 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(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() ); + + 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(section.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) = 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::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") + { + /** + * 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) = 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::eigen_matrix_to_std_vector(D_sec_capac), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_capac_true)) ); + } +} + + +TEST_CASE("rod_element_property_card_constant_thermoelastic_1d", + "[thermoelastic],[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + 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(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() ); + + 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(section.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) = 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::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") + { + /** + * 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(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) ); + + 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) = 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::eigen_matrix_to_std_vector(D_sec_texpB), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_texpB_true)) ); + } +} + + +TEST_CASE("rod_element_property_card_constant_dynamic_1d", + "[dynamic],[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + 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(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() ); + + 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(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(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(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(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(); + 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(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 *= 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::eigen_matrix_to_std_vector(D_sec_iner), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_iner_true)) ); + } +} + + +TEST_CASE("rod_element_property_card_constant_structural_1d", + "[structural],[1D],[isotropic],[constant],[property]") +{ + const uint dim = 1; + 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(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() ); + + 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(section.area_true) ); + + Real torsion_constant; + const MAST::FieldFunction& TorsionConstant = section.J(); + TorsionConstant(point, time, torsion_constant); + REQUIRE( torsion_constant == Approx(section.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) = 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::eigen_matrix_to_std_vector(D_sec_ext), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_ext_true)).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(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(); + + 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) = 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::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") + { + /** + * 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(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) ); + + 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) = 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. + + // 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_bndext), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_bndext_true)) ); + } + + 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(section.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) = 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::eigen_matrix_to_std_vector(D_sec_shr), Catch::Approx(TEST::eigen_matrix_to_std_vector(D_sec_shr_true)).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); +// +// +// // 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 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 } 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..2caf0dc6 --- /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 = 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. + // 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 = 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. + // 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 = 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 + // 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 = 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. + // 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 = 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. + // 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 = 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. + // 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 = 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. + // 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 = 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) ); + } + + 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 = 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. + // 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 = 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) ); +// } +} 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..d2711b42 --- /dev/null +++ b/tests/property/mast_solid_1d_tube_section_element_property_card.cpp @@ -0,0 +1,1508 @@ +// 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_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]") +{ + 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 = 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. + // 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 = 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. + // 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 = 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 + // 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 = 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. + // 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 = 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. + // 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 = 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. + // 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 = 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. + // 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 = 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) ); + } + + 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 = 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. + // 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 = 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) ); +// } +} diff --git a/tests/test_helpers.cpp b/tests/test_helpers.cpp index 44f1575d..085b4d0a 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 TEST::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 TEST::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